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建议设为0
  • napi_defer_hard_irqs:延迟硬中断次数,建议2-4
  • dev_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-lowtx-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就够,别太小也别太大
  • 调优后一定要验证,别光凭感觉
网卡驱动调优知识体系 网卡驱动调优 NAPI轮询机制 关键参数 • gro_flush_timeout → 0 • napi_defer_hard_irqs → 2 • dev_weight → 16 中断节流 参数设置 • rx-usecs → 0 或 1 • tx-usecs → 0 或 1 • adaptive-rx → off DMA缓冲区 Ring Buffer大小 • RX → 128(推荐) • TX → 128(推荐) • 不低于64 芯片选型 延迟对比 • E1000 → ~50μs • IGB → ~20μs • IGC → ~10μs 验证调优效果 验证工具 • cyclictest → 系统抖动 • ethtool -S → 丢包统计 • 24小时通信测试

好了,这一章的内容就到这里。网卡驱动调优是个细活,每个参数背后都有它的物理意义。你动手调的时候,记得一次只改一个参数,然后观察效果。别像我刚开始那样,一口气改了一堆参数,出了问题都不知道是哪个引起的。

专注资料整理