☰
FreeBSD 双网卡自动故障转移:用 devd 实现实时路由切换
2026/10/8 10:39:40 网站建设 项目流程

FreeBSD 双网卡自动故障转移:用 devd 实现实时路由切换

场景:一台 FreeBSD 机器同时插了有线网卡(em0)和无线网卡(wlan0),都连同一个路由器。希望有线优先,无线备用,有线断了自动切无线,有线恢复了自动切回,全程无人值守。


一、问题背景

最开始遇到的问题是:双网卡都通过 DHCP 获取 IP,两个网卡都自动加了默认路由,导致系统出现两个默认路由:

default 192.168.0.1 UGS em0 default 192.168.0.1 UGS wlan0

这时候 FreeBSD 默认走 ECMP(等价多路径),轮流往两个网卡发包。但无线网卡有时候是no carrier状态(没连 WiFi),这时候就会出现:

  • DNS 解析时好时坏
  • NTP 一直报Name could not be resolved
  • 有时候 ping 外网通,有时候不通
  • 网络非常不稳定

二、方案选型对比

我先后试了几种方案,从差到好排一下:

❌ 方案 1:手动删路由

每次开机手动删 wlan0 的默认路由。

  • 缺点:重启就忘,治标不治本

⚠️ 方案 2:cron 每分钟轮询

写个脚本每分钟跑一次,检查 em0 是否 active,如果 active 就删掉 wlan0 的默认路由。

  • 缺点:响应慢,最坏情况要等 1 分钟才切换;一直空跑浪费资源

✅ 方案 3:devd 事件驱动(最终方案)

利用 FreeBSD 自带的devd守护进程,监听网卡 link up/down 事件,网卡状态一变就立即触发脚本。

  • 优点:秒级实时响应,不用轮询,系统原生支持,稳定可靠

三、最终实现方案

3.1 整体思路

┌─────────────┐ link up/down ┌─────────────┐ │ em0 有线 │ ────────────────────> │ │ └─────────────┘ │ │ │ devd │ ──> 触发 route-failover 脚本 ┌─────────────┐ link up/down │ 事件守护 │ │ wlan0 无线 │ ────────────────────> │ │ └─────────────┘ └─────────────┘

脚本逻辑非常简单:

  • 如果 em0 是 active 状态 → 删掉 wlan0 的默认路由(只走有线)
  • 如果 em0 是 down 状态 → 什么都不做(让 wlan0 的 DHCP 默认路由生效)

💡 为什么不用手动加路由?因为两个网卡都是 DHCP,当 wlan0 连上 WiFi 时,DHCP 客户端会自动帮我们加好默认路由。我们只需要在有线正常的时候把它删掉就行。


3.2 第一步:写路由切换脚本

创建脚本/usr/local/sbin/route-failover:

#!/bin/sh# 双网卡自动故障转移 - 有线em0优先,无线wlan0备用# 由 devd 事件触发,网卡状态变化时自动执行# 检查 em0 是否连接正常em0_active=$(ifconfigem0|grep-c"status: active")if["$em0_active"-gt0];then# 有线正常,删除 wlan0 的默认路由(如果存在)route delete default-interfacewlan02>/dev/nullelse# 有线断了,不处理,让 wlan0 的 DHCP 默认路由生效:fi

加执行权限:

chmod+x /usr/local/sbin/route-failover

3.3 第二步:配置 devd 事件监听

创建 devd 配置文件/usr/local/etc/devd/route-failover.conf:

# 网卡 link 事件触发路由切换 # 监听 em0 有线网卡 notify 100 { match "system" "IFNET"; match "subsystem" "em0"; action /usr/local/sbin/route-failover; }; # 监听 wlan0 无线网卡 notify 100 { match "system" "IFNET"; match "subsystem" "wlan0"; action /usr/local/sbin/route-failover; };

重启 devd 让配置生效:

servicedevd restart

四、工作原理详解

4.1 devd 是什么?

devd是 FreeBSD 自带的设备事件守护进程,开机就运行。当系统硬件状态发生变化时(比如插U盘、插网线、WiFi连接),内核会发出事件,devd 收到事件后根据配置执行对应的 action。

我们这里监听的是IFNET(网络接口)类事件,当 em0 或 wlan0 的 link 状态变化时(up/down),就自动执行我们的路由脚本。

4.2 为什么这样设计最稳?

  • 不用手动加路由:两个网卡都用 DHCP,IP 和网关都自动获取,我们只需要管默认路由的去留
  • 有线优先:只要有线插着,就强制走有线,无线只做备用
  • 自动切回:有线一恢复,脚本立刻删掉无线路由,自动切回有线
  • 无状态:脚本不需要记录当前走哪个网卡,每次都根据 em0 实际状态判断,简单可靠

五、验证效果

5.1 正常状态(有线 + 无线都连着)

$netstat-rn-finet|grepdefault default192.168.0.1 UGS em0

✅ 只有一个默认路由,走有线 em0

5.2 拔掉网线

# 拔网线瞬间,devd 自动触发脚本$netstat-rn-finet|grepdefault default192.168.0.1 UGS wlan0

✅ 自动切到无线 wlan0,网络不断

5.3 插回网线

# 插网线瞬间,devd 自动触发脚本$netstat-rn-finet|grepdefault default192.168.0.1 UGS em0

✅ 自动切回有线 em0


六、注意事项

  1. 网卡名要对应:配置文件里的em0和wlan0要和你实际的网卡名一致,用ifconfig查看
  2. 网关地址:脚本里没写死网关,因为我们只是删除路由,添加路由是 DHCP 自动做的,所以网关变了也不用改脚本
  3. 为什么不用负载均衡?:两个网卡连同一个路由器,出口是同一个公网 IP。负载均衡不仅没意义,还可能因为同一个连接的包走不同路径导致连接断开,主备模式是最稳定的选择
  4. 切换时间:devd 事件触发是毫秒级的,几乎感觉不到断网

七、总结

这个方案的优点:

  • ✅实时响应:网卡状态一变就切,不用等
  • ✅系统原生:用的都是 FreeBSD 自带功能,没装额外软件
  • ✅简单可靠:脚本只有几行,逻辑清晰,不容易出 bug
  • ✅开机自启:devd 是系统服务,重启后自动生效

如果你的 FreeBSD 机器也有双网卡的需求,强烈推荐用 devd 事件驱动的方式,比 cron 轮询优雅太多了。


作者:小浣熊运维笔记
平台:FreeBSD 15.1-STABLE
环境:有线 em0 + 无线 wlan0,同一路由器

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询