4. 传统收包路径:经典中断方式下网卡驱动收包流程与性能开销

在深入 NAPI 之前,必须先理解传统中断驱动收包路径的完整流程。经典方式下,每当网卡接收一个数据包,就会触发一次硬件中断,通知 CPU 暂停当前任务去处理该包。这种“每包必中断”的模式在低速网络时代工作良好,但在高速网络下会引发严重的性能问题。

4.1 经典中断收包全流程

下图展示了从数据包到达网卡到交付给协议栈的完整中断驱动路径:

经典中断驱动收包流程 经典中断驱动收包流程 ① 网卡接收数据包 ② DMA 写入 Ring Buffer ③ 触发硬件中断 ④ 中断处理上半部 (ISR) ⑤ 调度软中断 (NET_RX_SOFTIRQ) ⑥ 软中断处理 (net_rx_action) ⑦ 协议栈处理 (IP/TCP/UDP) ⑧ 用户态 socket 接收 ⚠ 关键性能瓶颈 • 每个包都触发硬件中断 • 中断上下文切换开销大 • 高 PPS 下 CPU 被中断淹没

4.2 各阶段详细开销分析

传统中断路径的每个阶段都引入可量化的 CPU 开销。下表汇总了各环节的主要性能损耗:

阶段 操作内容 主要开销类型 相对开销等级
① 硬件中断触发 网卡向中断控制器发送 IRQ,CPU 保存当前上下文 中断上下文切换、Cache 污染 高
② ISR 执行 读取中断状态寄存器,标记设备,调度软中断 寄存器 I/O 访问、中断屏蔽/解屏蔽 中
③ 软中断调度 设置 NET_RX_SOFTIRQ 标志位,触发软中断处理 软中断向量查找、ksoftirqd 唤醒 低
④ 软中断处理 调用 net_rx_action,从 Ring Buffer 读取 skb 内存拷贝、skb 分配、链表操作 高
⑤ 协议栈处理 IP 分片重组、TCP 重组、校验和验证 CPU 计算、内存访问、锁竞争 高
⑥ 用户态交付 将 skb 放入 socket 接收队列,唤醒用户进程 进程调度、锁、系统调用 中

关键指标:在 1 Gbps 网络下,64 字节小包的理论 PPS 约为 1.49 Mpps。传统中断方式每包约消耗 2-5 μs CPU 时间,这意味着单核 CPU 最多只能处理约 200 Kpps,远低于线速。中断频率与包速率成正比,导致 CPU 利用率随 PPS 线性增长。

4.3 中断风暴:性能崩溃的根源

当网络流量增大时,传统中断路径会陷入“中断风暴”恶性循环:

  1. 高 PPS 触发大量中断:每到达一个数据包,网卡就触发一次硬件中断。
  2. CPU 被中断淹没:CPU 频繁保存/恢复上下文,实际用于处理数据包的时间比例下降。
  3. Cache 抖动加剧:中断处理导致 L1/L2 Cache 频繁失效,指令流水线被打断。
  4. 吞吐量断崖式下降:当中断频率超过 CPU 处理能力时,丢包率急剧上升,有效吞吐量反而下降。
中断风暴恶性循环 中断风暴恶性循环 高 PPS → 大量中断 CPU 被中断淹没 Cache 抖动 + 上下文切换 吞吐量断崖下降 + 丢包

实际案例:在 10 Gbps 网络下,64 字节小包线速为 14.88 Mpps。传统中断方式在单核上最多处理约 200 Kpps,这意味着超过 98.6% 的中断无法被及时处理,导致大规模丢包。这也是为什么现代网卡驱动必须引入 NAPI 轮询机制的根本原因。

4.4 传统中断路径的三大性能开销

将上述分析归纳为三个核心开销维度:

开销维度 具体表现 量化参考(每包)
上下文切换开销 硬件中断保存/恢复寄存器、TLB 刷新、中断栈切换 0.5 - 2 μs
Cache 污染开销 中断处理代码和数据挤占 L1/L2 Cache,导致应用程序 Cache 命中率下降 10% - 30% 应用性能损失
调度与锁开销 软中断调度、ksoftirqd 唤醒、skb 分配锁、协议栈锁竞争 1 - 3 μs

性能优化启示:传统中断路径的核心矛盾在于“中断频率与包速率成正比”。要突破性能瓶颈,必须打破这种线性关系——这正是 NAPI 轮询机制的设计目标:在高速率下将中断转换为轮询,大幅降低每包的中断开销。

4.5 传统路径与 NAPI 路径的初步对比

在进入 NAPI 详细分析之前,先通过下表建立两种路径的宏观对比:

对比维度 传统中断路径 NAPI 轮询路径
中断触发频率 每包一次硬件中断 仅在开始轮询时一次中断
CPU 开销特征 中断开销随 PPS 线性增长 中断开销固定,轮询开销可控
高 PPS 表现 中断风暴,吞吐量崩溃 稳定处理,接近线速
适用场景 低速率网络(< 100 Kpps) 高速率网络(> 1 Mpps)
公平性 各设备公平中断 需配额机制防止饿死