在注册网络设备时,会调用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 "); 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 "); 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 = ð_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 }