Linux虛擬網卡實現__Linux

來源:互聯網
上載者:User
本文檔的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。
 










    
   

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.