网络设备接口层:
struct net_device
|
struct net_device_ops *netdev_ops;
|
netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev);
char name[IFNAMSIZ];设备的名字
//硬件信息
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
int irq;
unsigned short type; 接口类型 例如:以太网
unsigned int mtu; 最大传输单元
unsigned short hard_header_len; 硬件地址长度 MAC头 如果是以太网为14
struct netdev_hw_addr_list dev_addrs; 硬件地址 MAC地址
unsigned int flags; 网络接口状态 IFF_AUTOMEDIA
netdev_ops 网卡操作函数集合
const struct ethtool_ops *ethtool_ops; 与应用空间的ethtool-----ifconfig
const struct header_ops *header_ops;
unsigned long trans_start; 记录最后一个数据包开始发送的时间戳
struct device dev; 硬件信息
流程:
设置net_device
分配net_device:alloc_netdev(sizeof_priv, name, name_assign_type, setup)
注册net_device:int register_netdev(struct net_device *dev);
注销net_device:unregister_netdev
demo:模仿virtio_net.c,虚拟网卡编写
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/average.h>
#include <net/busy_poll.h>
#include <linux/types.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/virtio_types.h>
#include <linux/if_ether.h>
#define LKM_NAME "vnet0"
/*OOP编程三把斧
1.设计并分配
2.设置
3.注册
*/
/*构造对象的结构体,进行OOP方式的编程*/
struct lkm_vnet_dev{
unsigned char *lkm_vnet_name;
spinlock_t lock;
unsigned long cnt;
struct mutex mutex;
struct net_device *vnet_dev; //创建一个net_device结构体
};
/*建立全局结构体对象*/
static struct lkm_vnet_dev * plkm_vnet_dev;
static netdev_tx_t vir_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
//获取私有设备结构体
struct lkm_vnet_dev *vnet=netdev_priv(dev);
vnet->cnt++;
printk("vnet send packet cnt =%ld\n",vnet->cnt);
return 0;
}
static const struct net_device_ops vnet_netdev={
.ndo_start_xmit = vir_net_start_xmit, //指定当前模块
};
static int lkm_vnet_setup_dev(struct lkm_vnet_dev * dev,int index)
{
dev->lkm_vnet_name=kzalloc(sizeof(LKM_NAME), GFP_KERNEL);
spin_lock_init(&dev->lock);
mutex_init(&dev->mutex);
dev->cnt=0;
return 1;
}
static __init int lkm_vnet_init(void)
{
int iRet;
printk("SQ:module loaded\n");
struct net_device *vnet_dev=NULL;
/*alloc a net_device obj*/
vnet_dev=alloc_netdev(sizeof(struct lkm_vnet_dev), "vnet%d", NET_NAME_UNKNOWN, ether_setup);
if (!vnet_dev)
{
iRet=-ENOMEM;
printk(KERN_ERR"lkm_memory:can't malloc memory\n");
goto error_alloc_netdev;
}
vnet_dev->netdev_ops=&vnet_netdev;
/*register net_device obj*/
register_netdev(vnet_dev);
/*alloc lkm obj*/
//为当前LKM对象分配内存 内存类型
//除了申请内核内存外,还会对申请到的内存内容清零。
plkm_vnet_dev=kzalloc(sizeof(struct lkm_vnet_dev), GFP_KERNEL);
if(!plkm_vnet_dev)
{
iRet=-ENOMEM;
printk(KERN_ERR"lkm_memory:can't malloc memory\n");
goto error_alloc;
}
//调用当前的LKM结构体综合设置函数
iRet=lkm_vnet_setup_dev(plkm_vnet_dev,0);
if(!iRet)
{
iRet=-EINVAL;
printk(KERN_ERR"lkm_memory:lkm_vnet_setup_dev_error\n");
goto error_set_dev;
}
plkm_vnet_dev->vnet_dev=vnet_dev;
return 0;
error_set_dev:
error_alloc:
error_alloc_netdev:
return iRet;
}
static __exit void lkm_vnet_exit(void)
{
printk("LKM-Vnet:module removed\n");
unregister_netdev(plkm_vnet_dev->vnet_dev);
free_netdev(plkm_vnet_dev->vnet_dev);
kfree(plkm_vnet_dev->lkm_vnet_name);
kfree(plkm_vnet_dev);
}
module_init(lkm_vnet_init);
module_exit(lkm_vnet_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Chandler");
MODULE_DESCRIPTION("LKM_VirNet");
MODULE_VERSION("1.0");
截图:
应用: