把 PVE 多余物理网口当交换机用
家里的小主机装了 Proxmox VE,板载 4 个网口,但只用到一个接主路由当管理口,剩下三个一直空着。前两天发现书桌旁的物理交换机口又不够用了,懒得再买一台,就琢磨着能不能直接拿 PVE 这几个空口顶上。
PVE 本身就是 Linux + KVM,网络这块用的是内核自带的 Linux Bridge,思路其实很直接:把闲置的物理网口加入到现有的 vmbr0 里,bridge 内部二层互通,效果上就跟一台交换机一样。
原理
Linux Bridge 是内核自带的二层虚拟交换机,把多个接口(物理网口、tap 设备、VLAN 子接口都行)加到同一个 bridge,它们之间就能像接在同一台交换机上一样互通。
PVE 默认就是用 vmbrX 这种 bridge 把 VM 的虚拟网卡和物理网口连起来。所以这次的改动本质上没引入任何新东西,只是把原本只挂着一个上行口的 vmbr0 扩展成一个多口的虚拟交换机:
┌─────────────────────────────────────────────────┐
│ vmbr0 (Linux Bridge) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌────┐ │
│ │ nic0 │ │ nic1 │ │ nic2 │ │ nic3 │ │ VM │ │
│ └───┬──┘ └───┬──┘ └───┬──┘ └───┬──┘ └────┘ │
└──────┼─────────┼─────────┼─────────┼────────────┘
│ │ │ │
主路由 PC/NAS 其他设备 闲置
环境
- PVE 9.1.9(kernel 7.0.2-2-pve)
- 板载 4 口:
nic0~nic3 nic0接主路由,IP192.168.18.18/24,挂在vmbr0- 目标:让
nic1/nic2/nic3也能直接接终端设备
摸现状
动手前先看清楚当前的网络结构:
ip -br link show
ip -br addr show
brctl show
输出:
$ ip -br link show
lo UNKNOWN 00:00:00:00:00:00
nic0 UP a8:b8:e0:03:7c:21
nic1 DOWN a8:b8:e0:03:7c:22
nic2 DOWN a8:b8:e0:03:7c:23
nic3 DOWN a8:b8:e0:03:7c:24
vmbr0 UP a8:b8:e0:03:7c:21
tap100i0 UNKNOWN e2:be:ad:87:6a:02
$ brctl show
bridge name bridge id STP enabled interfaces
vmbr0 8000.a8b8e0037c21 no nic0
tap100i0
nic0 在 vmbr0 里,三个空口状态都是 DOWN,tap100i0 是 VMID 100 那台群晖虚拟机的虚拟网卡。
改配置
PVE 的网络配置在 /etc/network/interfaces。先备份:
cp /etc/network/interfaces /etc/network/interfaces.bak.$(date +%Y%m%d)
看一下原始内容:
cat /etc/network/interfaces
auto lo
iface lo inet loopback
iface nic0 inet manual
auto vmbr0
iface vmbr0 inet static
address 192.168.18.18/24
gateway 192.168.18.1
bridge-ports nic0
bridge-stp off
bridge-fd 0
iface nic1 inet manual
iface nic2 inet manual
iface nic3 inet manual
source /etc/network/interfaces.d/*
挺干净的,只有 vmbr0 一个 bridge,三个闲置口已经声明了但没被使用。
要改的就一行——把 bridge-ports nic0 改成 bridge-ports nic0 nic1 nic2 nic3。一条 sed 解决:
sed -i 's/bridge-ports nic0$/bridge-ports nic0 nic1 nic2 nic3/' /etc/network/interfaces
确认一下:
$ grep bridge-ports /etc/network/interfaces
bridge-ports nic0 nic1 nic2 nic3
应用
先用 ifquery 解析一遍配置,相当于 dry-run:
ifquery -a
没报错就可以应用:
ifreload -a
这里有个坑要注意:**别用 systemctl restart networking**。ifreload 来自 ifupdown2,会做增量 diff,只刷变化的部分;而 networking 服务的 restart 是一刀切重启所有接口,远程操作时大概率会把自己 SSH 连接干掉。
ifreload 应用完之后整个过程是无感的,连接不会断。
验证
$ brctl show vmbr0
bridge name bridge id STP enabled interfaces
vmbr0 8000.a8b8e0037c21 no nic0
nic1
nic2
nic3
tap100i0
四个物理口加 VM 的 tap 设备都在 vmbr0 里了。
把一台 Windows 电脑接到 nic1,开机直接从主路由 DHCP 拿到 192.168.18.x 的 IP,能 ping 通网关、ping 通 PVE,上网正常,一气呵成。
想看插拔状态变化可以开个 watch 盯着:
watch -n 1 'ip -br link show | grep nic'
接上网线那一下 nic1 从 DOWN 翻成 UP,没有任何额外配置。
几个要注意的点
环路是最容易翻车的地方。 如果几个口同时插到同一台外部交换机或主路由(比如 nic0 和 nic1 都接到主路由 LAN 口),就会形成二层环路。我的配置里 bridge-stp off 关闭了生成树协议,广播风暴会瞬间把整个网络打爆。
要么物理上避免(只有一个口当上行接路由器,其他口只接终端设备,这是最简单的做法),要么把 bridge-stp 改成 on 让 bridge 自己检测和阻断环路。家用单上行场景关 STP 没事,拓扑复杂或者怕自己手抖插错的话开着稳妥。
MTU 要一致。 同一个 bridge 里所有端口的 MTU 不一致会出现奇怪的丢包,本文场景全是 1500 默认值,没什么要操心的。
性能边界。 Linux Bridge 走的是 CPU 软转发,千兆环境下毫无压力,跑满线速 CPU 占用都很低。但万兆及以上场景,多口同时大流量 CPU 会成瓶颈,那时候才需要考虑 PCI 直通、SR-IOV 这些更猛的方案。家用千兆别折腾,virtio + bridge 已经够用。
Offload 兼容性。 某些网卡的 TSO/GRO/GSO 在 bridge 场景偶尔会有性能怪异或丢包,遇到再用 ethtool -K nicX tso off gso off gro off 关掉就行,不出问题不用动。
翻车了怎么办
如果改完发现网断了(最常见的就是改错文件名或者管理口被踢),通过 IPMI、iKVM 或者直接接显示器键盘登录后:
cp /etc/network/interfaces.bak.YYYYMMDD /etc/network/interfaces
ifreload -a
这就是为什么前面要先备份。改网络配置之前一定要留好回滚路径,没有带外管理通道的话风险会高很多。
后续可以折腾的方向
记一下以后可能用得上的扩展。
VLAN 感知。 想在这个虚拟交换机上做 VLAN 划分(隔离访客网、IoT 网什么的),把 vmbr0 改造成 VLAN-aware:
auto vmbr0
iface vmbr0 inet static
address 192.168.18.18/24
gateway 192.168.18.1
bridge-ports nic0 nic1 nic2 nic3
bridge-stp off
bridge-fd 0
bridge-vlan-aware yes
bridge-vids 2-4094
VM 网卡指定 VLAN tag 就能参与隔离。
Open vSwitch。 需要更细的流表、端口镜像、LACP 这些功能可以上 OVS,但配置复杂度也跟着上去,家用一般用不到。
PCI 直通。 想让某个 VM(OpenWrt 软路由、群晖)独占一个物理口拿到原生性能,可以做 PCIe passthrough。代价是这个口从 PVE 剥离、再也不能当 bridge 成员用,且需要主板和 CPU 支持 IOMMU。我也想过把一个口直通给群晖,但实测 virtio + bridge 在千兆下已经能跑满线速,提升微乎其微,就放弃了。万兆环境再考虑这个。
小结
整个改动只有一行配置变更,ifreload 应用一下就完事,零成本、零中断、随时可回滚。如果你也有 PVE 主机网口闲置,强烈建议直接利用起来——板载 4 口主板瞬间多出 3 个交换机口可用,比再买一台交换机省事多了。