请教个napi_struct 、net_device数据结构中与链表相关的几个问题

发布于 2022-10-15 10:11:13 字数 3196 浏览 26 评论 0

本帖最后由 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;
};

  1. struct net_device
  2. {
  3.                struct list_head        dev_list;
  4.         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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一袭白衣梦中忆 2022-10-22 10:11:13

使用的内核版本为2.6.32.12

黎夕旧梦 2022-10-22 10:11:13

内核要改写NAPI这块接口,引入了napi_struct结构,就是为多队列做支持的,每个队列,而非原来的每个网卡,对应一个napi结构,例如igb中有:

        for (i = 0; i < adapter->num_rx_queues; i++) {
                struct igb_ring *ring = &(adapter->rx_ring);
                ring->count = adapter->rx_ring_count;
                ring->adapter = adapter;
                ring->queue_index = i;
                ring->itr_register = E1000_ITR;

                /* set a default napi handler for each rx_ring */
                netif_napi_add(adapter->netdev, &ring->napi, igb_poll, 64);
        }

为每个rx queue注册napi……

只怪假的太真实 2022-10-22 10:11:13

回复 3# 独孤九贱

    非常感谢~

    另外请教一个问题哈:
                不知大侠是如何来跟踪linux中协议栈的变动的?感觉随着内核版本的递增,其协议栈变动太大。我现在对着2.6.32的内核代码来看《深入理解LINUX网络技术内幕》,看的有
                点云里雾里

枯寂 2022-10-22 10:11:13

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是没有问题的。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文