为什么网卡停止收包?——Intel网卡RX Buffer Replenishment机制深度解析(上)
一、一次十分诡异的现网故障
某数据中心部署了一套基于DPDK开发的100GbE高性能交换机。
系统上线数月后。
现场反馈:
业务偶尔出现:20~50ms流量中断。
随后自动恢复。
整个过程中:
CPU始终100%。
Worker没有退出。
PMD持续运行。
监控如下:
| 指标 | 状态 |
|---|---|
| PMD CPU | 100% |
| RX Queue | 正常 |
| TX Queue | 正常 |
| Descriptor Error | 0 |
| DD Bit | 正常 |
| Link | Up |
继续抓取:网卡统计。
发现:
CRC Error:0。
Missed Packet:0。
RX No Buffer:0。
一切似乎都没有问题。
但是:
交换机就是停止收包几十毫秒。
随后又恢复正常。
核心知识点一
对于DPDK来说:DD Bit正常,并不意味着RX能够持续运行。
真正决定:NIC是否还能继续DMA。
还有另外一个容易被忽略的条件。
二、第一轮排查:怀疑DD Bit
由于收包停止。
团队首先怀疑Descriptor。
于是:增加调试日志。
持续打印Descriptor Status。
例如:
status = rxdp->wb.upper.status_error;观察发现:
DD始终能够正常置位。
并不存在Descriptor没有回写的问题。
因此排除:Write Back异常。
三、第二轮排查:怀疑RX Ring
继续查看RX Ring。
发现:RDH、RDT均处于合理范围。
Descriptor没有耗尽。
Ring也没有Overflow。
很多开发者此时都会认为:RX Ring没有问题。
事实上这里恰恰隐藏着真正的陷阱。
核心知识点二
RX Ring里面保存的不是Packet。
保存的是:Buffer描述信息。
四、很多人一直误解了RX Descriptor
第一次阅读Intel网卡手册。
很多人都会认为:RX Descriptor就是Packet。
实际上完全不是。
例如:
Intel 82599:Advanced RX Descriptor里面主要包含:
Packet Buffer Address Header Buffer Address Status Length RSS Hash VLAN Checksum注意。
真正的数据并没有存放:Descriptor。
Descriptor只保存一个DMA目标地址。
真正Packet存放在mbuf对应的数据缓冲区。
也就是说:Descriptor更像一张"地址卡片"。
告诉NIC:
下一帧数据,请DMA到这里。
五、真正的数据流是什么?
收到一个Packet以后。
NIC真正执行的是:
Packet ↓ MAC ↓ RX FIFO ↓ DMA到mbuf Data Buffer ↓ 更新Descriptor Status ↓ DD = 1CPU随后读取Descriptor获得Packet Length、RSS、Checksum。
然后取得对应mbuf。真正处理Packet。
注意。
这里CPU已经拿走了这个mbuf。
那么问题来了。
NIC下一次收到Packet。
还能继续DMA到同一个Buffer吗?
答案:不能。
核心知识点三
一个RX Buffer只能完成一次DMA。
Packet被CPU接管以后。
NIC必须重新获得一个新的Buffer。
才能继续收包。
六、真正容易被忽略的一半生命周期
很多开发者理解的RX流程:
只有前半段。
例如:
Packet ↓ DMA ↓ DD=1 ↓ CPU收到mbuf于是认为整个RX流程结束。
实际上真正完整的生命周期应该是:
Packet ↓ DMA到mbuf ↓ DD=1 ↓ CPU处理Packet ↓ 释放旧Buffer ↓ 重新申请mbuf ↓ 重新填写RX Descriptor ↓ 通知NIC ↓ 下一次DMA也就是说。
CPU处理完Packet以后。
真正重要的工作才刚刚开始。
如果没有新的Buffer。
NIC即使收到Packet。
也没有地方DMA。
七、问题终于开始浮现
继续阅读PMD源码。
发现rte_eth_rx_burst():并不是收到Packet就结束。
真正最后还有一段容易被忽略的代码。
它负责:
- 分配新的mbuf;
- 重新填写RX Descriptor;
- 更新RX Tail。
看到这里。
真正的问题终于浮现。
现场DD正常、Descriptor正常、CPU正常。
但是NIC为什么还是停止收包?
真正值得怀疑的已经不是DD Bit。
而是:RX Buffer Replenishment(接收缓冲补充)机制。
(未完待续)