4. 实时网卡驱动调优:IGB/IGC/E1000驱动参数优化,NAPI轮询与中断节流
网卡驱动调优,说白了就是让数据包从网线到应用层的路走得更快、更稳。我做了这么多年EtherCAT主站,发现很多人把精力都放在应用层代码上,却忽略了网卡驱动这个"第一公里"。你想想看,数据从物理层进来,第一关就是驱动,这里要是堵了,后面再怎么优化也是白搭。
这一章,我就把IGB、IGC、E1000这三款常用网卡的调优经验掰开揉碎了讲。这三款芯片我都踩过坑,尤其是IGB,我在一个高速运动控制项目里被它折腾了整整两周——后来发现就是一个中断节流参数没调对。
4.1 三款网卡芯片的选型差异
先说说这三款芯片的区别。E1000是Intel的老将,千兆级别,适合做原型验证。IGB是E1000的继任者,性能更好,支持多队列。IGC则是针对I210/I211这些新芯片的驱动,延迟更低。
| 芯片 | 驱动 | 典型延迟 | 适用场景 |
|---|---|---|---|
| 82574/82576 | E1000 | ~50μs | 原型验证、低负载 |
| I210/I350 | IGB | ~20μs | 工业现场、中等负载 |
| I225/I226 | IGC | ~10μs | 高性能EtherCAT、2.5G |
我个人习惯,新项目直接上IGC驱动的芯片。虽然贵一点,但省下来的调优时间,折算成工时成本其实更划算。
4.2 NAPI轮询机制与参数调优
NAPI是Linux网络子系统的核心机制。它的思路很简单:中断来了,先别急着处理,而是切换到轮询模式,一口气把数据收完。这样能避免中断风暴。
但这里有个坑——NAPI的权重参数weight。这个值决定了每次轮询最多收多少个包。默认是64,对于EtherCAT来说太大了。
核心参数:
gro_flush_timeout:GRO合并超时,EtherCAT建议设为0napi_defer_hard_irqs:延迟硬中断次数,建议2-4dev_weight:全局NAPI权重,建议16-32
我曾经在一个项目中,默认的weight=64导致EtherCAT帧处理抖动达到200μs。后来改成16,抖动直接降到30μs以内。为什么会这样?因为EtherCAT的帧很小,64个包要攒很久,反而增加了延迟。
# 调整NAPI权重
echo 16 > /sys/class/net/eth0/gro_flush_timeout
echo 2 > /sys/class/net/eth0/napi_defer_hard_irqs
echo 16 > /sys/class/net/eth0/dev_weight
4.3 中断节流(Interrupt Throttling)
中断节流,说白了就是让网卡别那么"勤快"。每来一个包就中断一次,CPU就光顾着响应中断了,啥也干不了。
IGB驱动里有个参数叫InterruptThrottleRate,单位是微秒。默认是自适应模式,但对于EtherCAT,我建议直接设成固定值。
我的经验值:
对于1kHz的EtherCAT周期,InterruptThrottleRate设成0(关闭节流)或者1μs。对于4kHz以上,设成0。别担心中断太多,EtherCAT的帧率是固定的,不会产生中断风暴。
# 关闭中断节流(IGB)
ethtool -C eth0 rx-usecs 0 tx-usecs 0
# 或者设置固定值
ethtool -C eth0 rx-usecs 1 tx-usecs 1 adaptive-rx off adaptive-tx off
嗯,这里要注意。IGC驱动的参数名不一样,叫rx-usecs-low和tx-usecs-low。我第一次调IGC的时候,照着IGB的文档改了半天没反应,后来才发现参数名变了。
# IGC驱动的中断节流
ethtool -C eth0 rx-usecs-low 0 tx-usecs-low 0
4.4 DMA缓冲区大小调整
DMA缓冲区,就是网卡和内存之间的"中转站"。缓冲区太小,容易丢包;太大,延迟又高。EtherCAT的帧很小,一般不超过1500字节,所以缓冲区不需要太大。
我建议把RX缓冲区描述符数量从默认的256降到64或128。这样每个描述符占用的内存更少,CPU缓存命中率更高。
# 查看当前ring buffer大小
ethtool -g eth0
# 调整ring buffer(IGB/IGC)
ethtool -G eth0 rx 128 tx 128
# E1000驱动
ethtool -G eth0 rx 64 tx 64
避坑指南:
我曾经把RX缓冲区设成32,结果在高负载下出现了丢包。后来发现是DMA缓冲区太小,网卡来不及把数据搬走就被覆盖了。建议不要低于64,除非你确定帧率很低。
4.5 综合调优脚本
下面是我在实际项目中用的调优脚本,针对IGB驱动做了优化。你可以根据自己的硬件微调。
#!/bin/bash
# EtherCAT网卡驱动调优脚本
# 适用于IGB/IGC/E1000
IFACE=eth0
# 1. 关闭中断节流
ethtool -C $IFACE rx-usecs 0 tx-usecs 0 adaptive-rx off adaptive-tx off
# 2. 调整ring buffer
ethtool -G $IFACE rx 128 tx 128
# 3. NAPI参数
echo 0 > /sys/class/net/$IFACE/gro_flush_timeout
echo 2 > /sys/class/net/$IFACE/napi_defer_hard_irqs
echo 16 > /sys/class/net/$IFACE/dev_weight
# 4. 关闭硬件卸载(EtherCAT不需要)
ethtool -K $IFACE gro off gso off tso off
# 5. 设置中断亲和性(绑定到隔离的CPU核心)
echo 2 > /proc/irq/$(cat /sys/class/net/$IFACE/device/irq)/smp_affinity
echo "网卡调优完成"
4.6 验证调优效果
调优之后,怎么知道效果好不好?我一般用两个工具:cyclictest测系统抖动,ethtool -S看网卡统计信息。
# 查看网卡统计
ethtool -S eth0 | grep -E "rx_packets|tx_packets|rx_dropped|tx_dropped"
# 重点关注
# rx_dropped: 如果非零,说明DMA缓冲区太小
# rx_overruns: 如果非零,说明中断节流太激进
我个人习惯,调优后跑24小时的EtherCAT通信测试,看看有没有丢帧或者延迟抖动。如果一切正常,再把这个配置固化到启动脚本里。
核心要点总结:
- IGC驱动延迟最低,适合高性能EtherCAT
- NAPI权重设16-32,不要用默认的64
- 中断节流直接关闭或设1μs
- DMA缓冲区128就够,别太小也别太大
- 调优后一定要验证,别光凭感觉
好了,这一章的内容就到这里。网卡驱动调优是个细活,每个参数背后都有它的物理意义。你动手调的时候,记得一次只改一个参数,然后观察效果。别像我刚开始那样,一口气改了一堆参数,出了问题都不知道是哪个引起的。