Linux bridge: MAC addresses and dynamic ports
场景:KVM 虚拟化宿主机运行多个桥接模式的客户机(guests)。宿主机有一个网桥接口 br0,最初只包含 eth0,随着客户机的启动和停止,其他接口会动态地加入或移除出网桥。
问题是,当某些客户机启动或停止时,宿主机似乎会随机遭受一些连接丢失(从几秒到 30-40 秒)。起初人们可能会想到这与 STP(生成树协议)有关,但事实证明它是禁用的(而且即使启用,端口的出现或消失也不应影响现有端口)。
实际情况是:当启动新虚拟机时,会创建一个 tap接口 并绑定到网桥(该接口通常连接到虚拟机的以太网接口)。该接口名称类似 vnet5。一个微小但重要的细节是:这个 tap 接口拥有一个近乎随机的 MAC 地址。(注意这里指的是主机侧的 tap 接口,而非虚拟机侧的虚拟接口——后者的 MAC 地址可在虚拟机配置文件或命令行中配置)。理论上可以设置这个主机侧 tap 接口的 MAC 地址,但操作复杂且基本无人这样做(而且 virt-manager 也未提供该功能)。
现在,Linux 中的网桥接口默认会使用所有绑定接口中 MAC 地址最低的那个作为自身的 MAC 地址。因此,如果新创建的接口拥有更低的 MAC 地址,网桥就会改变自身 MAC 地址,使用新接口的地址。当虚拟机停止时,tap 接口会从网桥中移除并销毁,此时网桥的 MAC 地址必须再次变更。根据虚拟机启动/停止的频率,主机的网桥接口可能会相当频繁地更改其 MAC 地址。
这当然会(也确实)导致主机进出流量出现连接问题(幸运的是,虚拟机的进出流量不受影响),因为相邻的计算机和网络设备在与主机通信前,必须用新的 MAC 地址更新其 ARP 缓存。根据流量模式的不同,这一过程可能需要几秒到数十秒不等。
所幸,有一种方法可以确保网桥的 MAC 地址固定不变,从而完全避免该问题。感谢这个讨论帖和这个讨论帖中遇到类似问题的人,我发现:如果强制将网桥的 MAC 地址设置为特定值,网桥会“记住”该地址并使其永久生效。但有个注意事项:该地址必须属于网桥绑定的某个设备。在我们的示例(可能也是最常见的情况)中,理想的候选对象显然是永久绑定的 eth0。
设置接口 MAC 地址有两种方法。传统方法是使用 ifconfig:
# 00:0a:e7:2c:44:2a is eth0's MAC address# ifconfig br0 hw ether 00:0a:e7:2c:44:2a
更新更好的方法是使用 iproute2:
ip link set br0 address 00:0a:e7:2c:44:2a
另外,最好在启动时设置永久 MAC 地址。例如在 Debian/Ubuntu 系统中,可以在配置文件 /etc/network/interfaces 中添加以下配置:
auto br0iface br0 inet static address 10.4.0.3 netmask 255.255.255.0 gateway 10.4.0.254 bridge_ports eth0 bridge_stp off post-up ip link set br0 address 00:0a:e7:2c:44:2a
Src
https://backreference.org/2010/07/28/linux-bridge-mac-addresses-and-dynamic-ports/index.html