把 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 接主路由,IP 192.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 个交换机口可用,比再买一台交换机省事多了。