在玩转 Proxmox VE(PVE)做软路由、NAS 或 AIO(All-in-One)系统时,PCIe 硬件直通几乎是必经之路。但很多人在直通网卡(尤其是多口网卡或板载网卡)时,经常会遇到一个诡异的现象:
一旦把网卡分配给虚拟机,PVE 宿主机上的其他设备(比如某个 NVMe 固态、USB 控制器甚至显卡)突然就动不了了,甚至导致 PVE 直接死机或网络彻底断开。
这背后的根本原因,就是 IOMMU 分组不独立。本文将从底层原理出发,带你一步步解决这个直通领域的最大痛点。
为什么直通网卡会连累其他设备?
简单来说,IOMMU(Intel VT-d 或 AMD-Vi)是负责将物理硬件隔离并分配给虚拟机的技术。为了保证安全,IOMMU 划分了多个 IOMMU Group(分组)。
- 安全规则:同一个 IOMMU 分组内的所有设备,必须打包在一起。要么全部留给宿主机,要么全部直通给同一个虚拟机。
- 罪魁祸首:许多消费级主板(尤其是 B 系列、H 系列芯片组)为了省电或缩减成本,硬件上不支持 ACS(Access Control Services,访问控制服务)。这导致主板芯片组引出的多个 PCIe 插槽、板载网卡、SATA 控制器被强行划分在同一个 IOMMU 分组里。
当你强行直通其中一个网卡时,PVE 会试图把整个分组的控制权都抢过来。结果就是,同组的其他设备被硬生生切断了与宿主机的联系,瞬间失效。
彻底解决 IOMMU 分组冲突的三个步骤
解决这个问题需要由易到难,从物理层面逐步过渡到软件层面。
第一步:排查 BIOS 设置(最基础但最易遗漏)
有些主板默认关闭了关键的分离协议,先去 BIOS 里确认以下选项已开启:
- VT-d / AMD-Vi:必须为
Enabled(开启直通的基础)。 - SR-IOV Support:如果主板和网卡支持,务必开启。
- PCIe ACS / ARI Support:部分中高端主板在高级 PCI 设置里有 ACS 选项,将其设为
Enabled。 - IOMMU:设置为
Enabled,不要选Auto。
保存重启后,进入 PVE 终端,运行以下脚本查看当前的 IOMMU 分组情况:
find /sys/kernel/iommu_groups/ -type l
如果发现你的网卡依然和一堆关键设备(如 SATA 控制器)挤在同一个 group 里,说明主板硬件本身确实无法物理拆分,需要进入下一步。
第二步:物理规避——调整 PCIe 插槽
主板上的 PCIe 插槽并非地位平等:
- 直连 CPU 的插槽(通常是靠近 CPU 的第一条 PCIe x16 插槽,用来插显卡的):通常拥有独立的 IOMMU 分组,拆分非常完美。
- 芯片组(PCH)引出的插槽:通常共享带宽,极易合用一个 IOMMU 分组。
实操建议:
如果你直通的是一张多口网卡(如 Intel i350-T4、i226-V),尝试将它拔下来,插到最靠近 CPU 的主 PCIe 插槽上。把不需要直通的设备(如显卡或 HBA 卡)移到下方的副插槽。这种“物理位移”往往能奇迹般地让网卡获得独立的 IOMMU 分组。
第三步:终极大招——开启 PVE ACS 补丁(软解拆分)
如果物理调整不可行(比如用的是 ITX 主板,或者直通的是板载网卡),我们就必须借助内核参数,强行让内核“假装”设备之间是相互隔离的。这就是经典的 ACS Override 补丁。
请根据你的 PVE 引导方式(GRUB 或 systemd-boot)进行配置。如果不确定是哪种,可以通过以下命令判断:
[ -d /sys/firmware/efi ] && echo "EFI 模式" || echo "Legacy 模式"
情况 A:使用 GRUB 引导(多数 Legacy 模式及部分 UEFI 安装)
编辑 GRUB 配置文件:
nano /etc/default/grub找到
GRUB_CMDLINE_LINUX_DEFAULT这一行。默认可能长这样:GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on"在后面追加
pcie_acs_override=downstream,multifunction。- Intel CPU 示例:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction"- AMD CPU 示例:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt pcie_acs_override=downstream,multifunction"保存并退出(在 nano 中按
Ctrl+O,回车,再按Ctrl+X)。更新 grub 配置:
update-grub
情况 B:使用 systemd-boot 引导(新版 PVE 默认且使用 ZFS 文件系统)
编辑内核参数配置文件:
nano /etc/kernel/cmdline这一行内容较短,直接在末尾空格后添加参数。
- 添加后的完整示例:
root=ZFS=rpool/ROOT/pve-1 boot=zfs quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction保存并退出。
更新 PVE 引导工具(此步至关重要,否则重启不生效):
proxmox-boot-tool refresh
关键参数解析:我该用哪个参数?
在上面的配置中,我们使用了 pcie_acs_override=downstream,multifunction。这两个参数的作用不尽相同,你可以根据拆分效果进行微调:
pcie_acs_override=downstream:拆分所有从 PCIe 桥(PCIe Bridge)引出的下游设备。通常解决不同插槽之间的设备混淆。pcie_acs_override=multifunction:拆分多功能设备。例如单张网卡上有 4 个网口(通常识别为01:00.0,01:00.1等),如果不加此参数,4 个网口会死死绑定在同一个组里,无法做到“网口 1 直通给 OpenWrt,网口 2 留给 PVE”。pcie_acs_override=id:xxxx:xxxx(进阶):如果你只想针对某一个特定的物理设备进行拆分,避免全局拆分带来安全风险,可以使用设备的 VID/PID 进行精准拆分。
验证拆分结果
完成上述修改后,重启 PVE 宿主机。
重启完成后,再次登录 Shell,运行以下脚本来查看分组:
# 这个脚本能清晰地展示每个 IOMMU 组里有哪些设备
for d in /sys/kernel/iommu_groups/*/devices/*; do
n=${d#*/iommu_groups/*}; n=${n%%/*}
printf 'IOMMU Group %s ' "$n"
lspci -nns "${d##*/}"
done
此时你应该会发现,原本挤成一坨的设备已经被整齐地划分到了不同的 IOMMU Group 中。那个你想直通的网口,现在应该独自占有一个 Group。
接下来,你就可以放心地在虚拟机硬件设置里,添加“PCI 设备”,并勾选对应的网卡进行直通,而完全不用担心影响到宿主机的其他设备了。
⚠️ 避坑安全警告
使用 pcie_acs_override 属于“欺骗”内核的黑科技。在享受独立直通的便利时,必须知晓潜在的安全隐患:
- 数据安全风险:硬件上它们依然共享某些底层总线。如果直通的虚拟机被黑客攻破,理论上黑客可以利用 DMA(直接内存访问)越界读取或写入同组内其他设备(比如你的系统盘、显卡)的内存数据。
- 稳定性隐患:如果某些廉价硬件本身存在设计缺陷,强行拆分可能会导致数据校验出错,极少数情况下会导致 PVE 宿主机无故重启。
因此,在 Homelab 娱乐或个人测试环境中,该补丁可以放心使用;但如果在商用生产环境或多租户的云服务器中,强烈建议通过更换支持 ACS 的企业级主板来彻底解决问题。