环境
-
设备:iStoreOS 24.10.7 x86_64(OpenWrt 主线)
-
CPU:x86,三张网卡
-
eth0:Intel I226-V(igc 原生驱动)
-
eth1:Realtek RTL8125B 2.5GbE ← 本文主角
-
eth2:Realtek RTL8168h
-
-
使用 OpenClash(mihomo)作为透明代理
现象
设备运行一段时间后代理就断连,重启恢复,但过一阵又断。YouTube / Google 打不开,BAIDU 正常(国内直连没断)。短则十几分钟,长则几小时,完全没有规律,极难复现。
排查过程
-
怀疑 OpenClash 配置问题 → 查看日志发现每次代理中断前都有
fw4 -q reload调用 -
确认 fw4 reload 会清掉 OpenClash 注入的 nft 规则 → 代理挂掉
-
谁在调 fw4 reload?→
/etc/hotplug.d/iface/20-firewall,任何接口 ifup 都会触发 -
哪个接口在反复 ifup?→ eth1(RTL8125B)间歇性 link down / up
-
为什么 eth1 闪断?→
/sys/class/net/eth1/carrier_changes持续增长,PCIe 错误计数增长,ethtool确认链路不稳定 -
查驱动 → eth1 和 eth2 都在用
r8169万能驱动
根因
Realtek RTL8125B 2.5GbE 网卡使用 r8169 通用驱动时存在兼容性问题:
-
PCIe Correctable Errors 持续累积
-
ASPM(省电)无法通过模块参数关闭
-
表现为物理链路间歇断开重连(闪断)
连锁反应链
r8169 驱动不兼容 RTL8125B
→ 物理闪断(link flap)
→ hotplug-call iface
→ 20-firewall → fw4 -q reload
→ OpenClash nft 规则被清
→ 透明代理中断 1~7 分钟
这里有一个更形象的比喻:
你租了一间房子(防火墙),房东(fw4)每次要换个灯泡(某个接口 ifup),就把整栋楼(整个 nft 规则集)拆了重建。住在里面的租户(OpenClash、PassWall 等第三方工具)刚装修好的房间(注入的规则)全部被推平,只能等房东重建完之后重新装修一次。
如果房东能做到"换个灯泡只拆那个房间"——也就是 fw4 支持只重载某一个 zone 而不是全量重建——那其他租户的房间就不会被反复牵连。
为什么重启能"暂时解决"
重启后 r8169 模块重新加载,链路重新建立,能撑一段时间。但 PCIe 错误累积到一定程度后再次触发闪断,整个过程重演。用户误以为是"稳定了一段时间",实际上是下一个故障周期的开始。
临时修复方案(用户侧)
-
换官方驱动:RTL8125B 用
r8125驱动,RTL8168 用r8168驱动,彻底卸载并黑名单r8169 -
拦截闪断 trigger(治标):添加
/etc/hotplug.d/iface/19-skip-lan1-firewall,让 eth1 闪断不触发 fw4 reload -
减少 reload 伤害(治标):将
20-firewall中的fw4 -q reload改为fw4 -q reload-sets,只刷新 nft 集合不动规则链
对官方的建议
iStoreOS / OpenWrt 在 x86 平台上默认启用 r8169 驱动覆盖绝大多数 Realtek 网卡,这个策略本身是合理的,但存在两个问题:
-
RTL8125B 2.5G 芯片在 r8169 下存在明显稳定性缺陷——这不是个例,国内外论坛均有类似反馈。r8169 是 in-kernel 驱动,迭代慢;r8125 是 Realtek 官方闭源驱动,对 2.5G 芯片支持更好。
-
fw4 -q reload 是全量重建 nft 规则集,不保护第三方注入的规则——OpenClash、PassWall 等代理工具都依赖在 fw4 的 nft 表中注入规则,一次 reload 全部清空。希望官方考虑:
-
在 fw4 中增加原子化的 zone 级重载能力(而不是
reload全量重建) -
或提供一个 hook 机制,在 reload 后自动回调第三方工具恢复规则
-
短期至少能让
fw4 -q reload不破坏已有第三方规则链
-
附:相关排查命令
# 查 carrier 变化
cat /sys/class/net/eth1/carrier_changes
# 查 PCIe 错误
cat /sys/bus/pci/devices/0000:01:00.0/ari_enabled 2>/dev/null
# (不同设备路径不同,用 lspci 确认)
# 查当前驱动
ethtool -i eth1 | grep driver
# 查 ASPM 状态
lspci -vvv -s 01:00.0 | grep ASPM