跳到主要内容

内存与队列

网络数据面使用有界、预分配、move-only 的所有权流水线。当前不承诺端到端 zero-copy;目标是让 DMA buffer 在 queue CPU 与唯一 protocol CPU 之间的每次转移都 可证明,并让 ring 满、submit retry、stop/rollback 不会复制或泄漏 token。

1. 内存域

内存域对象owner
hardware/DMADmaBuffer、descriptor/virtqueuefixed-CPU QueueGroupExecutor
queue/protocol boundary四条 SPSC ring + pending_* slot每条唯一 producer/consumer
Ethernet frameDMA ProtocolRxFrame 或兼容 ProtocolEthernetFrame唯一 protocol executor
Router packet bufferRouter.rx_buffer / tx_buffer唯一 protocol executor
smoltcp socket bufferTCP SocketBuffer、UDP/raw PacketBufferSocketSet / protocol executor
user buffersyscall IoBuf/IoBufMut调用者

hard IRQ 不拥有 DMA payload。它只拥有 endpoint-local status snapshot,并发布对应 group。

2. Move-only DMA token

DmaBuffer 不实现 Clone/Copy。buffer 包含 CPU mapping、bus address、capacity、 effective length 与 DMA sync 能力。合法 RX 状态:

pool
-> IRxQueue::submit / initial_refill
-> device DMA ownership
-> IRxQueue::reclaim -> RxCompletion { buffer, packet_len }
-> submit replacement before publishing completion
-> RX-ready SPSC -> ProtocolRxFrame
-> EthernetDevice -> Router -> smoltcp RxToken::consume
-> RxRecycler -> RX-recycle SPSC/overflow
-> queue-local spares -> later replacement

合法 TX 状态:

pool
-> TX-free SPSC
-> protocol fills frame
-> TX-ready SPSC
-> ITxQueue::submit_with_options -> flush
-> device DMA ownership
-> ITxQueue::reclaim
-> TX-free SPSC

SubmitError 必须携带原 buffer。Retry 时 runtime 保存在 pending_txpending_rx_refill;terminal error 也先恢复可回收 ownership,再决定 group failure。

3. SPSC memory ordering

每条 ring 预分配 capacity + 1UnsafeCell<MaybeUninit<T>> slot,以保留一个 slot 区分 full/empty。

  • producer 独占 tail slot,写 payload 后 Release publish tail
  • consumer Acquire observe tail,read payload 后 Release publish head
  • producer Acquire observe head 后才能复用 slot;
  • endpoint 非 Sync,不能产生第二 producer/consumer;
  • T: Send 是 token 跨 CPU 的最低条件。

ring Drop 只在两个 endpoint 都不再并发访问时遍历剩余 live slot。unsafe safety 依赖 唯一 endpoint 与 Acquire/Release 配对,不依赖外部大锁。

4. Ring capacity

RX-ready/recycle capacity 来自 driver RX queue capacity,TX-ready/free capacity 来自 TX queue capacity。runtime 不再用 protocol crate 的固定“设备 RX/TX queue size”覆盖硬件 ring 深度。

容量与 token 数量相等,因此初始化可以把全部 TX pool token 放入 TX-free ring;RX initial refill 使用 driver capacity。spsc_ring() 额外保留内部 sentinel slot,不减少 对调用者承诺的有效容量。

5. Backpressure

ring full 不会 busy-wait 或 drop token:

边界owner 保留
RX-ready fullpending_rx: RxCompletion
RX replacement submit retrypending_rx_refill 保存 completion 和 replacement;丢包重投时只保存原 token
TX-free fullpending_tx_free: DmaBuffer
TX submit retrypending_tx: TxRequest 保存 token 与提交选项
protocol recycle fullRxRecycler 的 overflow vector
protocol TX-ready fulltoken 回到 protocol tx_spares

queue group 在 blocked 时保持 IRQ mask。protocol owner 消费或释放 ring 空间后精准 schedule 该 group;没有周期 retry timer。

取走 RX-ready 中的 completion 时,ring slot 已可复用,必须立即通知 queue owner。 这个通知不能延后到 ProtocolRxFrame 析构:协议可能在等待 TX 空间时保留 DMA frame, 而释放 TX 空间又需要 queue owner 继续运行。DMA token 仍只在消费完成后归还, ring 空间通知与 DMA 回收是两个独立的进度事件。

TX submit 返回 RetryLinkDown 时,只结束本轮发送提交并保留待发请求; 已提交批次仍需 flush,RX 回收、补充和交付仍按预算推进。否则,共用 SDIO owner 的 收发路径可能相互等待。没有可推进工作时仍通过原有 rearm 流程等待中断。

6. DMA synchronization

CPU 读取 RX payload 前使用 read_with_cpu(),CPU 写 TX payload时使用 write_with_cpu()。driver 在 submit/reclaim 边界完成 device-direction sync 和 doorbell/ completion ordering。非一致 DMA 平台必须在这些 API 中实现 cache maintenance,不能 假设 Rust atomic fence 会刷新设备 cache。

