直通与半直通:网卡与硬盘

为什么要直通

虚拟机通过虚拟网卡读写硬件,中间要经过宿主内核转发,性能打折。直通(Passthrough)则是把物理设备整个交给虚拟机,虚拟机里看到的设备和真机一样,性能接近原生。软路由最典型的场景就是 WAN 网卡直通:千兆线速转发只占少量 CPU,2.5G 与万兆更是基本绑定直通。硬盘直通同理,NAS 虚拟机绕过虚拟磁盘层,可以直接管理磁盘的健康检测与休眠。

直通之后代价也要清楚:第一,设备给了虚拟机,宿主就用不了;第二,启用直通的虚拟机不能在线迁移,对家用 AIO 无所谓;第三,配置比普通虚拟机多几步,排错需要看内核日志。所以原则是性能瓶颈点才直通,普通场景虚拟网卡完全足够——一个百兆宽带配上两台虚拟机的家用环境,不直通也感受不到差别。

启用 IOMMU 与 VFIO

直通的底层依赖是 IOMMU(Intel 叫 VT-d,AMD 叫 AMD-Vi)。先在 BIOS 打开 VT-d 或 IOMMU 开关,再给宿主内核加参数。GRUB 引导的机器编辑 /etc/default/grub,找到 GRUB_CMDLINE_LINUX_DEFAULT 那一行:

# Intel 平台
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt"
# AMD 平台
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt"

保存后执行 update-grub。systemd-boot 引导的机器则改 /etc/kernel/cmdline,同样追加参数后执行 proxmox-boot-tool refresh。怎么判断自己是哪种引导?执行 proxmox-boot-tool status 就能看到。接着加载 VFIO 模块,编辑 /etc/modules 加入四行:

vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

然后 update-initramfs -u -k all 并重启。重启后先验证:dmesg 的输出里能看到 IOMMU enabled 字样,说明底层已就绪。较新的 Intel 内核可能默认已开启 IOMMU,显式写上也不会出错,属于成本为零的保险。

直通配置五步

IOMMU 分组是能否直通的关键。设备按分组整体分配,同一组里的设备要么全给一个虚拟机,要么都不给。用 find /sys/kernel/iommu_groups/ -type l 可以列出分组,网页上添加 PCI 设备时也会提示同组设备。有的主板会把核显、声卡、USB 控制器塞进同一组,这时候要么整组直通,要么加 pcie_acs_override=downstream 参数强行拆分,后者不保证稳定,只建议在无法退换的硬件上尝试。废话少说,买板子之前搜一下型号加 IOMMU 关键词,比事后折腾强一百倍。

网卡直通

确认分组没问题后,在 PVE 网页给虚拟机添加硬件,选 PCI 设备,下拉列表里挑目标网卡,勾选所有功能与 PCI-Express,保存开机即可。进虚拟机里用 ip link 就能看到网卡。网卡直通最常见的坑:宿主还在用这块网卡当管理口。直通前务必确认管理流量走另一网口,否则一开机宿主就失联,只能去机器前插显示器。第二个坑是双口网卡的两个口常在同一分组,直通一个口通常会连带另一个口都进虚拟机,规划时要按整卡考虑。

设备 直通收益 注意事项
WAN 网卡 高,软路由必备 先确认管理口在另一网卡
核显 中,转码可用 分组常与声卡同组
SATA 控制器 高,给 NAS 注意光驱也计入同组
USB 控制器 中 单个 USB 设备也可走 USB 透传
独立网卡 高 双口常为整组,按卡规划

硬盘直通

硬盘的处理有三种路线。第一种整盘直通:连盘带控制器一起交给虚拟机,性能与兼容性最好,适合 NAS 虚拟机组 ZFS 或 RAID。前提是控制器分组干净,板载 SATA 口经常光驱、多口共组,买张便宜的 PCIe SATA 扩展卡单独分组是常见解法。第二种裸盘直通,在网页虚拟机硬件里添加硬盘选择 Discard 与直接磁盘,或用命令行:

# 把 /dev/sdb 整块盘塞给虚拟机 201
qm set 201 -scsi1 /dev/disk/by-id/ata-ST2000DM008-2FR102_ZFL1A1BC

注意用 by-id 而不是 sdb 这种动态名称,否则某个插拔动作之后盘符漂移,虚拟机就找不到盘了。第三种就是常规虚拟磁盘,最灵活、可快照、可备份,性能损失对日常共享文件几乎无感,建议系统盘一律走这条路线。

