在阅读有关网络驱动程序中的NAPI调度时,我有一个疑问。
通常,整个网络处理代码都在softirq上下文中运行。借助NAPI轮询机制,驱动程序将在中断到达后轮询数据包。
因此,如果NAPI代码也可以在softirq上下文中运行,那么如何安排它。 (因为,无法安排中断上下文代码)。
网络驱动程序中工作队列的用途是什么。
最佳答案
在NAPI的意义上进行调度仅意味着将其标记为需要运行。换句话说,您只需简单地使函数调用说“安排我在NAPI softirq中运行”即可。这将导致驱动程序的轮询功能被添加到“需要轮询”的设备列表中,并且还导致NAPI softirq在“出路”被激活。
因此,它通常以这种方式工作。您的驱动程序将设备配置为告诉它在将来准备处理某些数据包(理想情况下是多个数据包,以分摊开销)时在某个时候中断。同时,内核调度普通的用户空间进程。
设备中断时:
如果尚未进入内核模式,则中断将导致转换到内核模式
linux中断处理代码查找驱动程序的中断处理程序例程并调用它。
您的中断处理程序将调用napi_schedule
(将轮询功能放在列表中并触发softirq。
您的中断处理程序返回。
在返回用户模式(或中断之前CPU所做的任何事情)之前,中断处理代码会看到网络softirq需要运行并激活它。
softirq调用您的轮询功能来处理传入的数据包,直到没有更多数据包或NAPI“预算”用尽为止。 (在后一种情况下,稍后会通过ksoftirqd
线程[我认为]重新调用softirq。)
然后,如果驱动程序已完成对所有准备处理数据包的处理,则驱动程序将仅在设备上重新启用中断。
以我的经验,工作队列通常仅用于某些需要在可调度上下文中进行的长时间操作(即,在等待某些事情完成时可能会阻塞[睡眠]的实际任务上下文)。
例如,在intel ixgbe驱动程序中,如果驱动程序检测到需要重置NIC,则会触发工作队列条目以重新初始化NIC。其中一些操作需要相对较长的睡眠时间,并且如果您可以让其他任务运行,则不想在softirq上下文中占用处理器。可能还有其他原因-例如,您需要分配大量内存,这可能需要在任务上下文中进行分配调用。