两个所有者,一个地址:TAP 网桥上的重复 IP
只有先连接才保住地址的 VPN 客户端,输掉的是 ARP 冲突而不是竞争。找出网桥上该地址的所有持有者。
一台 Windows 客户端持有 10.8.0.2,在启动顺序不变时工作正常;顺序一变,同一个地址就被报告为冲突,而客户端本身毫无改动。同一桥接网段上的另一台主机声明了同一个值,而最后完成配置的机器往往就是输家。两者都认为自己拥有它,输的一方悄悄停止使用一个本应使用的地址。正是把它当作时序问题,才让它每次重启都重现。
动网桥之前先读冲突证据
Windows 报告地址冲突时会附带另一名声明者的硬件地址。那个硬件地址才是有用的事实,因为它对应某一台主机上的某一个接口,而事件的显示名称并不会告诉你重复地址在哪里。改动任何东西之前,先把硬件地址记下来。
基于 ARP 的重复检测会在地址投入使用前探测竞争持有者,之后继续监视。所以在你配置网络时缺席的主机,一小时后仍可能引发冲突。探测不是启动时的一次性检查。后来出现的机器可以拿走一个整天安静使用的地址,这就是为什么这类故障读起来像竞争而不是配置错误。
冲突事件本身不会说明是哪份配置制造了另一半声明,而实验性地清除地址会毁掉本该告诉你答案的对应关系。证据的意义在于把一个硬件地址变成可检查的接口。按机器名去查资产清单,通常只会把你带到错误的主机。
把网段上的每一份声明都盘点出来
桥接 TAP 的部署把原本彼此隔离的以太网段连在一起,于是各自网络里唯一的地址,一旦帧共享同一条链路就可能相撞。这就是为什么这类故障在 VPN 上存在,而在它所取代的路由网络中不存在。要逐一列出所有可能的持有者,而不是你怀疑的第一个。
按这个顺序过一遍:每个网桥设备及其成员端口上的地址、OpenVPN 地址池以及任何按客户端固定分配的地址,还有覆盖该桥接网段的任何 DHCP 服务器。然后把冲突报告里的硬件地址与找到的接口对应起来。
ip -4 addr show | grep -E 'inet |^[0-9]+: '
bridge link show
ip neigh show dev br0
地址池和 DHCP 范围是人们最容易忘掉的两个持有者。把两个范围一起打印出来,先找重叠,再做别的事。手工指定的网桥地址和发放同一个值的地址池迟早会撞上,而在两个范围并排打印出来之前,这次相撞看起来像是随机的。
只在确实需要身份的地方给网桥编号
在普通的宿主机网桥里,网桥设备承载宿主机的三层配置,以太网和 TAP 成员则充当端口。给每个成员配一个自己的地址,或者把同一份安装脚本原封不动地复制到多台机器,就是一个网段出现三个同一值持有者的由来。成员转发帧并不需要自己的身份。它们需要的是:每台必须在该网段可达的宿主机,恰好只有一个身份。
只做帧交换的网桥在那个网段上根本不需要地址。不给它编号就消除了一整类冲突,前提是你已经验证过宿主机仍有管理通道。先确认访问,再移除地址,最后检查可达性。
如果要删的地址是进入这台机器的唯一路径,那么把它当实验删掉就是自找的中断,而不是诊断。测试任何东西之前,先验证带外通道。
让修正经得起重启
改动正在运行的接口只修好了这一次启动,别的什么也没修。任何在启动时重建该地址的东西,都会在下次重启时把冲突带回来,而你会得出修正没起作用的结论,实际上它从来就不是持久的。记下你改了哪个文件,好让下次重启是在确认一个决定,而不是揭开一个意外。
找到那份配置的持有者:网络管理器配置、按接口的文件、容器或虚拟机定义,或者 cloud-init 片段。在那里改,然后有意重启一台受影响的主机,确认回来的就是新值。重启是唯一能证明持久性的测试。
把网桥地址作为排除项保留在 DHCP 范围内,或者把它们移到范围之外。只存在于表格里的保留不是排除项,分配器不会读它。
在所有客户端都在线时证明它
一次连接成功什么都证明不了,因为最初的症状只在顺序改变时出现。把所有预期客户端都启动起来,改变启动顺序,并在重连之后重复一遍。然后重启那台过去总是输掉竞争的主机,确认地址仍然存在。
要直接确认,就在分配地址之前探测是否存在重复持有者,之后观察邻居表。如果没有任何回应,而且地址在完整的重启周期内保持唯一持有,冲突就是被解决了,而不只是被藏起来。下面的命令在网桥设备上完成这两项检查。RFC 5227 描述了这些工具所执行的探测与通告行为,当有人提议干脆关掉检测时,它就是应当引用的依据。
arping -D -I br0 10.8.0.2
ip neigh show dev br0 | grep 10.8.0.2
没有回应的探测在干净的网段上是预期结果。引出回应的探测会给你剩余持有者的硬件地址,也就是 Windows 事件在开头给你的同一份证据。把这份输出与变更记录放在一起,因为它是地址被唯一持有的唯一证明。