请教个napi_struct 、net_device数据结构中与链表相关的几个问题
本帖最后由 lofeng410 于 2011-04-19 08:09 编辑
struct napi_struct
struct list_head poll_list; unsigned long state;
int weight;
int (*poll)(struct napi_struct *, int);
#ifdef CONFIG_NETPOLL
spinlock_t poll_lock;
int poll_owner;
#endif
unsigned int gro_count;
struct net_device *dev;
struct list_head dev_list; struct sk_buff *gro_list;
struct sk_buff *skb;
};
- struct net_device
- {
- struct list_head dev_list;
- struct list_head napi_list;
复制代码在这两个结构体中,那四个标红的struct list_head类型的变量之间是什么关系呢?
1.
在netif_napi_add()中,有这样的操作:
list_add(&napi->dev_list, &dev->napi_list);
这样是不是说每个网口可能有多个struct napi_struct类型的变量?
2.
感觉着四个struct list_head类型的变量中,就poll_list有多用(在net_rx_action中轮询该链表),其他的都没有用,具体是这样子的么?
3.void __napi_schedule(struct napi_struct *n)
{
unsigned long flags;
local_irq_save(flags);
list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list);
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
local_irq_restore(flags);
}
static void net_rx_action(struct softirq_action *h)
{
struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
从这两个地方看,处理时总是使用&__get_cpu_var(softnet_data).poll_list,好像每个CPU的poll处理队列是属于同一个网口,那这样就意味着一个CPU固定用于处理某个网口。但是我们有没有强制约定说每个网口的中断致能送到固定的CPU上,这样该如何来理解呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用的内核版本为2.6.32.12
内核要改写NAPI这块接口,引入了napi_struct结构,就是为多队列做支持的,每个队列,而非原来的每个网卡,对应一个napi结构,例如igb中有:
为每个rx queue注册napi……
回复 3# 独孤九贱
非常感谢~
另外请教一个问题哈:
不知大侠是如何来跟踪linux中协议栈的变动的?感觉随着内核版本的递增,其协议栈变动太大。我现在对着2.6.32的内核代码来看《深入理解LINUX网络技术内幕》,看的有
点云里雾里
1. 这样是不是说每个网口可能有多个struct napi_struct类型的变量?
是的,在NAPI机制里面,网卡驱动自己配置和管理napi_struct实例,如果驱动愿意,完全可以建立多个napi_struct实例,add到net_device的napi_list中,就是 list_add(&napi->dev_list, &dev->napi_list);做的。
2.
感觉着四个struct list_head类型的变量中,就poll_list有多用(在net_rx_action中轮询该链表),其他的都没有用,具体是这样子的么?
不是的,四个都有用。net_device.napi_list应该是这块网卡下面挂的napi_struct链表的表头
net_device.dev_list应该是把这块网卡实例链接到其他链表里面的节点。
napi_struct.dev_list是把napi_struct实例挂接到net_device.napi_list链表里面的节点。
napi_struct.poll_list是用来把自己挂接到softnet_data.poll_list里面的节点。
softnet_data.poll_list是每个CPU处理的napi_struct链表表头。
3 从这两个地方看,处理时总是使用&__get_cpu_var(softnet_data).poll_list,好像每个CPU的poll处理队列是属于同一个网口,那这样就意味着一个CPU固定用于处理某个网口。但是我们有没有强制约定说每个网口的中断致能送到固定的CPU上,这样该如何来理解呢?
这里理解有点偏差,NAPI的基本过程是这样,当网卡接收到数据,网卡中断被触发,某一个CPU会处理这个中断,假设这个CPU为CPUA。 CPUA处理中断处理程序,生成一个napi_struct实例,关闭网卡中断,调用napi_schedule()把napi_struct实例链接到CPUA的softnet_data.poll_list上,并触发软中断,然后退出中断处理程序。这时,网络软中断子系统开始运行,以轮询的方式接收网卡的大量数据包(net_rx_action)。
这里软中断仍然是CPUA来处理的,因为 软中断可以用两种方式触发,第一个是中断退出时,这个时候肯定是与中断处理程序同一个CPU。另一种是 ksoftirq内核线程,每个CPU都有自己的软中断,所以CPUA在中断处理程序中产生的nap_struct仍然由本CPU来处理。所以软中断中使用 __get_cpu_var(softnet_data).poll_list是没有问题的。