Amazon ENA 驱动深度排查:安全升级、Linearize 与 DMA Mapping
Amazon ENA 驱动深度排查:安全升级、Linearize 与 DMA Mapping
ENA 问题经常被简化成“升级驱动并重启”,但真正遇到丢包、发送失败或热替换后网卡消失时,需要同时理解 PCI 设备生命周期和 Linux Tx 数据路径。
本文把两个相关主题合在一起:如何安全升级 ENA 驱动,以及 linearize_failed、dma_mapping_err 等计数器究竟对应哪一步失败。
ENA 设备生命周期
模块加载后,PCI core 匹配设备 ID 并调用 ena_probe()。驱动随后完成设备版本验证、特性协商、队列和中断初始化,再把 netdev 注册给网络栈。
卸载模块时,ena_remove() 会反向执行:停止网络设备、删除队列、释放 IRQ 和 DMA 资源,最后注销 netdev。执行 rmmod ena 不是“只替换一个文件”,而是主动拆除当前实例的主网卡驱动。
因此远程热替换具有一个显而易见的风险:SSH 和 SSM 数据通道都可能与网卡一起中断。操作前必须具备 EC2 Serial Console、带外恢复或自动回滚路径。
先记录基线
uname -r
modinfo ena | grep -E '^(version|srcversion|vermagic|filename):'
ethtool -i eth0
ethtool -S eth0 > /var/tmp/ena-stats.before
ip -details link show eth0
dmesg -T | grep -i ena | tail -100同时确认当前内核头文件与目标模块匹配:
test -e "/lib/modules/$(uname -r)/build" || echo 'missing kernel headers'vermagic 或符号版本不匹配会导致 Unknown symbol、Invalid module format,这不是 ENA 设备故障,而是模块与当前内核 ABI 不兼容。
推荐升级路径
按风险从低到高:
- 升级发行版内核,让内核自带 ENA 一起更新;
- 使用 DKMS 为每个目标内核构建并安装模块,安排重启;
- 只在有恢复通道时执行
rmmod/modprobe热替换。
DKMS 的价值是把模块构建与内核版本绑定。升级内核后,DKMS 会为新 ABI 构建模块,避免下一次启动才发现网卡驱动不存在。
升级后验证:
modinfo ena | grep -E '^(version|filename|vermagic):'
ethtool -i eth0
ip link show eth0
ethtool -S eth0 | grep -iE 'reset|timeout|dma|linear|drop|error'
dmesg -T | grep -i ena | tail -100Tx 路径中的 linearize
Linux 发送的 skb 可能由一个线性头部和多个 fragments 组成。ENA 队列描述符数量有限;当 fragment 数量超过设备或驱动允许的上限时,驱动会尝试 skb_linearize(),把分散数据合并成连续缓冲区。
这一步需要额外内存分配和复制。以下场景会增加失败概率:
- 高内存压力或碎片化;
- 异常多的 skb fragments;
- GSO/TSO 配置变化;
- 上层封装导致报文结构复杂。
查看计数器:
ethtool -S eth0 | grep -i linear大量 linearize 但没有失败不一定是故障,只说明发送路径经常需要整理 skb。linearize_failed 持续增长才意味着内存合并失败,并可能造成丢包。
排查:
cat /proc/buddyinfo
vmstat 1
slabtop -o
ethtool -k eth0 | grep -E 'scatter-gather|tcp-segmentation|generic-segmentation'不要为了消除计数器盲目关闭 TSO/GSO。应先用相同流量做 A/B,确认 offload 是否真的制造异常 fragment,而不是把 CPU 负载提高后产生新的瓶颈。
DMA mapping 失败
skb 满足描述符限制后,驱动要把每个缓冲区映射成设备可访问的 DMA 地址。如果 dma_map_single() 或 dma_map_page() 返回错误,dma_mapping_err 会增长,报文无法提交到硬件队列。
常见检查项:
ethtool -S eth0 | grep -i dma
dmesg -T | grep -iE 'dma|swiotlb|iommu|ena'
grep -i swiotlb /proc/meminfo 2>/dev/null || trueDMA mapping 错误可能与 IOMMU、SWIOTLB 耗尽、内核缺陷或极端内存压力有关。它和普通队列拥塞不同,调大发送队列通常不能解决映射失败。
把计数器与处理阶段对应起来
| 计数器/现象 | 所在阶段 | 优先检查 |
|---|---|---|
| linearize 次数高 | skb fragments 整理 | offload、封装、fragment 数量 |
linearize_failed 增长 | 内存合并失败 | 内存压力、碎片、slab |
dma_mapping_err 增长 | DMA 地址映射失败 | IOMMU、SWIOTLB、内核日志 |
| prepare Tx 失败 | 描述符/设备命令准备 | 队列状态、驱动与固件日志 |
| reset/keep-alive 计数增长 | 设备健康与恢复 | dmesg、实例底层事件、驱动版本 |
排障时用速率而不是累计值:
ethtool -S eth0 > /var/tmp/ena-stats.1
sleep 60
ethtool -S eth0 > /var/tmp/ena-stats.2
diff -u /var/tmp/ena-stats.1 /var/tmp/ena-stats.2实例启动以来出现过一个错误,与当前每秒持续增长,是完全不同的严重程度。
升级后的验收
安全升级不仅是 modinfo 显示新版本,还要完成:
- 实例重启后 ENA 自动加载;
- 主网卡、地址、路由和 DNS 恢复;
- SSM/SSH 可重新连接;
- 业务吞吐和延迟回到基线;
- reset、timeout、linearize_failed、dma_mapping_err 不再异常增长;
- DKMS 状态覆盖当前和计划中的内核版本。
如果热替换后 modprobe ena 失败,不要不断重试卸载加载。保留串口输出,先检查 vermagic、缺失符号和 initramfs,再决定回滚旧模块或从快照/AMI 恢复。
总结
ENA 升级是一次网络设备生命周期变更,必须按可能失联的操作设计。Tx 错误则要按数据路径分层:先看 skb 是否需要 linearize,再看内存合并是否失败,最后看 DMA mapping。只有把计数器放回源码阶段,才能避免把所有发送故障都归因于“驱动版本太旧”。