ownership publish 顺序:

RX completion observed
-> device-to-CPU sync
-> Release SPSC publish
-> protocol Acquire + read

protocol write
-> Release SPSC publish
-> queue Acquire
-> CPU-to-device sync
-> descriptor/doorbell publish

7. Protocol copies

DMA RX 的 ProtocolRxFrame 保留原 token,经 EthernetDevice 和 Router 传到 smoltcp RxToken::consume,不经过 inline frame 或 Router packet buffer 复制。 消费完成才归还 token;queue owner 已在发布 completion 前提交 replacement,硬件 不必等待协议栈释放旧 buffer。回收 token 优先进入 queue-local spare cache。额外 token 上限为 max(RX capacity, 64), 因此每 group 的 RX payload 上限为 (RX capacity + max(RX capacity, 64)) * buf_size; 还需计入 pool/token 元数据。overflow 和 spare cache 只容纳这些已存在的 token, 不再通过持续分配扩大这项预算。到达上限或 DMA 分配失败时丢包并重投原 token, RX drop 经 frame port 汇总到设备统计。

TX 从 socket buffer 经 smoltcp/Router 生成 IP packet,直接填充 DMA token 中的 Ethernet header、payload 和 padding。可选 checksum offload 与 deferred doorbell 随 token 传递。非 DMA 端口和设备 FIFO 积压继续使用兼容 frame,socket/user buffer 之间也仍有复制。loopback 直接注入 Router RX buffer,不分配物理 DMA token。

7.1 Device TX queue discipline

每个物理设备的 QueueFramePort 都持有一个显式 TxQueueDisciplineNoQueue 直接 提交,busy 时返回 Again,其 pending_tx 始终为空且 VecDeque 不分配 backing。 Fifo { max_frames } 在 busy 后保留 ProtocolEthernetFrameTxSubmitOptions 并按序重试;构造时 同样使用 VecDeque::new(),第一次真实入队前 capacity 为零。

64 位目标上的一个 ProtocolEthernetFrame 是 2048 字节 payload 加 8 字节长度, 因此 64 个 frame 的内容为 64 * 2056 = 131584 字节,即 128.5 KiB;此外还有逐包提交选项、队列和 allocator metadata。当前 axruntime 为每个生产网卡显式选择 64 帧 FIFO;这部分内存只在该设备 实际形成 backlog 后增长,不再由所有网卡在启动时预留。不同设备的 limit 和 backlog 彼此独立;hardware ring、SPSC token pool 与 AIC queue size 仍按各自所有者另外计算。

8. Protocol/socket budgets

协议常量仍集中在 consts.rs

TCP RX/TX: 256 KiB each per socket
UDP RX/TX: 64 KiB each per socket plus packet metadata
RAW RX/TX: 64 KiB each per socket plus packet metadata
LISTEN_QUEUE_SIZE: 512
SOCKET_BUFFER_SIZE: 64 packet slots
ETHERNET_MAX_PENDING_PACKETS: 128

TCP 双向 buffer 合计每 socket 512 KiB;被动连接在 SYN 建立子 socket 时也分配这两块 buffer,512 个排队连接仅 payload 预算就可能达到 256 MiB,另有 socket 元数据。 当前通过 consts.rs 的两个常量统一设置,不支持运行期自动调节或每监听 socket 的独立预算。

这些是 protocol/ARP 预算,不是 hardware queue capacity。提高 socket 预算会按 socket 数量放大;提高 driver queue capacity 会按 group 增加 DMA pool 与 SPSC slot。

9. Queue budget

一个 group poll 对 TX completion、TX submit、RX recycle、RX reclaim 各最多处理 64 项;一个 CPU round 最多 256 项。预算用尽不会 rearm IRQ,而是保留 group ownership、 yield/repoll。这限制单个 burst 对同 CPU 其它 group 的占用,同时合并 IRQ。

10. Stop 与失败回收

runtime teardown 先拒绝控制请求,disable/synchronize IRQ,再 stop/join executor。只有 确认 callback 与 queue task 不再运行后才 drop ring、queue 和 DMA pool。

driver shutdown 必须返回或隔离仍可被设备 DMA 的 token。无法确认 DMA 已停止时, 宁可 quarantine buffer,也不能把 mapping 归还 allocator 后让设备继续访问。

11. 验证

确定性测试至少断言:

  • ring bounded/order 与 move-only token exactly once;
  • submit error 返回相同 bus-address token;
  • RX/TX backpressure 保留 pending token;
  • stop 后拒绝新 schedule/request;
  • budget exhaustion 保持 IRQ mask;
  • non-coherent sync 顺序由目标 driver/board 测试确认。

GRO、page-pool、scatter-gather protocol token 和 user zero-copy 不在本次 架构范围内。