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