我在 Raspberry Pi 上运行 Alpine Linux,它基于 Busybox 和 musl。
当我运行时ifup eth0
,它也会udhcpc
在该界面的后台启动。这意味着,如果我运行时连接了以太网电缆ifup
,它会立即获取 IP 地址,如果未连接,它将在后台旋转,直到我连接它,然后它会收到 IP 地址。然而,这是一次性的事情。
如果它获得一个 IP 地址,然后我拔掉电缆,它会保留该 IP 地址,并且如果我尝试发出一些网络请求,例如ping google.com
,它会很高兴地尝试通过此接口执行此操作,直到超时。如果我有多个网络接口,这尤其是一个问题,在这种情况下,它将继续尝试使用第一个网络接口并忽略另一个可能有互联网连接的网络接口。
什么是合适的轻量级解决方案来检测电缆已断开连接或连接丢失并取消配置接口,然后在再次连接后重新配置它?
以防万一,这也是我的/etc/network/interfaces
文件
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
auto eth1
iface eth1 inet dhcp
答案1
在通常的系统上,该命令ip monitor link dev ethX
可用于事件驱动的方法,对载体状态的变化做出反应(例如:NO-CARRIER
)。
因为它不可用忙碌盒的最小实现,如我对 Q/A 的回答中所述ip link down 和物理链路缺失的区别, 这载体状态一个名为以太网也可在以下网址获取:
/sys/class/net/ethX/carrier
- 0表示无运营商,即
NO-CARRIER
接口上的标志 - 1 表示运营商
该值仅在接口启动后才可用(使用ip link set ethX up
),否则读取时会返回错误。这载体状态和操作状态在几乎所有设置中都是等效的(包括这种情况,请参阅前面的链接了解详细信息),因此更容易使用操作状态此时/sys/class/net/ethX/operstate
可以返回:
lowerlayerdown
对于无运营商(接口打开),up
对于承运人来说,down
当接口为行政上的向下。
因此,要替换ip monitor link dev ethX
一个,可以定期轮询/sys/class/net/ethX/operstate
以检索相同的信息,就像下面的 shell 函数一样,该函数大约每 2 秒轮询一次作为参数给出的接口,并且仅输出更改:
stateevent () {
local fileoperstate=/sys/class/net/"$1"/operstate
local operstate oldoperstate=$(cat "$fileoperstate")
while sleep 2; do
operstate=$(cat "$fileoperstate")
if [ "$oldoperstate" = "$operstate" ]; then
continue
fi
oldoperstate="$operstate"
echo "$operstate"
done
}
OP 的愿望是最终丢失断开连接的接口的路由,这样就不会超时,也不会与双宿主 RPi 发生冲突(有解决方案让两个默认网关在自己的路由表中分别处理,但它很复杂,尤其是在与 DHCP 集成,并且需要其自己的方法并且仍然需要处理载波丢失)。
从一些测试来看,丢失地址(也会丢失路由)比仅仅丢失路由更容易,或者这些路由(特别是内核的自动 LAN 路由)稍后可能无法正确恢复。这意味着在极少数情况下,RPi 是其自身的客户端,它不应连接到由 DHCP 设置的自己的地址,而应坚持使用例如在 RPi 上分配的地址。罗接口如 127.0.0.1 或添加到其中的任何其他地址。
忙碌盒' 内置有udhcpc
一个有用的功能可以轻松帮助完成这一切:
信号:
USR1
续租
USR2
解除租约
所以只要问跑步乌兹别克斯坦使用一个简单的信号来完成工作本身:release 将删除地址(由于接口已断开连接,因此无法通知 DHCP 服务器,但这不是问题),renew 会将其(和路由)添加回来。
这是一个事件循环函数,可以执行此操作,事件来自前一个函数的输出:
eventloop () {
local intf=$1
local state
while read -r state; do
case "$state" in
lowerlayerdown)
pkill -USR2 -f "(^|/)udhcpc( | .* )-i $intf( |$)"
;;
up)
pkill -USR1 -f "(^|/)udhcpc( | .* )-i $intf( |$)"
;;
down)
;;
esac
done
}
如果接口以管理方式关闭(即使只是使用 ),则无需执行任何操作ip link set eth0 down
:路由已被内核删除,并且 LAN 路由稍后将自行添加回来,由发送到的信号的默认路由完成乌兹别克斯坦一旦接口备份。
您可以有一个名为manageudhcpc.sh
(以通常的#!/bin/sh
, 开头)的 shell 脚本,包括上面的两个 shell 函数并以以下结尾:
stateevent "$1" | eventloop "$1"
并运行它两次(它永远不会返回,所以分叉它):
./manageudhcpc.sh eth0 &
./manageudhcpc.sh eth1 &
我把它留给OP:
- 集成此脚本进行启动
- 查看接口初始启动时要做什么,因为乌兹别克斯坦当它刚刚使用未连接的接口启动并等待其初始租约时,其行为可能会有所不同。
笔记:
- 在 Alpine 3.12 和 Alpine Edge LXC 容器上成功测试,并在两个网络上为 DHCP 设置了两个接口,
- 非常保守的扩展正则表达式用于找到正确的乌兹别克斯坦可能需要根据确切的 Alpine 版本进行更改(我必须在 3.12 和 Edge 之间更改它,以便它适用于两者)。它是pid文件可以用来代替。