无线 bonding
支持可移除设备的网络接口 Bonding
Linux bonding 驱动程序提供了一种将多个网络接口聚合到单个逻辑“bonded”接口的方法。
Linux Ethernet Bonding 驱动程序 HOWTO
Linux 内核 bonding 驱动程序可用于提供并行的网络连接以最大化吞吐量,或允许冗余网络连接以最大化网络可用性。 这是一个使用内核 bonding 驱动程序最大化可用性的示例,通过允许网络连接在主网络设备和任意数量的辅助设备之间“故障转移”,或者,通过选择可用的最高速度连接。 此方法使用仅内核 bonding 模块的“active-backup”模式、sysfs、iproute2 命令和 systemd “模板”单元文件,不使用 systemd-networkd,提供支持可移除设备的自动有线和无线网络配置。
此示例将在任何接口上根据需要连续运行 wpa_supplicant,并在虚拟“bond0”接口上运行 DHCP 客户端。 这对于例如便携式计算机非常有用,当您希望在有线接口可用时使用它来获得速度和/或安全性,而在有线接口不可用时使用无线接口。 基本思想是拥有两个“始终活动”的有线和无线接口,然后将它们“bonding”或“slave”到一个虚拟接口“master”,然后让内核 bonding 模块处理接口之间的切换。 当然,此方案可以应用于任何其他类型的网络接口,并扩展到两个以上的物理或虚拟网络接口。
请注意,主机网络直接使用 systemd 管理,并且此处未使用任何其他“连接管理器”,从而提供了一种更基本的方法。 但是,wpa_supplicant 本身仍然可以使用 wpa_supplicant_guiAUR 中的 wpa_gui
直接管理,以扫描、选择和连接到新的无线接入点/基站。
在此示例中,使用了六个 systemd 服务单元文件,以及五个相关的配置文件,用于 内核 bonding 模块、wpa_supplicant、dhclient 以及静态网络配置和指定主从网络接口名称。 这六个单元文件本质上是通用的服务单元文件,不包含配置数据,并且不需要修改。 各种服务单元可以单独停止、启动和重启,而不会出现排序错误或失败状态。 任何网络接口设备,例如典型的有线或无线 PC 卡,都可以移除和更换,并且重新配置将是自动的。
DHCP 配置
/etc/dhclient.conf
# These time-outs are aggressively short, supposing a sparsely populated network. initial-interval 2; reboot 5; timeout 10; retry 20; # RFC 4361 Node-specific Identifiers for DHCPv4 February 2006 send dhcp-client-identifier 00:02:00:02:2e:2d:01:bd:c3:92:9a:44:2a:c4 ; send host-name "laptop";
如果您还运行 DHCPv6 客户端,请确保 DHCP 客户端标识符和 DHCPv6 客户端标识符是相同的 DUID。 DHCP 服务器,例如 dnsmasq,可以配置为根据多个 MAC 地址或提供的主机名或提供的客户端标识符给出固定的 IP 地址。
/etc/systemd/system/dhclient@.service
[Unit] Description= ISC dhclient on interface %I Documentation= man:dhclient(8) man:dhclient.conf(5) Wants= network.target Before= network.target After= network-pre.target BindsTo= sys-subsystem-net-devices-%i.device [Service] ExecStartPre= /usr/bin/sleep 8 ExecStart= /usr/bin/dhclient -d -pf /run/dhclient-%i -i %I # Release the current lease and ensure that dhclient has actually stopped. ExecStop= /usr/bin/dhclient -r -pf /run/dhclient-%i ExecStop= /usr/bin/sleep 1 Restart= on-abnormal [Install] WantedBy= sys-subsystem-net-devices-%i.device
有一个特殊的问题需要解决。 当启动内核 bonding 时,唯一工作接口是非主从接口 - 例如,当有线接口是主接口时,仅从无线接口启动 - 那么 dhclient 将快速启动并采用初始主从接口的 MAC 地址,并在尝试与 DHCP 服务器通信时使用该 MAC 地址。 当无线接口在稍后的短时间内通过接入点/基站进行身份验证、关联和授权,建立与网络的连接时,bonding 驱动程序会将无线接口设为新的活动接口,并将 bond0 接口上的活动 MAC 地址更改为与无线 MAC 地址匹配。 由于 dhclient 将继续使用来自有线接口的 MAC 地址,并且 bond0 接口不再接受该 MAC 地址,因此所有 DHCP 通信都将失败。 如果 /var/lib/dhclient/dhclient.leases 中没有保存的租约文件,则不会配置 IPv4 地址,并且 IPv4 流量将不可能。 还可以看到,当 dhclient 快速启动时,它可以读取主从接口的固件 MAC 地址,而不是分配给设备接口的任何 MAC 地址。 如果固件 MAC 地址为“null”,则 dhclient 会分配一个随机 MAC 地址。 使用这些固件或随机 MAC 地址的 BOOTP/DHCP 数据包可能在主从设备上“成功”获得回复,而在非主从设备上失败。 这可能会令人困惑和恼火。
这些只是 dhclient 和 IPv4 的问题。 幸运的是,在租约到期后,dhclient 在 DHCP 请求时“做对了”。 无论 dhclient 在哪个从接口上启动,它都能正常工作。
通过使用默认的 fail_over_mac=none
配置 bonding 驱动程序无法解决此问题。 几乎所有网络接口设备都不会传递 MAC 地址不是其自身的流量。 可以在 此处 看到这种警告的示例。 将会产生奇怪的网络行为,其中广播数据包将通过,但 ping/icmp 数据包仅在某些情况下通过,而在其他情况下则不通过。
理想情况下,dhclient 每次最初重试联系 DHCP 服务器时都会重新确定 bonding 接口 MAC 地址。 如果没有这一点,另一种不同的方法是简单地延迟 dhclient 的启动,直到内核 bonding 驱动程序配置了活动从接口之后。 如果活动从接口是无线接口,则 wpa_supplicant 将首先通过接入点/基站进行身份验证、关联和授权,并且 dhclient 将采用正确的 MAC 地址。 如果活动从接口是主从接口,则 dhclient 也会采用正确的 MAC 地址。 此延迟是通过 dhclient 服务单元文件中的简单 ExecStartPre= /usr/bin/sleep 8
行强制执行的,这是 systemd 启动 dhclient 与 supplicant 和 bonding 驱动程序选择活动接口之间保守的长时间延迟。 此选择时间在系统启动时最长,因为此时会启动许多进程。 在更快的硬件上,更短的延迟,例如 sleep 4
,可能仍然有效。
静态网络配置
/etc/conf.d/network.conf
# These Environment names are formed by prefixing the base variable name with the interface names. # Remember, here, these are systemd.service Environment variables, not shell variables. # Variables that are not set or that are set to the empty string will have no effect. # Add a list of interface names here, in the form of a comment, for reference. # wlp2s0 enp3s0 bond0 # PRIMARY is the name of the preferred network interface in the bonded group of interfaces. bond0PRIMARY='enp3s0' # ADDRS is a single-quoted space separated list of IPv4 and IPv6 addresses to apply to the interface. # The ADDRESS must be followed by a slash and a decimal number which encodes the network prefix length. # interfaceADDRS='address1/length address2/length ...' bond0ADDRS='192.168.0.2/24' wlp2s0ADDRS= enp3s0ADDRS= # ROUTES is a single-quoted space separated list of double-quoted ip-route ROUTE specifications. # A PREFIX must be followed by a slash and a decimal number which encodes the network prefix length. # Remember, to be able to add a route, the host must first be able to reach the gateway. # interfaceROUTES='"to prefix1/length] via gateway1" "to prefix2/length via gateway2" ...' bond0ROUTES=
这里,例如,静态私有 IPv4 地址将分配给 bonding 接口作为“安全措施”,以防 DHCP 服务器发生故障或无法访问。 主从接口也在此文件中指定。
/etc/systemd/system/static@.service
[Unit] Description= Static Network Configuration on %I Documentation= man:ip-address(8) man:ip-route(8) man:systemd.service(5) Wants= network.target Before= network.target BindsTo= sys-subsystem-net-devices-%i.device [Service] EnvironmentFile= /etc/conf.d/network.conf Type= oneshot RemainAfterExit= yes # Apparently, "ip" is not synchronous/atomic, so allow some time. ExecStart=-/usr/bin/ip link set %I up ExecStart=-/usr/bin/sh -c '[ "$%IADDRS" ] && \ for a in $%IADDRS;do /usr/bin/ip address add local $$a dev %I;done' ExecStart= /usr/bin/sleep 1 ExecStart=-/usr/bin/sh -c '[ "$%IROUTES" ] && \ for r in ${%IROUTES};do /usr/bin/ip route replace $$r dev %I;done' ExecStop=-/usr/bin/sh -c '[ "$%IROUTES" ] && \ for r in ${%IROUTES};do /usr/bin/ip route del $$r dev %I;done' ExecStop= /usr/bin/sleep 1 ExecStop=-/usr/bin/sh -c '[ "$%IADDRS" ] && \ for a in $%IADDRS;do /usr/bin/ip address del local $$a dev %I;done' [Install] WantedBy= sys-subsystem-net-devices-%i.device
当然,静态网络配置可以用作动态网络配置的替代方案或补充,或者完全不用。
wpa_supplicant 配置
/etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant ctrl_interface_group=wheel update_config=1 eapol_version=2 ap_scan=1 # fast_reauth=1 country=US network={ ssid="MyHome" priority=2 proto=RSN group=CCMP pairwise=CCMP key_mgmt=WPA-PSK #psk="SuperSecret" psk=404fe69d94ef522ba8e7a0c456a67a583c8f39ba0b29a3ac22ebe9494cf9992b }
请注意 wpa_supplicant 配置文件中的实际协议配置。 使用与基站不兼容的协议可能会导致无线连接不稳定且难以排除故障。 使用 wpa_passphrase ssid passphrase
预先计算 PSK。 wpa_gui
可以覆盖此文件。 请注意,wpa_supplicant
可以根据需要在任何有线或无线接口上运行。
/etc/systemd/system/supplicant@.service
[Unit] Description= wpa_supplicant on %P Documentation= man:wpa_supplicant(8) man:wpa_cli(8) man:wpa_supplicant.conf(5) man:wpa_passphrase(8) Wants= network-pre.target Before= network-pre.target BindsTo= sys-subsystem-net-devices-%i.device [Service] # Disable legacy 802.11b bitrates. ExecStartPre=-/usr/bin/iw %I set bitrates legacy-2.4 6 9 12 18 24 36 48 54 ExecStart= /usr/bin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant.conf -Dnl80211,wext,wired -i %I ExecStartPost=-/usr/bin/sh -c "/usr/bin/iw phy phy`iw dev %I info|grep wiphy|cut -d' ' -f2` set distance 10" ExecReload= /usr/bin/wpa_cli -i %I reconfigure ExecReload= /usr/bin/wpa_cli -i %I reassociate ExecStop= /usr/bin/wpa_cli -i %I terminate # Reset bitrates. ExecStopPost=-/usr/bin/iw %I set bitrates Restart= on-abnormal [Install] WantedBy= sys-subsystem-net-devices-%i.device
supplicant 和 DHCP 客户端相对于 shutdown 时的 network-pre.target 排序。 supplicant 不得在 DHCP 客户端释放地址租约之前停止。
请记住,iw
命令不适用于有线接口驱动程序或依赖于无线扩展用户空间驱动程序的旧无线驱动程序,并且在这些情况下将被忽略。
从设备配置
/etc/systemd/system/slave@.service
[Unit] Description= %P@%I Slave Documentation= https://docs.linuxkernel.org.cn/networking/bonding.html Wants= network.target Before= network.target Requires= master@%i.service After= master@%i.service Before= dhclient@%i.service Before= static@%i.service Before= supplicant@%p.service BindsTo= sys-subsystem-net-devices-%p.device BindsTo= sys-subsystem-net-devices-%i.device [Service] Type= oneshot RemainAfterExit= yes ExecStart=\ /usr/bin/ip link set %P down ;\ /usr/bin/ip address flush dev %P ;\ /usr/bin/ip link set %P master %I ;\ /usr/bin/ip link set %P up ExecStop=\ -/usr/bin/ip link set %P nomaster ;\ -/usr/bin/ip link set %P up [Install] WantedBy= master@%i.service WantedBy= sys-subsystem-net-devices-%p.device
这里将使用一个“技巧”,在从设备服务模板单元文件的命名中。 将两个环境变量传递给从设备单元文件,即网络接口的名称和 bonding 接口的名称。 请注意,有两个特定的环境变量传递到 systemd 单元文件中,%p/%P 和 %i/%I,它们分别是模板单元文件名中“@”字符之前和之后的字符串。 这里,bonding 接口名称在单元文件名中“@”字符之后的部分指定,而网络接口名称在“@”字符之前的部分传递。 这允许在命令行上任意指定两个网络接口名称,而无需修改单元文件本身。
此“slave@.service”单元文件将硬链接到与网络接口同名的文件,例如“wlp2s0@.service”和“enp3s0@.service”。 请注意,此处不能使用符号链接,因为 systemd 会将 %p/%P 设置为目标文件名“slave”,而不是所需的网络接口名称。
主设备配置
/etc/modprobe.d/bonding.conf
# The primary slave will be configured from the systemd master unit file. options bonding max_bonds=0 miimon=100 mode=active-backup fail_over_mac=active
/etc/systemd/system/master@.service
[Unit] Description= %I Interface Master Documentation= https://docs.linuxkernel.org.cn/networking/bonding.html Wants= network.target Before= network.target BindsTo= sys-subsystem-net-devices-%i.device [Service] # Environment= PRI=enp3s0 # Environment= PRI=wlp2s0 EnvironmentFile=-/etc/conf.d/network.conf Type= oneshot RemainAfterExit= yes # Apparently, "ip" is not synchronous/atomic, so allow some time. ExecStart=\ -/usr/bin/sh -c ' case %I in \ *br*) /usr/bin/ip link add name %I type bridge ;; \ *) /usr/bin/ip link add name %I type bond ; \ echo -n $%IPRIMARY > /sys/devices/virtual/net/%I/bonding/primary ;; \ esac' ;\ /usr/bin/ip link set %I up ;\ /usr/bin/sleep 1 ExecStop=\ /usr/bin/ip link delete %I ;\ /usr/bin/sleep 1 [Install] RequiredBy= dhclient@%i.service RequiredBy= static@%i.service
当然,如果未使用静态网络配置,则可以在此处使用“Environment=”代替 Environment 文件,然后可以避免使用 Environment 文件。 来自 Environment 文件的设置会覆盖使用“Environment=”进行的设置。
此主设备服务单元文件支持创建 bonding 主设备或桥接主设备网络接口。 创建的主设备接口类型由接口名称确定。 当接口名称包含字符串“br”时,将创建桥接主设备,否则创建 bonding 主设备。
RequiredBy 依赖项仅在此处用于在主设备停止和重启期间激活静态或动态网络配置单元的停止排序。 网络配置必须被关闭,并且该过程必须在释放从接口并删除主接口之前完成。
仅当主接口也是主机的 IP 接口时,才启用/安装 bonding 主设备单元或桥接主设备单元,也就是说,当在该主接口上启用/安装了静态或动态网络配置单元时。 如果 bonding 主设备或桥接主设备不是 IP 接口,则不应启用/安装主设备服务单元,因为它将手动启动,或者将在启动时或插入网络设备时由从设备服务单元启动。
启用/安装服务单元
有了这些准备工作,必须在命令行上指定接口名称。
每当编辑单元文件后,请运行 daemon-reload。
接下来,在插入任何可移除设备后,观察可用的网络接口名称
# ip address
对于每个将被 enslaved 的接口,将“slave@.service”硬链接到“interface_name@.service”
# ln /etc/systemd/system/slave@.service /etc/systemd/system/enp3s0@.service # ln /etc/systemd/system/slave@.service /etc/systemd/system/wlp2s0@.service
现在,确定哪些网络接口设备需要 supplicant 才能访问网络。 通常这只会是无线接口。 根据需要为每个接口启动/启用 supplicant@.service
单元(例如 supplicant@wlp2s0.service
)
然后,启用从设备和主设备单元,使用任何所需的接口名称。 (此处使用“bond0”:enp3s0@bond0.service
wlp2s0@bond0.service
master@bond0.service
)
显式地 启用 仅所需的网络配置,指定接口名称(此处再次为 bond0:dhclient@bond0.service
static@bond0.serice
)
最后,通过启动 master@bond0.service
来激活 bonding 接口、DHCP 客户端和任何静态网络配置
当任何配置的从设备出现时,特别是当系统启动时,主设备和 supplicant 单元将自动启动。 如果任何 DHCP 或从设备单元独立启动,则主设备单元也将启动,但通常这些单元已经在启动时启动。
测试结果
检查结果
# journalctl -afn100 $ ip a $ ps wax
$ systemctl list-units '*bond*' '*master*' '*supplicant*'
UNIT LOAD ACTIVE SUB DESCRIPTION sys-devices-virtual-net-bond0.device loaded active plugged /sys/devices/virtual/net/bond0 sys-subsystem-net-devices-bond0.device loaded active plugged /sys/subsystem/net/devices/bond0 dhclient@bond0.service loaded active running ISC dhclient on interface bond0 enp3s0@bond0.service loaded active exited enp3s0@bond0 Slave master@bond0.service loaded active exited bond0 Interface Master static@bond0.service loaded active exited Static Network Configuration on bond0 supplicant@enp3s0.service loaded inactive dead wpa_supplicant on enp3s0 supplicant@wlp2s0.service loaded active running wpa_supplicant on wlp2s0 wlp2s0@bond0.service loaded active exited wlp2s0@bond0 Slave system-master.slice loaded active active system-master.slice system-supplicant.slice loaded active active system-supplicant.slice LOAD = Reflects whether the unit definition was properly loaded. ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type. 12 loaded units listed. To show all installed unit files use 'systemctl list-unit-files'.
使用有线以太网接口,
$ cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011) Bonding Mode: fault-tolerance (active-backup) (fail_over_mac active) Primary Slave: enp3s0 (primary_reselect always) Currently Active Slave: enp3s0 MII Status: up MII Polling Interval (ms): 100 Up Delay (ms): 0 Down Delay (ms): 0 Slave Interface: wlp2s0 MII Status: up Speed: Unknown Duplex: Unknown Link Failure Count: 0 Permanent HW addr: 68:a3:c4:ac:63:d1 Slave queue ID: 0 Slave Interface: enp3s0 MII Status: up Speed: 100 Mbps Duplex: full Link Failure Count: 0 Permanent HW addr: e8:9a:8f:2a:9e:e1 Slave queue ID: 0
使用无线接口,
$ cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011) Bonding Mode: fault-tolerance (active-backup) (fail_over_mac active) Primary Slave: enp3s0 (primary_reselect always) Currently Active Slave: wlp2s0 MII Status: up MII Polling Interval (ms): 100 Up Delay (ms): 0 Down Delay (ms): 0 Slave Interface: wlp2s0 MII Status: up Speed: Unknown Duplex: Unknown Link Failure Count: 0 Permanent HW addr: 68:a3:c4:ac:63:d1 Slave queue ID: 0 Slave Interface: enp3s0 MII Status: down Speed: Unknown Duplex: Unknown Link Failure Count: 0 Permanent HW addr: e8:9a:8f:2a:9e:e1 Slave queue ID: 0
要关闭 bonding 接口并关闭主设备、从设备和 DHCP 单元,只需停止 master@bond0.service
。
可以使用 supplicant@interface_name.service
独立地停止 supplicant 单元。
这种 bonded 无线网络方法使 wpa_supplicant 在启动它的任何接口上持续运行。 通过运行 htop,可以看出 wpa_supplicant 和 DHCP 客户端守护程序似乎运行良好,并且不占用任何明显的 CPU 时间。
尽管如此,硬件开关或 rfkill 可用于在需要时实际禁用无线电。
请注意,除了已显式配置的排序依赖项之外,各种服务单元都是相当独立的。 因此,例如,可以通过停止 dhclient@bond0.service
来删除配置的 dhclient IPv4 地址,而不会干扰任何其他网络配置或功能。
同样,可以通过重启 dhclient@bond0.service
来释放地址并获取新地址。
可以通过停止 静态服务单元 (static@bond0.service
)、编辑 network.conf
文件,然后启动 static@bond0.service
单元来更改静态地址或默认网关
此外,当仅使用有线接口时,可以暂时禁用 wpa_supplicant,然后在稍后再次启动它。
即使只有一个接口可用,例如,当仅使用有线接口时,此 bonding 接口也能正常工作。 然后,只需插入配置的无线网卡,此新的无线接口将自动添加到 bonded 接口池,并启动 wpa_supplicant。 再次移除此无线网卡将移除从接口并停止 wpa_supplicant。
当首选有线网络时,请检查以太网电缆是否实际插入。 并且在使用无线网络时,例如使用 wpa_cli status
或 iwconfig
来验证与正确服务集标识符/SSID 的连接。