diff --git a/study/kernel/04-net/04-/README.md b/study/kernel/04-net/04-/README.md index 19e6cb3..c991541 100644 --- a/study/kernel/04-net/04-/README.md +++ b/study/kernel/04-net/04-/README.md @@ -348,7 +348,7 @@ struct net_device { -ip_ptr 、 ip6_ptr 、 atalk_ptr 等指针指向特定于协议的数据,通用代码不会操作这些数据, 他们定义在[include/linux/netdevice.h?v=4.7, line 1721](http://lxr.free-electrons.com/source/include/linux/netdevice.h?v=4.7#L1721) +`ip_ptr`、 `ip6_ptr`、 `atalk_ptr`等指针指向特定于协议的数据,通用代码不会操作这些数据, 他们定义在[`include/linux/netdevice.h?v=4.7, line 1721`](http://lxr.free-electrons.com/source/include/linux/netdevice.h?v=4.7#L1721) ```cpp struct net_device @@ -456,13 +456,15 @@ struct header_ops { 其中最重要的是`header_ops->create`和`header_ops->parse`, 前者创建一个新的硬件首部, 后者分析一个给定的硬件首部 -* header_ops->create 的默认实现是`eth_header`该函数为现存的分组数据生成网络访问层首部. +* `header_ops->create`的默认实现是`eth_header`该函数为现存的分组数据生成网络访问层首部. + +* `header_ops->parse`, 通常由eth_header_parse实现)获取给定的分组的源硬件地址. -* header_ops->parse(通常由eth_header_parse实现)获取给定的分组的源硬件地址. ##2.3 注册网络设备 ------- + 每个网络设备都按照如下过程注册. 1. `alloc_netdev`分配一个新的`struct net_device`实例,一个特定于协议的函数用典型值填充该结构. 对于以太网设备,该函数是`ether_setup`. 其他的协议(这里不详细介绍)会使用形如`XXX_setup`的函数, 其中 XXX可以是`fddi(fiber distributed data interface`, 光纤分布式数据接口)、tr @@ -484,6 +486,7 @@ struct header_ops { 如果`net_device->init`提供了特定于设备的初始化函数,那么内核在进一步处理之前, 将先调用该函数. -由`dev_new_index`生成在所属命名空间中唯一标识该设备的接口索引。该索引保存在 net_device->ifindex`中. 在确保所选择的名称尚未使用, 而且没有指定自相矛盾的设备特性(所支持特性的列表, 请参见``中的 NETIF_F_* )后, 用`netdev_register_kobject`将新设备添加到通用内核对象模型中. 该函数还会创建上文提到的sysfs项. 最后,该设备集成到特定命名空间的链表中, 以及以设备名和接口索引为散列键的两个散列表中. +由`dev_new_index`生成在所属命名空间中唯一标识该设备的接口索引。该索引保存在`net_device->ifindex`中. 在确保所选择的名称尚未使用, 而且没有指定自相矛盾的设备特性(所支持特性的列表, 请参见``中的`NETIF_F_*`后, 用`netdev_register_kobject`将新设备添加到通用内核对象模型中. 该函数还会创建上文提到的sysfs项. 最后,该设备集成到特定命名空间的链表中, 以及以设备名和接口索引为散列键的两个散列表中. + diff --git a/study/kernel/04-net/05/README.md b/study/kernel/04-net/05/README.md index 5332934..ea08c89 100644 --- a/study/kernel/04-net/05/README.md +++ b/study/kernel/04-net/05/README.md @@ -182,4 +182,34 @@ NAPI的另一个优点是可以高效地丢弃分组. 如果内核确信因为 内核以循环方式处理链表上的所有设备 : 内核依次轮询各个设备, 如果已经花费了一定的时间来处理某个设备, 则选择下一个设备进行处理. 此外, 某个设备都带有一个相对权重, 表示与轮询表中其他设备相比, 该设备的相对重要性. 较快的设备权重较大,较慢的设备权重较小. 由于权重指定了在一个轮询的循环中处理多少分组, 这确保了内核将更多地注意速度较快的设备. -现在我们已经弄清楚了NAPI的基本原理, 接下来将讨论其实现细节. 与旧的API相比, 关键性的变化在于, 支持NAPI的设备必须提供一个 poll函数. 该方法是特定于设备的, 在用`netif_napi_add`注册网卡时指定. 调用该函数注册, 表明设备可以且必须用新方法处理. \ No newline at end of file +现在我们已经弄清楚了NAPI的基本原理, 接下来将讨论其实现细节. 与旧的API相比, 关键性的变化在于, 支持NAPI的设备必须提供一个 poll函数. 该方法是特定于设备的, 在用`netif_napi_add`注册网卡时指定. 调用该函数注册, 表明设备可以且必须用新方法处理. + +```CPP + +static inline void netif_napi_add(struct net_device *dev, +struct napi_struct *napi, +int (*poll)(struct napi_struct *, int), +int weight); +``` + +| 参数 | 描述 | +|:----:|:----:| +| dev | 指向所述设备的`net_device`实例 | +| poll | 指定了在IRQ禁用时用来轮询设备的函数 | +| weight | 指定了设备接口的相对权重。实际上可以对 weight 指定任意整数值。通常10/100 Mbit网卡的驱动程序 +指定为16,而1 000/10 000 Mbit网卡的驱动程序指定为64。无论如何,权重都不能超过该设备可以在 +Rx缓冲区中存储的分组的数目。 +netif_napi_add 还需要另一个参数,是一个指向 struct napi_struct 实例的指针。该结构用于 +管理轮询表上的设备。其定义如下: + +struct napi_struct { +struct list_head poll_list; +}; +unsigned long state; +int weight; +int (*poll)(struct napi_struct *, int); +轮询表通过一个标准的内核双链表实现, poll_list 用作链表元素。 weight 和 poll 的语义同上文 +所述。 state 可以是 NAPI_STATE_SCHED 或 NAPI_STATE_DISABLE ,前者表示设备将在内核的下一次循 +环时被轮询,后者表示轮询已经结束且没有更多的分组等待处理,但设备尚未从轮询表移除。 +请注意, struct napi_struct 经常嵌入到一个更大的结构中,后者包含了与网卡有关的、特定 +于驱动程序的数据。这样在内核使用 poll 函数轮询网卡时,可用 container_of 机制获得相关信息 \ No newline at end of file