为什么网卡停止收包?——Intel网卡RX Buffer Replenishment机制深度解析(下)

📅 2026/7/5 3:57:25 👁️ 阅读次数 📝 编程学习
为什么网卡停止收包?——Intel网卡RX Buffer Replenishment机制深度解析(下)

接上文:为什么网卡停止收包?——Intel网卡RX Buffer Replenishment机制深度解析(上)-CSDN博客

八、rte_eth_rx_burst()真正做了什么?

很多开发者认为:

rte_eth_rx_burst()

只是从网卡取Packet。

实际上对于Intel PMD来说RX Burst通常包含四个阶段:

检查DD Bit ↓ 取出mbuf ↓ 补充新的RX Buffer ↓ 更新RDT

真正保证RX能够持续运行的。

不是DD。

而是后两步。

如果没有新的Buffer。

整个RX Ring最终都会被消费完。


核心知识点四

RX Descriptor是可以重复使用的。

真正需要不断重新分配的是:Descriptor关联的mbuf Buffer。

Descriptor只是重新写入新的DMA地址。


九、PMD为什么不停申请新的mbuf?

来看Intel PMD的大致流程。

逻辑可以抽象为:

mbuf = rte_pktmbuf_alloc(rxq->mb_pool); rxdp->pkt_addr = rte_mbuf_data_iova(mbuf); rxdp->hdr_addr = 0;

这里并没有重新创建Descriptor。

而是把新的mbuf地址重新写入Descriptor。

于是NIC:下一次收到Packet。

便可以继续DMA。

如果这里没有成功申请mbuf。

意味着Descriptor没有新的DMA目标。

NIC最终就会没有Buffer可以使用。


十、为什么不会每处理一个Packet就更新RDT?

继续阅读PMD源码。

会发现:更新RDT通常不是每个Packet执行。

而是满足一定条件。

例如:

rx_free_thresh

达到以后。

一次补充一批Descriptor。

最后统一更新RDT。

为什么?

如果每处理一个Packet。

就写一次RDT。

意味着:CPU需要不断访问NIC寄存器。

对于PCIe设备来说。

寄存器属于MMIO。

一次MMIO远远比普通Cache访问昂贵。

因此。

Intel PMD采用批量更新。

大幅减少Doorbell。

提升吞吐。


核心知识点五

RDT更新属于MMIO操作。

它的成本远高于普通内存写。

因此:PMD一定采用批量更新。


十一、RDT到底是什么?

Intel网卡维护两个重要指针。

RDH Receive Descriptor Head NIC维护 RDT Receive Descriptor Tail Driver维护

可以理解为:

RDH -------------> Descriptor Ring <------------- RDT

其中:

RDH表示NIC已经消费到哪里。

RDT表示驱动已经准备好多少新的Buffer。

NIC只能在RDH和RDT之间继续DMA。

如果RDH追上RDT。

说明已经没有新的Buffer。

即使链路仍然收到Packet。

NIC也只能停止接收。

直到Driver再次推进RDT。


核心知识点六

真正决定NIC还能继续DMA。

不是DD。

而是:RDT后面是否还有可用Buffer。


十二、为什么现场会出现"停止几十毫秒"?

继续分析现场日志。

最终发现。

某版本为了减少mbuf申请次数。

修改了补充策略。

导致:

rx_free_thresh

设置过大。

结果:

CPU一直忙于业务处理。

长时间没有进入补Buffer流程。

NIC不断消耗Descriptor。

最终:

RDH追上RDT。

RX短暂停止。

随后:

CPU终于完成一次批量补充。

更新RDT。

NIC立即恢复DMA。

整个过程:持续几十毫秒。

与现场现象:完全一致。


十三、为什么DPDK一定使用Mempool?

有人会问既然不断申请mbuf。

为什么不用malloc()?

原因就在于RX路径必须极快。

Mempool能够提供固定大小对象。

Lockless。

Cache友好。

NUMA感知。

批量分配。

如果改成系统malloc。

不仅延迟增加。碎片也会越来越严重。

最终:RXBuffer补充速度下降。影响整个RX流水线。

因此高速数据平面几乎都会使用对象池。而不会动态申请内存。


核心知识点七

RX Buffer Replenishment:本质上不是内存管理问题。

而是:高速DMA流水线的一部分。


十四、RX完整生命周期

理解整个RX路径最好的方式就是记住下面这条完整生命周期。

Packet │ ▼ NIC收到Packet │ ▼ DMA写入mbuf │ ▼ Descriptor DD=1 │ ▼ CPU读取Descriptor │ ▼ CPU处理Packet │ ▼ 旧mbuf交付协议栈 │ ▼ 申请新的mbuf │ ▼ 重新填写Descriptor │ ▼ 更新RDT │ ▼ NIC继续DMA

真正:高性能RX路径实际上是一个不断循环补充Buffer的过程。


十五、全文总结

很多DPDK开发者把注意力集中在DD Bit,因为DD代表一个Descriptor已经可以被CPU处理。

然而,对于网卡来说,DD只是一次DMA完成的标志,并不意味着RX生命周期结束。

真正保证RX持续运行的是:

  • CPU及时回收Descriptor;
  • 分配新的mbuf;
  • 重写Descriptor中的DMA地址;
  • 批量更新RDT,让NIC获得新的可用Buffer。

只有这一整套Buffer Replenishment机制持续运行,RX流水线才能始终保持满速。

因此,从工程角度看,DD Bit回答的是"这个包好了没有",而RDT回答的是"下一个包还有没有地方可放"。

理解两者的区别,比单独理解DD Bit更重要。


全文核心知识点

  1. Descriptor保存的是DMA目标地址,而不是Packet数据。
  2. 每个RX Buffer通常只能完成一次Packet DMA,需要不断补充新的mbuf。
  3. rte_eth_rx_burst()不仅负责收包,还负责Buffer Replenishment。
  4. PMD采用批量补充Descriptor和批量更新RDT,以减少MMIO开销。
  5. RDT决定NIC还能否继续接收新的Packet,而DD仅表示当前Descriptor已经完成DMA。
  6. rx_free_thresh直接影响Buffer补充时机,配置不合理可能导致RX停顿。
  7. Mempool不仅是内存池,更是高速RX流水线的重要组成部分。
  8. 理解"Packet→DMA→DD→CPU→补Buffer→更新RDT→继续DMA"这一完整生命周期,是理解Intel网卡RX机制的关键。