网卡是如何接收数据的
预备知识
硬件中断:一般是由硬件产生的,当外设侦测到变化时,告知中断控制器,中断控制器通过CPU或内存的中断脚通知CPU,然后完成程序计数器及堆栈寄存器的现场保存,进行上下文切换,并根据中断向量调用对应的中断处理程序进行中断处理。
软中断:一般是软件程序直接以一个CPU中断指令的形式指示CPU进行程序计数器及堆栈寄存器的现场保存工作,并进行上下文切换,然后调用相应的软中断处理程序进行中断处理(即系统调用)。
硬件中断直接以硬件的方式引发,响应速度快;软中断以软件指令的方式触发,适合于对响应速度要求不是特别严格的场景。
Q:为什么要使用软中断?
A:由于硬件中断处理程序执行的过程中不能被中断,所以如果它执行时间过长,会导致CPU没法响应其它硬件的中断,于是内核引入软中断,这样可以将硬中断处理函数中耗时的部分移到软中断处理函数里面来慢慢处理。
网卡接收数据的步骤
- 网卡接收到一个数据包,根据目的MAC地址判断是不是发给自己的,如果不是则将丢弃该数据包;
- 网卡通过DMA技术将数据包拷贝内存中的RingBuffer(一个环形缓冲区)中;
- 网卡触发硬件中断,通知CPU接收到了数据包;
- CPU根据中断处理表,调用已注册的中断处理函数,该函数又会去调用网卡的驱动程序中相应的函数;
- 驱动程序先屏蔽网卡的中断,表示驱动程序已经知道内存中有数据了,告诉网卡下次再收到数据包直接写内存就可以了,不要再通知CPU了,这样可以提高效率,避免CPU不停的被中断;
- 启动软中断,这步结束后,硬件中断处理函数就结束返回了;
- 内核中的ksoftirqd进程专门负责软中断的处理,当它收到软中断后,就会调用相应软中断所对应的处理函数,对于上面第6步中是网卡驱动模块抛出的软中断,ksoftirqd会调用网络模块的net_rx_action函数,该函数调用网卡驱动里的poll函数来一个一个的处理数据包;
- 将数据包沿协议栈向上传递,逐层处理;
- 待内存中的所有数据包被处理完成后(即poll函数执行完成),启用网卡的硬件中断,这样下次网卡再收到数据的时候就会通知CPU;