一、为何要有NAPI:中断风暴与性能的权衡

早期Linux网络栈采用纯中断模式——每收到一个数据包,网卡触发硬中断,CPU暂停当前工作进入中断处理例程。千兆网络下82字节小包线速约1.488Mpps,万兆下则高达14.88Mpps。这意味着每秒百万级中断上下文切换,CPU将全部时间消耗在模式切换和数据拷贝上,甚至引发中断风暴(IRQ Storm)——系统完全失去响应,watchdog超时重启。

NAPI(New API)的核心思想是中断 轮询混合模式:

  1. 第一个数据包到达触发硬中断
  2. 中断处理中关闭后续中断,将设备加入轮询列表并调度软中断
  3. 软中断上下文中批量调用驱动的poll()函数收割数据包
  4. 所有数据包处理完毕,重新开启中断

这种设计将每包一次中断的O(N)中断开销降低为每轮一次中断的O(1)中断开销,极大提升了高吞吐场景的CPU效率。

二、NAPI核心数据结构

2.1 struct napi_struct

每个NAPI实例对应一个napi_struct,这是驱动注册轮询机制的最小单元:

struct napi_struct {
    struct list_head poll_list;    // 全局轮询链表节点
    unsigned long  state;          // NAPI状态机:SCHED/POLL_DISABLED/...
    int            weight;         // 每次poll()最大收包配额(默认64)
    int            (*poll)(struct napi_struct *, int);  // 收包回调
    unsigned int   gro_count;      // GRO合并计数
#ifdef CONFIG_NET_RX_BUSY_POLL
    unsigned long  busy_poll_end;  // busy polling截止时刻
#endif
};

weight是最关键的调优参数。默认值64意味着每次poll()调用最多处理64个数据包(对应64次DMA描述符处理)。Intel ice驱动在高性能场景配置为128~256。

2.2 状态机与生命周期

NAPI运行在一个精巧的状态机上:


[硬件中断到达]
    ↓
napi_schedule() // 触发软中断,状态设为NAPI_STATE_SCHED
    ↓
[softirq NET_RX_SOFTIRQ] 
net_rx_action() // 从poll_list中取出napi_struct
    ↓
调用poll(budget) // budget = dev-                        
                    
点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部