跳转至

网卡收发的异步化:为什么做、怎么做

日期:2026-08-15 标签:rust, async, network, nic, interrupt, queue, backpressure

为什么做这件事

网卡负责收发网络数据,一个包最多 1500 多字节。老做法是定时查看(轮询):系统每隔一小段时间去问网卡"有没有新数据"。没有数据时,这些查看是空转,处理器白忙。

异步化的目标:设备有数据时才通知系统(中断),系统唤醒一个后台任务去取;没有数据时后台任务睡觉,不占用处理器。

这条路径和之前做的异步串口类似,但网卡搬运的是整个包而不是字节,而且设备侧有自己的内存队列,规则更多。

怎么做

1. 分层:中断只唤醒,不搬数据

中断处理只做最少的事:读设备状态、计数、唤醒后台任务。不碰数据、不碰队列。数据搬运交给后台任务,两边职责分开,出错时容易定位。

2. 唯一后台任务

数据搬运只由一个后台任务负责,每次最多处理固定数量的包(预算),处理完就睡,等下一次唤醒。

3. 固定容量的内存槽位

收发包各 64 个槽位,每个槽位最大 1514 字节,启动时一次性分配。内存占用有上界,不会随流量增长。

4. 满了就让对方等(背压)

槽位满了返回"忙",上层停下来等;有槽位空出来再继续。不会无限排队,也不会悄悄丢包。

5. 完成账本

每个发出去的包有编号,完成一个回收一个,一一对应。对不上就报错并保持状态,不重复回收、不谎报完成。

6. 冲刷

提交一批数据后,可以等待这一批全部真正发完,而不是"塞进队列就算成功"。

7. 通知抑制

一批包只通知一次,避免高频小包下的中断风暴。

8. 先写测试再写代码

先用测试定义期望、观察失败,再实现到通过。并发竞态类测试重复跑 100 次,防止偶发问题漏网。

9. 验证程序与状态快照

验证程序用固定判定标准,能证明真的发了指定数量的数据、在截止时间内完成;状态快照让内部账本可见,还能暂停/放行某一阶段,用来复现"槽满"。

代码在哪

现在的进度

  • 收包异步化:完成,QEMU 验证通过。
  • 有界双向数据面:完成,六种收发场景验证通过。
  • 应用可见的异步网络:完成,协议栈独立推进、就绪状态桥到 select/poll。
  • 故障恢复语义:完成,在单 hart QEMU 上闭环设备 reset、分层取消、阶段超时与链路断开/恢复,并全量回归。

参考