一个数据包从网卡进入到被上层应用程序接受大致的路程如下:
(1)网卡在一个数据包到来时,会产生一个硬件中断。不同的硬件具有不同的硬件中断号,硬件会根据中断号调用对应的函数(驱动程序)进行处理。对于网卡驱动程序来讲,就是申请数据缓存空间sk_buffer结构,将收到的数据放入sk_buffer结构中,并挂到网卡对应的接收队列中(现在的网卡一般具有多个接收队列),紧接着产生一个软件中断(通过tasklet机制)来处理网络协议栈相关的处理,这样硬件中断算是结束了。
(2)硬件中断的最后会构建一个tasklet_struct,该结构指明了具体的回调函数。linux内核软中断daemon进程(ksoftirqd)会检测到tasklet事件的发生,然后执行对应的tasklet action函数。即分别交给对应的协议栈程序处理,IP层输入处理程序、TCP/UDP层输入处理程序,最后应用程序会接受到协议层处理完毕后的信号已经对应的网络数据。
软中断机制的核心构成要素
(1)软中断状态:表示是否有触发的软中断需要处理。注意:软中断不能被另外一个软中断所抢占。
(2)软中断向量表:相应地回调函数和调用参数。
struct softirq_action{
void (*action)(struct softirq_action *);
void *data;
}
(3)软中断守护内核线程,硬件中断中中断向量到中断服务程序是由硬件自动完成映射的;对于软中断则是由内核中的中断服务守护线程去实现的(ksoftirq),它会去轮询中断状态,然后调用对应的中断服务程序。Linux中最多可以注册32个软中断,目前系统使用了6个软中断:定时器、SCSI处理、网络收发处理、tasklet机制。其中tasklet机制也就是平常所说的硬件中断的“下半部分”。
多队列网卡
为了应对网络IO的提升,现在网卡都包含多个收发队列,每个队列都有不同的硬件中断号,因此在网卡流量很大的时候,可以显示的将队列绑定到不同的CPU核心上来提高网络IO处理的效率,即网卡的cpu affinity设置。默认情况下,所有队列的中断处理都在CPU0上进行,或者如果安装了irqbalance服务的话,进行动态均衡。