DragonOS NAPI 与 NetNamespace Poll 机制设计说明

本文档对 DragonOS 当前网络子系统中的 NAPI(New API)机制与 NetNamespace 轮询调度机制的设计与实现进行说明。

1. 机制概览

DragonOS 的网络包处理采用 “事件驱动 (Event-Driven) + 精确定时 (Precise Timing)” 的混合驱动模型。系统通过独立的内核线程来分别处理”硬件中断触发的收包任务”和”协议栈定时任务”,实现了对网络流量的高效响应与 CPU 资源的合理调度。

核心设计包含两个主要部分:

  1. NAPI 子系统:负责高吞吐量的网络包收发处理,采用”有界轮询 (Bounded Polling)” 机制。

  2. NetNamespace 调度器:负责管理协议栈的时间事件(如 TCP 重传),充当精确定时器。

2. 核心组件设计

2.1 NAPI 子系统 (kernel/src/driver/net/napi.rs)

NAPI 是 DragonOS 网络驱动层的核心收包机制。

  • NapiStruct: 每个支持 NAPI 的网卡接口(Iface)都绑定一个 NapiStruct 结构体。它维护了 NAPI 实例的状态(如 SCHED 调度位)和权重(weight)。

    • Weight (权重): 定义了单次调度周期内该接口允许处理的最大数据包数量(Budget),防止单网卡独占 CPU。

  • 全局 NAPI 管理器 (Global NapiManager):

    • 目前实现为单例(GLOBAL_NAPI_MANAGER)。

    • 维护一个全局的 napi_list 待处理队列。

    • 提供 napi_schedule() 接口:供网卡中断处理函数调用,将 NAPI 实例加入队列并唤醒处理线程。

  • NAPI 处理线程 (napi_handler):

    • 这是一个专用的内核线程,并在系统启动时初始化。

    • 工作逻辑:不断从 napi_list 取出被调度的 NAPI 实例,调用其 poll() 方法。

    • 循环调度:如果 poll() 返回 true(表示 Budget 用尽但仍有数据),线程会将该实例重新放回队列尾部,等待下一轮调度。

2.2 NetNamespace 调度器 (kernel/src/process/namespace/net_namespace.rs)

每个网络命名空间(NetNamespace)拥有一个独立的轮询线程(netns_poll),在当前设计中,它主要承担 “定时器”“兜底调度器” 的角色。

  • 精确定时: 该线程维护了命名空间内所有网卡的 poll_at_us(下一次需要处理的时间点)。它会计算出最近的截止时间(Deadline)并进行精确休眠(wait_event_timeout)。

  • 超时触发: 当休眠超时(即协议栈定时事件到达,如 TCP RTO)时,该线程不会直接处理数据包,而是调用 napi_schedule(),将任务分发给 NAPI 线程执行。这保证了繁重的协议栈处理逻辑统一由 NAPI 线程承担。

2.3 有界轮询 (Bounded Polling)

kernel/src/driver/net/mod.rs 中实现了适配 NAPI 的轮询接口 poll_napi(budget)

  • 逻辑

    1. 调用 smoltcppoll_ingress_single 处理接收队列,循环次数受 budget 限制。

    2. 执行一次 poll_egress 推进发送队列。

    3. 更新 poll_at_us 时间戳,供 NetNamespace 调度器参考。

  • 特性:保证了每次调度的执行时间是可控的,避免了长时关中断或线程饿死。

3. 工作流程图解

当前系统的网络处理数据流与控制流如下:

flowchart TD
    %% 硬件层与驱动层
    subgraph Hardware_Driver [硬件与驱动层]
        NIC[物理网卡]
        IRQ_Handler[中断处理函数]
        NIC -->|数据包到达| IRQ_Handler
    end

    %% NAPI 子系统
    subgraph NAPI_System [NAPI 子系统]
        NapiManager[NapiManager 全局队列]
        NapiThread[NapiHandler 线程]
        
        IRQ_Handler -->|1. napi_schedule| NapiManager
        NapiManager -->|2. 唤醒| NapiThread
        NapiThread -->|3. 取出 NapiStruct| NapiThread
    end

    %% 协议栈与定时器
    subgraph Network_Stack [协议栈与定时器]
        Smoltcp[smoltcp 协议栈]
        NetnsThread[Netns 调度线程]
        
        NapiThread -->|4. poll_napi (budget)| Smoltcp
        Smoltcp -->|5. 处理 Ingress/Egress| Smoltcp
        Smoltcp -->|6. 更新 poll_at_us| NetnsThread
        
        NetnsThread -.->|7. 休眠等待 poll_at| NetnsThread
        NetnsThread -->|8. 超时触发 napi_schedule| NapiManager
    end

    %% 循环反馈
    Smoltcp -.->|9. 数据未处理完 (Budget耗尽)| NapiManager

4. 当前实现现状

截至当前版本,DragonOS 的网络机制具有以下实现特征:

  1. 单队列 NAPI 管理

    • 目前的 NapiManager 是全局唯一的,所有 CPU 共享同一个待处理队列。

    • 尚未实现 Linux 风格的 Per-CPU NAPI 队列(代码中留有 TODO)。

  2. 线程模型

    • napi_handler:负责具体的包处理和协议栈推进,是计算密集型线程。

    • netns_poll:负责时间管理和事件分发,是 IO/Sleep 密集型线程。

  3. 驱动支持

    • Virtio-Net、Veth、Loopback 等驱动已接入此机制,在中断或发包时主动调用 napi_schedule

  4. Smoltcp 适配

    • 通过 IfaceCommonsmoltcp 进行了封装,将无界的 poll() 转化为适配 NAPI 的有界 poll_napi()