• 网络设备之分配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
    ");
     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        = &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 }
  • 相关阅读:
    maven的安装教程
    webstorm的中文教程和技巧分享
    WebStorm
    grunt配置任务
    grunt快速入门
    CSS简介
    浅介HTML DOM
    【转】计算机是如何启动的?
    【转】深入理解C++中public、protected及private用法
    【转】VS2013动态库文件的创建及其使用详解
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7526165.html
Copyright © 2020-2023  润新知