欢迎光临散文网 会员登陆 & 注册

万字讲解Linux内核网络收包角度——浅入中断(2)

2022-10-22 14:43 作者:补给站Linux内核  | 我要投稿

上文万字讲解Linux内核网络收包角度——浅入中断(1)主要从针对e1000网卡收包开始,分析了硬中断注册、处理过程,网卡收包后硬中断的过程非常简洁,处理过程比较简单,主 要是将网卡的napi->poll_list加入到CPU的softnet_data->poll_list里,然后发起软中断,就结束了,下面的就交给软中断进行数据包的接收处理,所以收包任务最大程度地交给软中断处理,最大程度简化硬中断处理。 总结以上描述中,上篇博文的具体细节步骤:

  • 内核启动网卡,为网卡分配(Ring Buffer,内核通过网卡驱动将DMA内存地址信息写入网卡寄存器,使得网卡获得DMA内存信息),并通过request_irq 内核 APi注册硬中断服务例程e1000_intr

  • 网卡收到数据包,通过DMA将数据包写入内存

  • 网卡触发硬中断,通过CPU接收数据

  • CPU中断当前的进程,跳转到异常向量表的中断异常向量处

  • 保存现场

  • 调用irq_handler

  • 对于ARM64,irq_handler将调用gic_handle_irq

  • gic_handle_irq首先读取中断寄存器得到硬件中断号,调用handle_domain_irq函数

  • handle_domain_irq->irq_enter进入中断上下文

  • handle_domain_irq->irq_find_mapping通过硬件中断号获取IRQ Number

  • handle_domain_irq->generic_handle_irq进入中断通用层处理

  • generic_handle_irq->irq_to_desc通过IRQ Number获取对应的中断描述符

  • generic_handle_irq->generic_handle_irq_desc->__handle_irq_event_percpu:遍历中断描述符中的action链表,依次执行每个action中回调函数action->handler,对应e1000网卡驱动,执行e1000_intr中断服务例程

  • e1000_intr->ew32(IMC, ~0)禁止网卡中断,避免频繁硬中断,降低内核的工作效率

  • e1000_intr->napi_schedule激活NAPI, napi_struct.poll_list 挂在 softnet_data.poll_list 上,方便后面软中断调用 napi_struct.poll 获取网卡数据。然后设置NET_RX_SOFTIRQ 软中断标识位。

  • handle_domain_irq->irq_exit():退出中断上下文,触发软中断执行收包流程。

  • 恢复现场

上文万字讲解Linux内核网络收包角度——浅入中断(1)重点在于通过网卡收包分析了硬中断,本文从网络收包角度分析和学习软中 断过程。

软中断的种类、定义 (Kernel 4.15)

以上是内核默认定义的几种软中断,硬中断是在CPU每个指令周期后,会去判断是否有硬中断产生,根据硬中断号找到对应的IRQ Number,执行对应的中断服务例程,而软中断会有内核线程,轮询一组标志位,如果标志位有值,那去这个标志位对应的软中断向量表,找到中断处理函数执行。


【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)  


软中断的注册

全局的软中断向量数组,即软中断描述符表

数组中的内容就是软中断触发时的钩子函数:

如网络收发包的软中断处理函数在网络子系统初始化时注册的:

注册软中断回调函数:

软中断在内核中的整体如下所示,pending为软中断标志位



其中标志位在内核中使用irq_cpustat来表示:

其中__softirq_pending为软中断标志位,该类型为int类型,最多支持32位软中断,ipi_rrq位cpu与cpu之间的中断。

在Linux内核中,定义NR_CPUS个该结构,即每个CPU有一个32bit的位图,来维护本cpu上的软中断是否激活

软中断的激活

在上文万字讲解Linux内核网络收包角度——浅入中断(1)中,硬中断的中断服务例程e1000_intr执行:

e1000_intr->__napi_schedule:

__napi_schedule(this_cpu_ptr(&softnet_data),n):

最终调用__raise_soft_irqoff设置软中断标志位,nr为NET_RX_SOFTIRQ

可以看到在执行__raise_soft_irqoff函数前,在__napi_schedule中,先是通过local_irq_save(flags)禁用了中断,因为置位位图是一个竞争操作,所有硬中断都可以做,所以要保证关中断的情况下完成,等pending置位结束后调用local_irq_restore(flags)恢复中断。

内核线程ksoftirqd是如何监测到软中断发生的:

上面函数先关中断查看本cpu的pending置位情况,如果有则进行进一步软中断处理。

软中断的入口函数__do_softirq:

对于数据包接收h->action()将执行:网络子系统注册的的回调函数net_rx_action:


关于net_rx_action涉及到软中断处理中进一步使用NAPI机制收包,在接下来的文章中进行分析和学习。


原文作者:技术简说



万字讲解Linux内核网络收包角度——浅入中断(2)的评论 (共 条)

分享到微博请遵守国家法律