網絡設備之分配net_device結構


在注冊網絡設備時,會調用pci_driver->probe函數,以e100網卡驅動為例,其最終會調用alloc_netdev_mqs來分配內存,並且在分配內存后調用setup函數(以太網為ether_setup)初始化二層地址等信息。下面以e100為例,分析alloc_netdev_mqs函數和ether_setup函數的執行流程;

相關函數的調用關系,如下;

1 /**
2  * e100分配net_device,並對以太網信息進行初始化的函數調用關系
3  *
4  * e100_probe-->alloc_etherdev-->alloc_netdev_mqs
5  *                                     |-->ether_setup                                                                                             
6  */

 

分配函數最終會調用alloc_netdev_mqs來對net_device進行分配,並做相關成員的初始化;

  1 /**
  2  * alloc_netdev_mqs - allocate network device
  3  * @sizeof_priv: size of private data to allocate space for
  4  * @name: device name format string
  5  * @name_assign_type: origin of device name
  6  * @setup: callback to initialize device
  7  * @txqs: the number of TX subqueues to allocate
  8  * @rxqs: the number of RX subqueues to allocate
  9  *
 10  * Allocates a struct net_device with private data area for driver use
 11  * and performs basic initialization.  Also allocates subqueue structs
 12  * for each queue on the device.
 13  */
 14 struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 15         unsigned char name_assign_type,
 16         void (*setup)(struct net_device *),
 17         unsigned int txqs, unsigned int rxqs)
 18 {
 19     struct net_device *dev;
 20     size_t alloc_size;
 21     struct net_device *p;
 22 
 23     BUG_ON(strlen(name) >= sizeof(dev->name));
 24 
 25     /* 檢查發送隊列數 */
 26     if (txqs < 1) {
 27         pr_err("alloc_netdev: Unable to allocate device with zero queues\n");
 28         return NULL;
 29     }
 30 
 31     /* 檢查接收隊列數 */
 32 #ifdef CONFIG_SYSFS
 33     if (rxqs < 1) {
 34         pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n");
 35         return NULL;
 36     }
 37 #endif
 38 
 39     /* 計算net_device結構大小 */
 40     alloc_size = sizeof(struct net_device);
 41     /* 加上私有數據大小 */
 42     if (sizeof_priv) {
 43         /* ensure 32-byte alignment of private area */
 44         alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
 45         alloc_size += sizeof_priv;
 46     }
 47     /* ensure 32-byte alignment of whole construct */
 48     /* 整個空間做對齊后的大小 */
 49     alloc_size += NETDEV_ALIGN - 1;
 50 
 51     /* 分配內存 */
 52     p = kvzalloc(alloc_size, GFP_KERNEL | __GFP_REPEAT);
 53     if (!p)
 54         return NULL;
 55 
 56     /* 內存對齊 */
 57     dev = PTR_ALIGN(p, NETDEV_ALIGN);
 58 
 59     /* 計算對齊的填充 */
 60     dev->padded = (char *)dev - (char *)p;
 61 
 62     /* 分配設備引用 */
 63     dev->pcpu_refcnt = alloc_percpu(int);
 64     if (!dev->pcpu_refcnt)
 65         goto free_dev;
 66 
 67     /* 地址列表初始化 */
 68     if (dev_addr_init(dev))
 69         goto free_pcpu;
 70 
 71     /* 組播列表初始化 */
 72     dev_mc_init(dev);
 73 
 74     /* 單播列表初始化 */
 75     dev_uc_init(dev);
 76 
 77     /* 設置net */
 78     dev_net_set(dev, &init_net);
 79 
 80     /* GSO設置 */
 81     dev->gso_max_size = GSO_MAX_SIZE;
 82     dev->gso_max_segs = GSO_MAX_SEGS;
 83 
 84     /* 初始化各種鏈表 */
 85     INIT_LIST_HEAD(&dev->napi_list);
 86     INIT_LIST_HEAD(&dev->unreg_list);
 87     INIT_LIST_HEAD(&dev->close_list);
 88     INIT_LIST_HEAD(&dev->link_watch_list);
 89     INIT_LIST_HEAD(&dev->adj_list.upper);
 90     INIT_LIST_HEAD(&dev->adj_list.lower);
 91     INIT_LIST_HEAD(&dev->ptype_all);
 92     INIT_LIST_HEAD(&dev->ptype_specific);
 93 #ifdef CONFIG_NET_SCHED
 94     hash_init(dev->qdisc_hash);
 95 #endif
 96     dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM;
 97 
 98     /* 初始化設備硬件地址,mtu等參數 */
 99     <span style="color: #ff0000;">setup(dev);</span>
100 
101     /* 隊列長度為0,則采用默認值 */
102     if (!dev->tx_queue_len) {
103         dev->priv_flags |= IFF_NO_QUEUE;
104         dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN;
105     }
106 
107     /* 設置發送隊列數 */
108     dev->num_tx_queues = txqs;
109     dev->real_num_tx_queues = txqs;
110 
111     /* 分配初始化發送隊列 */
112     if (netif_alloc_netdev_queues(dev))
113         goto free_all;
114 
115 #ifdef CONFIG_SYSFS
116     /* 設置接收隊列數 */
117     dev->num_rx_queues = rxqs;
118     dev->real_num_rx_queues = rxqs;
119 
120     /* 分配初始化接收隊列 */
121     if (netif_alloc_rx_queues(dev))
122         goto free_all;
123 #endif
124 
125     /* 拷貝名字 */
126     strcpy(dev->name, name);
127 
128     /* 賦值名字賦值類型 */
129     dev->name_assign_type = name_assign_type;
130 
131     /* 設置設備組 */
132     dev->group = INIT_NETDEV_GROUP;
133 
134     /* 設置默認ethtool操作 */
135     if (!dev->ethtool_ops)
136         dev->ethtool_ops = &default_ethtool_ops;
137 
138     /* 初始化netfilter入口 */
139     nf_hook_ingress_init(dev);
140 
141     return dev;
142 
143 free_all:
144     free_netdev(dev);
145     return NULL;
146 
147 free_pcpu:
148     free_percpu(dev->pcpu_refcnt);
149 free_dev:
150     netdev_freemem(dev);
151     return NULL;
152 }

 

如果二層設備遵循以太網規范,則上面setup函數實際會調用ether_setup,函數中對相關字段以太網標准進行了初始化,比類型,頭部長度和操作,MTU,隊列長度,標記等;前面文章中分析net_device結構時,其中的頭部操作header_ops就是在這里進行賦值的,以太網對應的就是的eth_header_ops操作了;

 1 /**
 2  * ether_setup - setup Ethernet network device
 3  * @dev: network device
 4  *
 5  * Fill in the fields of the device structure with Ethernet-generic values.
 6  */
 7 void ether_setup(struct net_device *dev)
 8 {
 9     dev->header_ops        = &eth_header_ops;
10     dev->type        = ARPHRD_ETHER;
11     dev->hard_header_len     = ETH_HLEN;
12     dev->min_header_len    = ETH_HLEN;
13     dev->mtu        = ETH_DATA_LEN;
14     dev->min_mtu        = ETH_MIN_MTU;
15     dev->max_mtu        = ETH_DATA_LEN;
16     dev->addr_len        = ETH_ALEN;
17     dev->tx_queue_len    = DEFAULT_TX_QUEUE_LEN;
18     dev->flags        = IFF_BROADCAST|IFF_MULTICAST;
19     dev->priv_flags        |= IFF_TX_SKB_SHARING;
20 
21     eth_broadcast_addr(dev->broadcast);
22 
23 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM