网络数据包内核探险记(二) —— linux内核网络分层结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37806112/article/details/82762512

网络设备接口层:

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");

  截图:

  

  

 应用:

   

猜你喜欢

转载自blog.csdn.net/m0_37806112/article/details/82762512