Linux虚拟网卡实现

来源:互联网 发布:91porm最新域名 编辑:程序博客网 时间:2024/06/06 08:31
本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性。
参考资料:《Linux设备驱动程序 第三版》,snull源码,linux-2.6.10

    曾经一段时间在看openswan源码,有一个问题迷惑我很久,就是它的那个ipsec虚拟网卡接口是怎么实现的?当时没有思路、没有想法,因为不知道从何着手去解决这个问题,最近接触到了内核模块的编写,又接触到openswan的klips模块,原来这一切全属于网络驱动程序编写范畴。现在我迫不及待的想去了解下它的实现,然后就有了这篇学习笔记……
    本文只是初步讲解虚拟网卡实现的过程,最终实现一个虚拟网卡,对于具体体细节和数据包的发送和传送等等问题没有涉及。对于klips的ipsec0的实现大体上类似这个过程。
    本文档注重实际实现过程,缺少理论知识。
    本文档以《Linux设备驱动程序 第三版》为理论知识;以snull源码为学习对象。为贪图省力,所帖源码来至snull源码和linux-2.6.10内核源码。

一、最终的效果,实现了一个名为sn0的虚拟网卡接口
  [root@xxx snull]# cat /proc/net/dev
  Inter-|   Receive                       
   face |bytes    packets errs drop fifo
      lo:    6528      76    0    0    0  
    eth0:148681882  216304    0    0    0
    eth1:       0       0    0    0    0  
    eth2:       0       0    0    0    0  
    sit0:       0       0    0    0    0  
     sn0:       0       0    0    0    0  
     sn1:     210       3    0    0    0

  [root@xxx snull]# ifconfig sn0  up
  [root@xxx snull]# ifconfig sn0
  sn0       Link encap:Ethernet  HWaddr 00:53:4E:55:4C:30  
            inet6 addr: fe80::253:4eff:fe55:4c30/64 Scope:Link
            UP BROADCAST RUNNING NOARP MULTICAST  MTU:1500  Metric:1
            RX packets:0 errors:0 dropped:0 overruns:0 frame:0
            TX packets:1 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:1000
            RX bytes:0 (0.0 b)  TX bytes:70 (70.0 b)

二、总体过程
    首先需要内核分配一个net_device结构(以下简称dev结构),并初始化dev结构。
      struct net_device *snull_devs[2]; //snull 实现的是两个虚拟网卡,用一个两个大小的结构体数组保存net_device结构,我只关注一个。
      snull_devs[0] = alloc_netdev(sizeof(struct snull_priv), "sn%d",
            snull_init);//内核分配一个dev,此dev由snull_init初始化。然后由alloc_netdev函数返回此dev指针。
 
      for (i = 0; i < 2;  i++)
        if ((result = register_netdev(snull_devs[i])))//dev结构初始化后调用register_netdev向内核注册,注册后就可以对设备(虚拟网卡)操作了。
            printk("snull: error %i registering device \"%s\"\n",
                    result, snull_devs[i]->name);
        else
            ret = 0;


