歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux管理 >> Linux網絡 >> 網絡驅動移植之解析Linux網絡驅動的基本框架

網絡驅動移植之解析Linux網絡驅動的基本框架

日期:2017/3/1 10:46:21   编辑:Linux網絡
內核源碼:linux-2.6.38.8.tar.bz2

概括而言,編寫Linux網絡驅動其實只要完成兩件事即可,一是分配並初始化網絡設備,二是注冊網絡設備。

1、分配並初始化網絡設備

動態分配網絡設備(從C語言角度來看,其實就是定義了一個struct net_device結構體變量,並對這個結構體變量的某些成員進行了初始化而已)及其私有數據的大致過程如下圖(以以太網設備為例):

下面將結合linux-2.6.38.8中的代碼詳細分析網絡設備的分配和初始化過程。

  1. /* linux-2.6.38.8/include/linux/etherdevice.h */
  2. #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
  3. #define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)
  4. /* linux-2.6.38.8/net/ethernet/eth.c */
  5. struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
  6. unsigned int rxqs)
  7. {
  8. return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs);
  9. }
  10. void ether_setup(struct net_device *dev)
  11. {
  12. dev->header_ops = ð_header_ops;
  13. dev->type = ARPHRD_ETHER;
  14. dev->hard_header_len = ETH_HLEN;
  15. dev->mtu = ETH_DATA_LEN;
  16. dev->addr_len = ETH_ALEN;
  17. dev->tx_queue_len = 1000; /* Ethernet wants good queues */
  18. dev->flags = IFF_BROADCAST|IFF_MULTICAST;
  19. memset(dev->broadcast, 0xFF, ETH_ALEN);
  20. }

以前各類網絡設備的分配函數(如以太網設備的alloc_etherdev)都只是alloc_netdev函數的封裝而已,但對於linux-2.6.38.8而言已經不是這樣了。

  1. /* linux-2.6.38.8/include/linux/netdevice.h */
  2. #define alloc_netdev(sizeof_priv, name, setup) \
  3. alloc_netdev_mqs(sizeof_priv, name, setup, 1, 1)

alloc_netdev_mqs函數的五個參數分別為私有數據大小、設備名稱、默認初始化函數、發送隊列數目和接收隊列數目。

以太網設備的名稱設為eth%d,默認初始化函數設為ether_setup,發送和接收隊列數目都設為1。

函數alloc_netdev_mqs定義在linux-2.6.38.8/net/core/dev.c文件中,大概會完成以下各種操作:

(1)、為struct net_device和私有數據分配內存空間

  1. alloc_size = sizeof(struct net_device);
  2. if (sizeof_priv) {
  3. alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); //#define NETDEV_ALIGN 32
  4. alloc_size += sizeof_priv;
  5. }
  6. alloc_size += NETDEV_ALIGN - 1;
  7. p = kzalloc(alloc_size, GFP_KERNEL);
  8. if (!p) {
  9. printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
  10. return NULL;
  11. }
  12. dev = PTR_ALIGN(p, NETDEV_ALIGN);
  13. dev->padded = (char *)dev - (char *)p;

對齊操作相關宏:

  1. /* linux-2.6.38.8/include/linux/kernel.h */
  2. #define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
  3. #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
  4. #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
  5. #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))

(2)、動態分配per-CPU變量

  1. dev->pcpu_refcnt = alloc_percpu(int);
  2. if (!dev->pcpu_refcnt)
  3. goto free_p;

(3)、初始化硬件地址鏈表dev->dev_addrs,並把首元素賦給dev->dev_addr

  1. if (dev_addr_init(dev))
  2. goto free_pcpu;

(4)、初始化組播和單播地址鏈表

  1. dev_mc_init(dev);
  2. dev_uc_init(dev);

(5)、設置網絡命名空間

  1. dev_net_set(dev, &init_net);

(6)、設置GSO最大值

  1. dev->gso_max_size = GSO_MAX_SIZE;

(7)、初始化各種鏈表

  1. INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
  2. dev->ethtool_ntuple_list.count = 0;
  3. INIT_LIST_HEAD(&dev->napi_list);
  4. INIT_LIST_HEAD(&dev->unreg_list);
  5. INIT_LIST_HEAD(&dev->link_watch_list);

(8)、設置priv_flags值

  1. dev->priv_flags = IFF_XMIT_DST_RELEASE;

(9)、執行默認初始化函數(以太網設備默認為ether_setup)

  1. setup(dev);

(10)、初始化數據包發送隊列

  1. dev->num_tx_queues = txqs;
  2. dev->real_num_tx_queues = txqs;
  3. if (netif_alloc_netdev_queues(dev))
  4. goto free_all;

(11)、初始化數據包接收隊列

  1. dev->num_rx_queues = rxqs;
  2. dev->real_num_rx_queues = rxqs;
  3. if (netif_alloc_rx_queues(dev))
  4. goto free_all;

(12)、設置網絡設備名稱

  1. strcpy(dev->name, name);
Copyright © Linux教程網 All Rights Reserved