虽然和网络相关,但是它却不是网络协议栈的一部分,这就是netpoll。
它只是一个出入口的处理框架。所谓的网络,它的终端节点就是主机,数据从主机的网卡发出,经过一个出口处理过程,网卡接收到一个数据包,经过一个入口处理过程,这一出一入的过程处理分为两种方式:

1.中断的方式

出口处理过程-数据排入发送队列,读取特定寄存器值,待网卡状态适合发送式,发送,等待发送后的中断通知,继续。
入口处理过程-数据被网卡收到,网卡中断CPU,CPU进而处理数据接收的过程。
网络协议栈下接的就是这种中断的出入口处理方式。

2.poll的方式

出口处理过程-数据排入发送队列,读取特定寄存器值,待网卡状态适合发送式,发送,不等待发送后的中断通知,继续读取寄存器以及根据队列情况权衡是否适合发送。
入口处理过程-数据被网卡收到,等待poll逻辑在适当的时候去主动poll网卡,若有数据,则将其从特定的网卡缓存读出。
Linux netpoll就是利用的这种方式。这种方式完全不依赖中断。
事实总是比说起来更麻烦。
要讲清楚这个有点混乱的主题,不得不引入第三种出入口处理方式,那就是中断和poll结合的方式,这就是NAPI方式。我把三种方式的图示先给出:
a.中断方式


Linux内核的netpoll框架与netconsole_第1张图片


b.poll方式


Linux内核的netpoll框架与netconsole_第2张图片


c.NAPI方式


Linux内核的netpoll框架与netconsole_第3张图片


理 解了这个,剩下的就都理解了。至于为何会有NAPI,在本文中只能简单说一句:在高速高带宽网络中,数据包持续到来,每一个包中断一次CPU的话,CPU 有点吃不消,反而耽误了CPU处理这些数据包,如果之前的数据包还没有处理完,最好的办法就是将数据包排入一个队列,然后沉默,不要打扰CPU,等CPU 空下来的时候,自己去poll这些队列里面的数据包,这就是NAPI。
       纯中断的方式我们都很熟悉,也是最直接的方式。然而为何要有纯poll的方式呢?使用纯poll的场合在中断完全不起作用的情况下。举一个例子,系统 panic之后。此时中断控制器将可能被disable掉,无论如何,此时的机器已经和外界失联了,然而如果此时必须需要一个方式对外界通告自己的死因的 话,这种netpoll的方式就派上用场了,因为它是纯手工的,完全不依赖系统的中断机制。另外一种场合比panic好一些,那就是协议栈故障,如果使用 中断或者NAPI的方式,由于它上接的就是协议栈,netif_receive_skb中又没有什么HOOK点,此时使用netpoll可以改变数据包的 处理路径,通过一个agent可以实现远程debug。
       不要把中断想象的太神秘。它无非也就是一个通知机制,告诉CPU,现在请查询我的状态,该干啥就干啥。事实上,当CPU收到网卡中断的时候,它也不知道该 干啥,它只会调用中断处理函数,其内部会去读取一写寄存器的状态,然后才能知道现在该干什么,比如可以发送数据包,比如收到一个数据包等。既然如此,即使 在关中断的情形下,如果不依靠中断,CPU择机主动调用一下网卡的中断处理函数,读取一写寄存器的状态,是不是也能知道该干什么呢?答案当然是肯定的了! 这就是netpoll的逻辑,它使用两步完成任务:
1.主动调用网卡的中断处理函数,获取当前该发送数据包还是接收到一个数据包;
2.直接hard_xmit数据包或者使用NAPI的接口去poll网卡的数据。
Linux netpoll的总体图示如下:


Linux内核的netpoll框架与netconsole_第4张图片


这 个图示中附带了netconsole的原理,没想到他是如此的简单。我记得我曾经写过一个模块,将panic后的信息发到远端,这个是受到了一个 xtables-addons模块的启发,起初失败了,但是最后我仔细debug了内核代码后,成功了。在成功的过程中,发现了很多以前不知道的东西。但 是现在看看netconsole吧,它什么复杂的东西都不需要,只需要两步:
1.注册一个console,此后内核buffer的信息就会发到这个console;
2.该console下接netpoll的netpoll_send_skb,此后由netpoll逻辑来处理。
即便在panic后,中断已经被关了,甚至中断控制器都关闭的情况下,只要网卡没有进水,数据依然可以收发,它完全不依赖中断和协议栈。这简直太棒了!关于netconsole,我写多少都不如内核的Document来的好:$kernel/Documentation/networking/netconsole.txt.
       netpoll是Linux内核中的一种在协议栈不可用或者中断机制异常的情况下与外界通讯的手段,当然它也是一种绕开协议栈的方法。这个位置足够底层, 写出来的东西也肯定比基于Netfilter的更好玩。Netfilter是在协议栈的特殊点捕获数据包的,而netpoll却可以在网卡之上直接捕获数 据包,它们甚至连协议栈的最底端都到不了。以后,如果想在内核态直接发包,再也不用PACKET套接字从用户态开始了,构造一个数据包,直接通过 netpoll接口发出。问题是,它采用手工触发中断处理函数的方式,效率如何待测试。因此这种机制最好还是限制于调试和少量内核审计信息的发送吧。用它 做×××,我觉得悬...