三、初始化过程
    为了便于理解初始化过程,帖上一段alloc_netdev的内核实现:
      struct net_device *alloc_netdev(int sizeof_priv, const char *mask,
                           void (*setup)(struct net_device *))//最后一个参数为函数指针,即指向传进来的snull_init
    {
        void *p;
        struct net_device *dev;
        int alloc_size;
    
        /* ensure 32-byte alignment of both the device and private area */
    
        alloc_size = (sizeof(struct net_device) + NETDEV_ALIGN_CONST)
                & ~NETDEV_ALIGN_CONST;
        alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
    
        p = kmalloc (alloc_size, GFP_KERNEL);
        if (!p) {
            printk(KERN_ERR "alloc_dev: Unable to allocate device.\n");
            return NULL;
        }
    
        memset(p, 0, alloc_size);
    
        dev = (struct net_device *)(((long)p + NETDEV_ALIGN_CONST)
                    & ~NETDEV_ALIGN_CONST);//为dev结构分配内存空间
        dev->padded = (char *)dev - (char *)p;
    
        if (sizeof_priv)
            dev->priv = netdev_priv(dev);
    
        setup(dev);//实现调用了snull_init(dev)对dev结构初始化。
        strcpy(dev->name, mask);
    
        return dev;//返回已初始化的dev
    }

    下面看下这个重要的初始化函数snull_init(),dev的一些重要函数指针均在此赋值
    void snull_init(struct net_device *dev)
    {
        struct snull_priv *priv;
        /*
         * Then, assign other fields in dev, using ether_setup() and some
         * hand assignments
         */
        ether_setup(dev); /* assign some of the fields *///这个函数初始化了dev的许多成员
    
        dev->open            = snull_open; //打开设备
        dev->stop            = snull_release;
        dev->set_config      = snull_config;
        dev->hard_start_xmit = snull_tx;  //数据发送函数
        dev->do_ioctl        = snull_ioctl;
        dev->get_stats       = snull_stats;
        dev->change_mtu      = snull_change_mtu;
        dev->rebuild_header  = snull_rebuild_header;
        dev->hard_header     = snull_header;//建立硬件头,包含源和目的mac地址
        dev->tx_timeout      = snull_tx_timeout;//数发送超时处理。
        dev->watchdog_timeo = timeout;
        if (use_napi) {
            dev->poll        = snull_poll;
            dev->weight      = 2;
        }
        /* keep the default flags, just add NOARP */
        dev->flags           |= IFF_NOARP;
        dev->features        |= NETIF_F_NO_CSUM;
        dev->hard_header_cache = NULL;      /* Disable caching */
    
        /*
         * Then, initialize the priv field. This encloses the statistics
         * and a few private fields.
         */
        priv = netdev_priv(dev);
        memset(priv, 0, sizeof(struct snull_priv));
        spin_lock_init(&priv->lock);
        snull_rx_ints(dev, 1);      /* enable receive interrupts */
        snull_setup_pool(dev);
    }

    以上内容已经把框架搭出来了,至于net结构成员的理解和细节、数据包的发送的接收、超时传输中断处理及sk_buff数据结构等
    信息可参考给出的参考资料。
    类似的实现网络驱动程序的源码还有内核源码中的loopback.c、plip.c、e100.c。
 










    
   

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 3d下载模型没颜色怎么办 车辆被扣30分怎么办 驾驶证被扣15分怎么办 驾驶本被扣分了怎么办 违章扣分扣错了怎么办 出国自驾游怎么办手续 新加坡开车工作遇到坏人怎么办 身份证户口本都丢了怎么办 户口本和身份证都丢了怎么办 网上预约挂完号没收到短信怎么办 驾驶证过了换证期限怎么办 身体弱末梢神经循环不好怎么办 自来水钙镁离子超标怎么办 呼吸感觉有煤烟味是怎么办 酒精弄到衣服上怎么办 孕妇吃了糟卤怎么办 气泡机打不了气怎么办 膝盖好冷好凉怎么办吃什么好 卸妆水进眼睛了怎么办 外出没带卸妆水怎么办? 种睫毛卸睫膏弄眼睛里面了 怎么办 化了妆没卸妆水怎么办 痘痘变成了黑痣怎么办 痘痘形成的痣怎么办 图片文件重命名改不了怎么办 想给宝宝改名字怎么办 洗照片像素过低怎么办 用ps改尺寸照片变形怎么办 平安银行卡三次密码错误怎么办 平安银行卡密码忘了怎么办 平安银行行用卡多次还款怎么办 平安银行大润发卡还不上怎么办 八载图片被投诉怎么办 ps用替换颜色后怎么办 三星s8百度闪退怎么办 吃了过敏的东西怎么办 过敏了痒的厉害怎么办 脸吃麻辣过敏了怎么办 脸过敏发红痒怎么办急救 脸过敏怎么办快速治疗方法 下巴起噶的过敏怎么办