记网口热插拔 + dhcp 几则

  • 热插拔网线,网卡/网桥 dhcp 自动更新…

  • 资料来源:

    https://www.debian.org/doc/manuals/debian-reference/ch05.zh-tw.html#_the_ifplugd_package
    https://forum.ubuntu.org.cn/viewtopic.php?t=366062
    https://unix.stackexchange.com/questions/503309/udev-network-cable-hotplug-event-not-catched

  • 更新

    1
    2
    21.01.11 初始化
    21.01.15 修正一个错误

导语

问题:

  • debian/ubuntu server 版网线热插拔 ip 死活不变..
  • 即使在 /etc/network/interface 配置了 allow-hotplug.

这个问题困扰了很久,一直没怎么在意,直到实验室的路由器被哪个幺儿(//就是我//)搞得不定期重启.非常棘手了..

allow-hotplug 坑

一直以来查阅和认定 allow-hotplug 的解释

  • 网口检测到热插拔后启动该接口
  • 拔掉网线重插也能重新进行 dhcp

但是为什么配置成 allow-hotplug,就是不能正常 dhcp 重新获取 ip 呢?

参考 Debian workaround 838871: dhcp network configuration without blocking boot proces

以上的理解是没错的,但是仅限 debian 引导启动时候..

又去翻了 debian 手册-网络设置, 带用户界面的 debian/ubuntu 一般都带 NetworkManager 或者 Wicd,有守护进程响应网口热插拔事件,但是 server 版没有这样一个守护进程,需要安装 ifplugd 实现.

一头撞在树下的猪旁边的石头上了…剩下的事情就顺理成章了…

ifplugd 网口热插拔

首先是 apt install ifplugd,安装 ifplugd.

当使用 ifplugd 接管网口热插拔时,需要注释掉 /etc/network/interfaces 对应网卡的 auto eth0allow-hotplug eth0 (这里以 eth0 为例),其他不动(前提是配置好了 dhcp 等).

dpkg-reconfigure ifplugd 设置需要监听的网卡.

  • 第一个页面设置的是非 usb/pcmcia 网卡,多个网卡使用空格隔开,eth0 eth1.
  • 第二个页面设置的是 usb/pcmcia 网卡,同样多个网卡使用空格隔开,wlan0 wlan1.
  • 第三四页面是,配置 ifplugd 的动作,建议去掉默认指令中的 -w,以免过长时间的等待,详细解释参考 ifplugd --help.
  • 第五六页面是,系统进入睡眠/暂停模式时 ifplugd 守护进程不动/暂停/停止.选不动作就好.

正常情况下,这样就能正常响应网口热插拔了.

网桥支持

ifplugd 只能支持硬件网卡的热插拔,不支持 linux bridge 等虚拟设备.到不是说完全不支持 linux bridge.

ifplugd 只能响应硬件网卡的插入/拔出,linux bridge + 桥接,可以响应网线拔出,移除 bridge,但是插入网线不能启动 linux bridge.

参考 令 ifplugd 支持网桥和弹出消息

把一个硬件网卡与一个 bridge 做一个映射,同时监听.在相应硬件网卡网口插入事件时,替换成 ifup bridge.

总体需要

  • 修改 ifplugd 的一个文件,解析映射.
  • 新建映射文件.
  • 配置 /etc/network/interface 下 bridge 和 网卡 pre-up 和 post-up.

配置网桥支持

ifplugd 的文件在 /etc/ifplugd/action.d/ifupdown,修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh
set -e

# 取结果 $1=xx
interface=$(sed -n "s/^$1=//p" "/var/run/ifplugd.map")
# 结果为空则取 $1
interface=${interface:-$1}

case "$2" in
up)
/sbin/ifup "$interface"
;;
down)
/sbin/ifdown "$interface"
;;
esac

在每次响应热插拔事件时,先从 /var/run/ifplugd.map 读取映射,映射不存在保持原值.

新建空白文件 /var/run/ifplugd.map,实际上每一个托管到 ifplugd 的硬件网口,在 /var/run/ 下都有对应的一个文件,表示网口对应守护进程的 pid.

这里假设 eth0 和 br0 绑定.

  • eth0

    • 首先要配置 eth0 dhcp,才能响应 eth0 的热插拔事件.
    • 如果要启动 eth0 而不是 br0,需要
      • down 掉 br0 -> pre-up
      • 清理掉 ifplugd.map 的映射 -> post-up
  • 最后 eth0 的配置

    1
    2
    3
    4
    5
    iface eth0 inet dhcp
    # down 掉 br0
    pre-up ifdown br0
    # 清理 eth0 映射
    post-up sed -i '/^eth0=/d' /var/run/ifplugd.map || true
  • br0

    • 开机要自动启动 br0
    • 启用 br0 前要,down 掉 eth0 -> pre-up
    • 启用后,要把映射 eth0=br0 写入 ifplugd.map -> post-up
  • 最后 br0 配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    auto br0
    iface br0 inet dhcp
    # 其他配置
    xxx
    pre-up ifdown eth0
    # 启用网卡后
    # 编辑文件 /var/run/ifplugd.map,所有 eth0= 行删除
    post-up sed -i '/^eth0=/d' /var/run/ifplugd.map || true
    # 追加 eth0=br0 到 ifplugd.map
    post-up echo 'eth0=br0' >>/var/run/ifplugd.map

最后 dpkg-reconfigure ifplugd 配置网卡监听 eth0 即可.相当于拦截了 eth0 up/down 对应的 br0.

结束语

难道要重新翻翻 debian 手册? 已经在翻了.