1. 工业现场双网卡路由冲突的典型症状与根因定位
1.1 一个让人抓狂的现场故障
去年冬天,一个做机器视觉的朋友半夜给我打电话,说他们产线上的工控机出了个邪门问题:设备同时插着有线网卡和无线网卡,有线接的是厂内PLC和相机的内网,无线连的是车间办公网。结果每次重启之后,访问外网时好时坏,有时候能ping通网关,有时候直接超时,更离谱的是连内网的相机都偶尔掉线。他一开始怀疑是网线接触不良,换了三根线、两个交换机端口,问题依旧。后来怀疑无线驱动,重装了两次系统,还是老样子。
这种场景在工业计算机上太常见了。工控机、边缘计算盒子、AGV小车控制器、视觉检测主机,几乎都是“有线+无线”双网卡并存的配置。有线负责低延迟、高可靠的设备通信,无线负责远程运维、数据上云或者调试。听起来很美好,但Linux内核的路由表只有一个默认网关,两张网卡同时存在时,谁抢到默认路由,流量就走谁。如果两张网卡都通过DHCP拿到了网关地址,那系统里就会出现两条默认路由,内核按Metric值小的优先。问题是,很多发行版默认给有线网卡的Metric是100,无线是600,看起来有线优先,但实际部署中经常反过来,或者两条路由的Metric一样,导致内核随机选一条,表现就是“时好时坏”。
我后来远程连上去看了一眼ip route show,果然两条default路由,一条走eth0,一条走wlan0,Metric都是100。内核在等价路由之间做哈希,每次新建连接可能走不同的网卡,内网流量被错误地扔到无线网卡上,外网流量又可能被扔到没有外网出口的有线网卡上。这就是典型的双网卡路由优先级冲突。
1.2 为什么传统ifconfig和route搞不定
很多从CentOS 6或者Ubuntu 14.04时代过来的运维,第一反应是改/etc/network/interfaces或者写/etc/sysconfig/network-scripts/route-eth0。但在现代Linux发行版上,网络管理栈已经换了好几代。Ubuntu 18.04之后默认用Netplan,底层可以是systemd-networkd或者NetworkManager;Debian 10之后systemd-networkd逐渐成为服务器和工控场景的主流;RHEL 8/9虽然默认NetworkManager,但很多工业客户为了精简系统,会手动切到systemd-networkd。
systemd-networkd的好处是轻量、启动快、配置统一,特别适合无头工控机。但它有个特点:路由Metric的配置方式和传统工具完全不同。你不能再写up ip route add default via ... metric 100这种脚本,而是要在.network文件里用[Route]段或者GatewayOnLink、Metric这些关键字。很多人不知道这个区别,照着网上的老教程改,结果配置根本不生效,重启后路由又乱了。
更麻烦的是,无线网卡在systemd-networkd下的行为和有线的差异很大。有线网卡通常由.network文件静态匹配,无线网卡如果走wpa_supplicant,可能由wpa_supplicant@wlan0.service管理,DHCP客户端拿到的路由Metric默认是600,但如果你在.network里没显式指定,systemd-networkd可能会给它一个默认值,导致和有线网卡的Metric打架。
1.3 根因拆解:内核路由决策的底层逻辑
要彻底解决这个问题,得先搞清楚Linux内核怎么选路。内核维护一张路由表(main表),每条路由有一个Metric(也叫跳数)。当有多个匹配目标地址的路由时,内核选Metric最小的。如果Metric相同,就进入等价多路径(ECMP)模式,按哈希分流。对于默认路由(0.0.0.0/0),如果两条路由Metric相同,内核会轮流用,或者根据源地址哈希,表现就是“一会儿走有线,一会儿走无线”。
工业场景的需求通常是:
- 内网设备(PLC、相机、机器人)必须走有线,因为无线延迟抖动大,丢包率高。
- 外网或办公网流量走无线,因为有线网络通常是隔离的,没有外网出口。
- 如果无线断开,系统不能完全失联,至少要有线还能通内网。
所以正确的路由策略应该是:有线网卡的默认路由Metric设小(比如100),无线网卡的默认路由Metric设大(比如600),并且确保内网网段的路由只走有线。这样内核优先选有线作为默认出口,但如果有线没有外网,流量会走有线然后被丢弃——所以还需要更精细的策略路由,或者干脆不给有线配默认网关,只配内网静态路由。
但很多工控机的有线网卡是通过DHCP拿地址的,DHCP服务器会下发默认网关,你没法控制。这时候就得在systemd-networkd里用UseRoutes=false或者Metric=来覆盖DHCP下发的路由。
2. systemd-networkd配置体系与Metric参数深度解析
2.1 systemd-networkd的文件结构与匹配逻辑
systemd-networkd的配置分三个层次:.netdev文件创建虚拟设备,.network文件匹配物理设备并配置网络,.link文件配置底层链路参数。对于双网卡路由优先级,核心是.network文件。
.network文件的匹配规则是按文件名排序,第一个匹配上的生效。比如10-eth0.network和20-wlan0.network,系统会先读10,再读20。匹配条件用[Match]段,可以按网卡名、MAC地址、驱动类型、PCI路径等匹配。工业现场建议用MAC地址匹配,因为网卡名可能因为内核枚举顺序变化而改变,比如enp3s0变成enp4s0。
一个典型的.network文件长这样:
[Match] MACAddress=00:1b:21:3c:4d:5e [Network] DHCP=ipv4 LinkLocalAddressing=no IPv6AcceptRA=no [DHCPv4] UseRoutes=false [Route] Destination=192.168.1.0/24 Gateway=192.168.1.1 Metric=100这里的关键是[DHCPv4]段的UseRoutes=false,它告诉systemd-networkd不要安装DHCP下发的默认路由。然后手动在[Route]段里加内网静态路由,Metric设小。这样有线网卡只负责内网,不会抢默认路由。
无线网卡的配置类似,但通常需要保留DHCP下发的默认路由,因为无线是外网出口。可以这样写:
[Match] MACAddress=aa:bb:cc:dd:ee:ff [Network] DHCP=ipv4 [DHCPv4] UseRoutes=true RouteMetric=600RouteMetric=600是systemd-networkd 244版本之后支持的参数,直接覆盖DHCP下发的默认路由Metric。如果你的系统版本较老,可能需要在[Route]段手动加默认路由,或者用Metric=在[Network]段全局设置。
2.2 Metric值的计算与选择依据
Metric值不是随便填的,它影响内核选路的优先级。数值越小优先级越高。常见的默认值:
- 有线DHCP:100
- 无线DHCP:600
- 静态路由:通常不设,默认0
工业场景建议:
- 有线内网静态路由:Metric 50-100
- 有线默认路由(如果有外网):Metric 100
- 无线默认路由:Metric 600
- 备用4G/5G路由:Metric 700
为什么无线要设600而不是200?因为无线链路的稳定性远不如有线,即使信号满格,延迟也可能突然飙升。把Metric设大,确保只要有线可用,默认流量就不走无线。600这个值是systemd-networkd的默认无线Metric,沿用它可以减少和其他服务的冲突。
如果两张网卡都需要默认路由,但希望有线优先,可以设:
- 有线默认路由Metric=100
- 无线默认路由Metric=600
这样内核优先选有线。但有线如果没有外网出口,流量会走有线然后被防火墙丢弃,不会自动切到无线。要实现自动切换,需要更复杂的策略路由或者用ip rule配合ip route,但工业场景通常不需要自动切换,因为网络拓扑是固定的。
2.3 策略路由与多表路由的进阶用法
如果需求更复杂,比如“内网走有线,外网走无线,但无线断开时外网走有线”,那就得用策略路由。Linux支持多张路由表,默认有local、main、default三张。可以创建自定义表,比如table 100给有线,table 200给无线。
配置方法是在.network文件里用[RoutingPolicyRule]段:
[RoutingPolicyRule] From=192.168.1.0/24 Table=100 Priority=1000然后在[Route]段指定Table=100。这样源地址是内网网段的流量会查table 100,走有线。其他流量查main表,走无线。
但策略路由的配置复杂度高,容易出错。工业现场如果只是简单的“内网有线、外网无线”,用Metric覆盖就够了。策略路由适合有多个内网网段、需要精细控制的场景。
3. 双网卡Metric配置的完整实操流程
3.1 环境确认与网卡识别
第一步永远是确认系统版本和网络管理栈。执行:
systemctl status systemd-networkd networkctl status ip link show如果systemd-networkd是active,说明它在管理网络。如果同时有NetworkManager在跑,可能会冲突,建议禁用其中一个:
systemctl disable --now NetworkManager systemctl enable --now systemd-networkd然后识别网卡名和MAC地址:
ip -br link show输出类似:
lo UNKNOWN 00:00:00:00:00:00 enp3s0 UP 00:1b:21:3c:4d:5e wlp2s0 UP aa:bb:cc:dd:ee:ff记下MAC地址,后面配置用MAC匹配更可靠。
3.2 有线网卡配置:只走内网,不抢默认路由
创建/etc/systemd/network/10-wired.network:
[Match] MACAddress=00:1b:21:3c:4d:5e [Network] DHCP=ipv4 LinkLocalAddressing=no IPv6AcceptRA=no LLMNR=no [DHCPv4] UseRoutes=false UseDNS=false [Route] Destination=192.168.1.0/24 Gateway=192.168.1.1 Metric=100这里UseRoutes=false是关键,它阻止DHCP下发的默认路由进入内核。UseDNS=false是因为内网DNS通常不需要,避免DNS查询走有线导致解析慢。然后手动加内网静态路由,Metric=100。
如果内网有多个网段,比如192.168.1.0/24和192.168.2.0/24,就加多个[Route]段。
3.3 无线网卡配置:作为默认出口,Metric设大
创建/etc/systemd/network/20-wireless.network:
[Match] MACAddress=aa:bb:cc:dd:ee:ff [Network] DHCP=ipv4 LinkLocalAddressing=no IPv6AcceptRA=no [DHCPv4] UseRoutes=true RouteMetric=600 UseDNS=trueRouteMetric=600确保无线默认路由的Metric是600,低于有线的100优先级。UseDNS=true让无线下发的DNS生效,用于外网域名解析。
如果系统版本不支持RouteMetric,可以改成手动加默认路由:
[Route] Destination=0.0.0.0/0 Gateway=192.168.100.1 Metric=600但网关地址得写死,不如DHCP灵活。
3.4 重启服务与路由验证
配置完成后,重启systemd-networkd:
systemctl restart systemd-networkd然后检查路由表:
ip route show期望输出:
default via 192.168.100.1 dev wlp2s0 proto dhcp src 192.168.100.50 metric 600 192.168.1.0/24 via 192.168.1.1 dev enp3s0 proto static metric 100 192.168.1.0/24 dev enp3s0 proto kernel scope link src 192.168.1.10 metric 100 192.168.100.0/24 dev wlp2s0 proto kernel scope link src 192.168.100.50 metric 600注意默认路由只有一条,走无线,Metric 600。内网路由走有线,Metric 100。这样内网流量走有线,外网流量走无线,互不干扰。
再验证一下:
ping -c 3 192.168.1.100 # 内网设备,应该走有线 ping -c 3 8.8.8.8 # 外网,应该走无线 traceroute 8.8.8.8 # 确认第一跳是无线网关如果内网ping不通,检查有线网卡的IP和路由是否正确。如果外网ping不通,检查无线网关和DNS。
3.5 持久化与开机自启验证
systemd-networkd的配置是持久的,重启后自动生效。但建议做一次完整重启测试:
reboot重启后再次检查ip route show,确认路由表符合预期。如果发现路由又乱了,可能是其他服务在干扰,比如dhclient或者NetworkManager残留。用systemctl list-units | grep -i network排查。
另外,工业现场经常有断电重启的情况,建议在/etc/systemd/network/下加一个99-default.link文件,统一设置网卡命名策略,避免网卡名变化导致匹配失败:
[Match] OriginalName=* [Link] NamePolicy=mac MACAddressPolicy=persistent这样网卡名会基于MAC地址生成,重启后不会变。
4. 常见故障排查与避坑经验实录
4.1 路由表里出现两条默认路由怎么办
这是最常见的症状。原因通常是DHCP下发的路由没被抑制。检查.network文件里有没有UseRoutes=false,或者RouteMetric是否生效。如果配置没问题,但路由还在,可能是systemd-networkd版本太老,不支持这些参数。用systemd --version查看版本,低于244的建议升级,或者改用[Route]段手动覆盖。
另一个可能是无线网卡的wpa_supplicant在DHCP之后又加了一条路由。检查/etc/wpa_supplicant/wpa_supplicant.conf里有没有update_config=1,这个选项会让wpa_supplicant修改网络配置,建议关掉。
4.2 内网流量被错误地路由到无线网卡
如果ip route show里内网网段的路由指向了无线网卡,说明有线的静态路由没生效。检查[Route]段的Destination和Gateway是否正确,Metric是否比无线的小。另外,如果内网网段和无线网段有重叠,比如都是192.168.1.0/24,那内核会优先选直连路由,导致冲突。工业现场一定要规划好网段,有线内网和无线外网用不同的私有网段。
4.3 无线断开后系统完全失联
如果无线是唯一的默认出口,无线一断,外网就没了。但内网应该还能通。如果内网也不通,说明有线的静态路由没配好,或者有线网卡的IP丢了。建议在.network文件里加ConfigureWithoutCarrier=yes,这样即使网线没插,网卡也会保留IP配置,方便调试。
另外,可以配一个备用路由,比如用4G模块,Metric设700,无线断了自动切4G。但工业场景通常不需要,因为产线网络是固定的。
4.4 排查工具与命令速查表
| 问题现象 | 排查命令 | 可能原因 | 解决方法 |
|---|---|---|---|
| 两条默认路由 | ip route show | DHCP路由未抑制 | 加UseRoutes=false或RouteMetric |
| 内网走无线 | ip route get 192.168.1.100 | 静态路由Metric太大 | 调小有线Metric |
| 外网走有线 | ip route get 8.8.8.8 | 有线默认路由Metric太小 | 调大有线Metric或删默认路由 |
| 无线断开失联 | networkctl status | 有线无IP | 检查DHCP和ConfigureWithoutCarrier |
| 配置不生效 | journalctl -u systemd-networkd | 文件权限或语法错误 | 检查chmod 644和networkctl reload |
注意:修改
.network文件后,一定要执行networkctl reload再networkctl reconfigure <网卡名>,或者直接重启systemd-networkd。只改文件不重载,配置不会生效。
4.5 几个只有踩过坑才知道的细节
第一个坑:[DHCPv4]段的RouteMetric参数在systemd 244之前叫Metric,而且只在[Network]段生效。如果你照着新文档写,在老系统上会报错。建议先查版本,再决定用哪个参数。
第二个坑:无线网卡的.network文件如果和wpa_supplicant的配置冲突,比如wpa_supplicant自己加了默认路由,那systemd-networkd的Metric会被覆盖。解决办法是在wpa_supplicant配置里加update_config=0,禁止它修改网络。
第三个坑:工业现场经常用USB无线网卡,这种网卡的MAC地址可能每次重启都变。用MAC匹配会失效。建议用[Match]的Path或者Driver匹配,比如Driver=rtl8192cu,或者用OriginalName=wlan*。
第四个坑:如果系统里同时有systemd-networkd和dhclient在跑,dhclient会偷偷加路由。检查ps aux | grep dhclient,如果有,禁用对应的服务。
5. 工业场景下的扩展配置与长期维护建议
5.1 多网卡多网段的策略路由模板
如果工控机有三张网卡:有线内网、无线外网、4G备用,可以这样配:
有线(内网):
[Match] MACAddress=00:1b:21:3c:4d:5e [Network] DHCP=ipv4 [DHCPv4] UseRoutes=false [Route] Destination=192.168.1.0/24 Gateway=192.168.1.1 Metric=100无线(外网):
[Match] MACAddress=aa:bb:cc:dd:ee:ff [Network] DHCP=ipv4 [DHCPv4] UseRoutes=true RouteMetric=6004G(备用):
[Match] MACAddress=11:22:33:44:55:66 [Network] DHCP=ipv4 [DHCPv4] UseRoutes=true RouteMetric=700这样优先级:有线内网 > 无线外网 > 4G备用。无线断了,4G自动接管默认路由。
5.2 配置文件的版本管理与备份
工业现场的配置一旦调好,就不应该随便动。建议把/etc/systemd/network/整个目录用git管理,或者至少打个tar包备份。每次修改前先cp -r /etc/systemd/network /etc/systemd/network.bak,出问题可以快速回滚。
另外,.network文件的权限必须是644,属主root。如果权限不对,systemd-networkd会忽略它。用chmod 644 /etc/systemd/network/*.network统一设置。
5.3 远程维护时的安全注意事项
工业现场通常没有显示器,全靠SSH远程。如果路由配错,SSH可能断连。建议在修改网络配置前,先开一个screen或者tmux会话,或者用at命令定时回滚:
echo "cp /etc/systemd/network.bak/* /etc/systemd/network/ && systemctl restart systemd-networkd" | at now + 5 minutes这样5分钟后如果没取消,配置自动回滚。确认新配置没问题后,用atrm删掉定时任务。
5.4 长期运行中的Metric漂移问题
有些工控机运行几个月后,路由Metric会莫名其妙变化。这通常是因为DHCP租约续期时,systemd-networkd重新应用了路由,但Metric没保持。解决办法是在.network文件里显式写死RouteMetric,并且加[DHCPv4]的UseRoutes=true,让每次续期都按配置来。
另外,如果无线信号弱,wpa_supplicant可能会频繁重连,每次重连都会重新DHCP,导致路由表抖动。建议在/etc/systemd/network/20-wireless.network里加[Network]的DHCP=ipv4和[DHCPv4]的RouteMetric=600,并且用wpa_supplicant的bgscan参数优化漫游。
5.5 从Metric到策略路由的演进路径
如果现场需求从“内网有线、外网无线”升级到“多个内网网段走不同网卡”,那就得用策略路由。比如:
- 192.168.1.0/24 走有线1
- 192.168.2.0/24 走有线2
- 其他走无线
配置方法是在.network文件里加[RoutingPolicyRule]:
[RoutingPolicyRule] From=192.168.1.0/24 Table=100 Priority=1000 [Route] Destination=192.168.1.0/24 Gateway=192.168.1.1 Table=100 Metric=100然后创建/etc/iproute2/rt_tables里的自定义表:
100 wired1 200 wired2这种配置复杂度高,建议先在测试环境验证,再上产线。
5.6 一个真实的产线案例复盘
去年那个朋友的产线,最后是怎么解决的?我远程连上去,发现他的系统是Ubuntu 20.04,systemd 245,NetworkManager和systemd-networkd都在跑。NetworkManager给无线加了默认路由Metric 600,systemd-networkd给有线加了默认路由Metric 100,但有线没有外网,所以外网流量走有线被丢弃。同时,内网流量因为两条默认路由等价,有时候走无线,导致相机掉线。
解决步骤:
- 禁用NetworkManager:
systemctl disable --now NetworkManager - 确认systemd-networkd接管:
systemctl enable --now systemd-networkd - 写有线
.network文件,UseRoutes=false,加内网静态路由Metric 100 - 写无线
.network文件,RouteMetric=600 - 重启,验证路由表
- 加
at定时回滚,确认稳定后取消
前后花了不到20分钟,问题彻底解决。后来他产线跑了半年,没再出过网络问题。
这个案例说明,双网卡路由冲突不是玄学,就是Metric没配对。只要理解了内核选路逻辑,用systemd-networkd的配置覆盖DHCP默认行为,就能稳稳搞定。工业现场的网络配置,稳定比灵活重要,宁可手动写死路由,也不要依赖DHCP的自动下发。