This commit is contained in:
gatieme
2016-09-04 22:15:05 +08:00
parent 1bfec98d12
commit b202e61457
2 changed files with 38 additions and 5 deletions
+7 -4
View File
@@ -348,7 +348,7 @@ struct net_device {
ip_ptrip6_ptratalk_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`中. 在确保所选择的名称尚未使用, 而且没有指定自相矛盾的设备特性(所支持特性的列表, 请参见`<netdevice.h>`中的 NETIF_F_* )后, 用`netdev_register_kobject`将新设备添加到通用内核对象模型中. 该函数还会创建上文提到的sysfs项. 最后,该设备集成到特定命名空间的链表中, 以及以设备名和接口索引为散列键的两个散列表中.
`dev_new_index`生成在所属命名空间中唯一标识该设备的接口索引。该索引保存在`net_device->ifindex`中. 在确保所选择的名称尚未使用, 而且没有指定自相矛盾的设备特性(所支持特性的列表, 请参见`<netdevice.h>`中的`NETIF_F_*`后, 用`netdev_register_kobject`将新设备添加到通用内核对象模型中. 该函数还会创建上文提到的sysfs项. 最后,该设备集成到特定命名空间的链表中, 以及以设备名和接口索引为散列键的两个散列表中.
+31 -1
View File
@@ -182,4 +182,34 @@ NAPI的另一个优点是可以高效地丢弃分组. 如果内核确信因为
内核以循环方式处理链表上的所有设备 : 内核依次轮询各个设备, 如果已经花费了一定的时间来处理某个设备, 则选择下一个设备进行处理. 此外, 某个设备都带有一个相对权重, 表示与轮询表中其他设备相比, 该设备的相对重要性. 较快的设备权重较大,较慢的设备权重较小. 由于权重指定了在一个轮询的循环中处理多少分组, 这确保了内核将更多地注意速度较快的设备.
现在我们已经弄清楚了NAPI的基本原理, 接下来将讨论其实现细节. 与旧的API相比, 关键性的变化在于, 支持NAPI的设备必须提供一个 poll函数. 该方法是特定于设备的, 在用`netif_napi_add`注册网卡时指定. 调用该函数注册, 表明设备可以且必须用新方法处理.
现在我们已经弄清楚了NAPI的基本原理, 接下来将讨论其实现细节. 与旧的API相比, 关键性的变化在于, 支持NAPI的设备必须提供一个 poll函数. 该方法是特定于设备的, 在用`netif_napi_add`注册网卡时指定. 调用该函数注册, 表明设备可以且必须用新方法处理.
```CPP
<netdevice.h>
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 实例的指针。该结构用于
管理轮询表上的设备。其定义如下:
<netdevice.h>
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 机制获得相关信息