半直通:LXC 挂载

半直通在 LXC 场景更常用:容器里要用宿主的目录或设备,不必整体直通,直接挂载。比如宿主建在 SSD 上的下载目录挂给下载容器用,或者把硬盘以绑定挂载方式挂进容器。配置在 PVE 网页对应容器的资源页添加挂载点,也可以直接改配置文件:

# 容器配置里加一行挂载点
mp0: /mnt/data01/download,mp=/data

半直通开销几乎为零,灵活性最高,代价是容器与宿主共享内核、隔离弱,适合放可信的轻量服务。给容器用硬盘还有一招:把整块盘格式化后挂到宿主某目录再挂进容器,容器层面看到的就是普通目录,管理最简单,但磁盘 SMART 信息就被宿主接管了。

硬盘三条路线;left=整盘直通;性能接近原生;宿主失去该盘;适合NAS组阵列;right=虚拟磁盘;可快照最灵活;多一层开销;适合系统盘

验证与排错

直通配置出问题的排错顺序固定三步:先看宿主 dmesg 与系统日志里的 vfio 相关条目,确认模块与分组正常;再看虚拟机的硬件配置,确认 PCI 设备条目还在且勾选项没丢;最后进客户机系统用 lspci 看设备是否枚举成功、驱动是否加载。绝大多数故障都暴露在这三步里,盲目重启虚拟机是最浪费时间的选择。

一个常被忽略的检查项是宿主的 BIOS 更新:有的板子 IOMMU 分组有缺陷,后续 BIOS 修复了分组策略,升级后原本不能直通的组合突然就分组干净了。也有反向的案例:某版 BIOS 反而引入了新的 ACS 限制,升级之后反而要回滚。所以宿主 BIOS 的任何变动都值得记到维护日志里,便于日后追溯。

直通设备的温度与功耗监控也值得做:直通后的硬件对宿主是不可见的,宿主看到的只是空的 PCI 槽位,温度信息全在客户机里。核显直通给 NAS 做转码时,转码高负载的温升要靠客户机内的传感器工具来观察,别等自动关机了才发现散热压不住。监控采集器的分工也对应调整:宿主跑 node_exporter 采宿主设备,客户机各自跑自己的采集器。

给一组常见硬件的直通友好度参考:Intel I225/I226 网卡与大部分 server 级网卡开箱即用、很少遇到分组问题;板载声卡与 USB 控制器经常与别的设备同组,直通前先看分组;核显的则需要额外留意型号与内核版本的配合(每个内核大版本初期常有回归)。这张表会随内核更新变化,遇到问题去社区搜对应内核版本是最快的。

家用 AIO 最常见的直通组合套装是:WAN 网卡给路由、SATA 控制器给 NAS、核显给影音转码,其余设备走半直通或虚拟设备。这套组合把“最需要性能的路径”都过了桥,剩下的应用层完全用不上直通。记住直通是手段不是目的,一个四口之家千兆宽带的环境里,把所有 PCI插槽都直通出去带来的排错复杂度,远超它带来的那点性能提升。

硬件兼容性经验(补充)

一个冷门但救命的注意点:虚拟机的机型选 q35(PVE 默认)时对 PCIe 直通支持更好,i440fx 老机型上部分设备表现异常。BIOS 选 OVMF(UEFI)也是同理——老 SeaBIOS 的显卡 ROM 加载经常出幺蛾子。这两个选项在装虚拟机时一次选对,能避开社区里一半的求助帖。

sh-0103

q35 机型与 OVMF 之外还有一个细节值得一提:直通设备的 ROM-Bar 选项。显卡类设备必须勾上 ROM-Bar 才能加载 GOP 驱动输出画面,网卡则不需要。相关的还有“主 GPU”选项,把显卡设为主 GPU 后虚拟机的控制台就直接从这张卡输出,第一次配置 Windows 虚拟机时省去不少折腾。

社区还流传着一个经典坑:直通后系统里设备管理器显示感叹号(代码 43),这是 Nvidia 显卡检测到虚拟化环境拒绝加载驱动。解决办法是在虚拟机 CPU 配置里隐藏虚拟化特征(hidden 选项),老版本 PVE 还要手工加 args 参数,新版直接在网页勾选即可。这类坑被踩了无数次,答案都写进了 Wiki,遇到时先搜一下而非自己从头排查。

延伸阅读