PCI(e) 透传
PCI(e) 透传是一种机制,它允许虚拟机从宿主机控制一个PCI设备。相比使用虚拟化硬件,这可以带来一些优势,例如更低的延迟、更高的性能或更多的功能(例如,卸载处理)。
但是,如果你将一个设备通过到虚拟机中,你就不能再在主机上或任何其他虚拟机中使用那个设备了。
请注意,虽然PCI直通对i440fx和q35机器都可用,但PCIe直通仅在q35机器上可用。这并不意味着作为PCI设备传递的PCIe能力设备将仅以PCI速度运行。将设备作为PCIe传递只是为了设置一个标志,告知客户端该设备是PCIe设备,而不是一个“非常快的旧版PCI设备”。某些客户端应用程序从这一点中受益。
一般要求
由于直通操作是在真实硬件上执行的,因此需要满足一些要求。下面简要概述这些要求,有关特定设备的更多信息,请参见 PCI Passthrough 示例。
硬件
您的硬件需要支持`IOMMU`(输入/输出 内存 管理 单元)中断重映射,这包括CPU和主板。
通常,带有VT-d的Intel系统和带有AMD-Vi的AMD系统支持这项功能。但是并不保证所有东西都能开箱即用,这可能是由于硬件实现不佳以及驱动程序缺失或质量低下。
进一步来说,服务器级别的硬件通常比消费级别的硬件有更好的支持,但即便如此,许多现代系统也能支持这一点。
请咨询您的硬件供应商,以确定他们是否支持您特定设置下的Linux系统中的此功能。
确定PCI卡地址
最简单的方式是在VM的硬件标签中使用GUI添加一种类型为"Host PCI"的设备。或者,你也可以使用命令行。
你可以使用以下方式找到你的卡片
lspci
配置
一旦你确保了你的硬件支持直通,你将需要进行一些配置来启用PCI(e)直通。
首先,您需要在BIOS/UEFI中启用IOMMU支持。通常对应的设置称为`IOMMU`或`VT-d`,但您应该在主板的手册中找到确切的选项名称。
对于Intel CPU,您还需要在kernel command line内核上启用IOMMU,通过添加:
intel_iommu=on
对于AMD的CPU来说,它应该会自动被启用。
如果您的硬件支持IOMMU直通模式,启用这种模式可能会提高性能。这是因为虚拟机会绕过超级管理程序通常执行的(默认的)DMA转换,而是将DMA请求直接传递给硬件IOMMU。要启用这些选项,请添加:
iommu=pt
到内核命令行。
您必须确保已加载以下模块。这可以通过将它们添加到’/etc/modules'`来实现。在6.2版本之后的内核中({pve} 8及以后版本),'vfio_virqfd’模块是’vfio’模块的一部分,因此,在{pve} 8及更高版本中加载’vfio_virqfd’是不必要的。
vfio vfio_iommu_type1 vfio_pci vfio_virqfd #如果是6.2或更高版本的内核,就不需要了
在更改任何与模块相关的内容后,你需要刷新你的`initramfs`。在{pve}上,这可以通过执行下列操作完成:
# update-initramfs -u -k all
要检查模块是否正在被加载,输出为
# lsmod | grep vfio
应当包括上述的四个模块。
最后重新启动以使更改生效,并检查它确实已启用。
# dmesg | grep -e DMAR -e IOMMU -e AMD-Vi
应该显示根据硬件和内核具体的消息可能会有所不同,IOMMU
、Directed I/O
或 Interrupt Remapping
是启用的。
有关如何排除故障或验证IOMMU是否按预期工作的说明,请参见我们wiki中的[验证IOMMU参数](https://pve.proxmox.com/wiki/PCI_Passthrough#Verifying_IOMMU_parameters)部分。
同样重要的是,你想要穿透的设备位于一个*单独的* IOMMU
组中。这可以通过调用 {pve} API 来检查:
# pvesh get /nodes/{nodename}/hardware/pci --pci-class-blacklist ""
如果设备与其功能(例如,带有HDMI音频设备的GPU)或与其根端口或PCI(e)桥一起处于一个`IOMMU`组中,这是可以的。
Note
|
PCI(e) 插槽
一些平台对其物理PCI(e)插槽的处理方式不同。因此,如果你没有得到期望的`IOMMU`组分离,有时将卡插入另一个PCI(e)插槽可能会有所帮助。 |
Note
|
不安全的中断
对于某些平台,可能需要允许不安全的中断。为此,在*/etc/modprobe.d/*目录下以`.conf`结尾的文件中添加以下行: options vfio_iommu_type1 allow_unsafe_interrupts=1 请注意,这个选项可能会让您的系统不稳定。 |
GPU直通笔记
无法通过{pve}网络界面上的NoVNC或SPICE显示GPU的帧缓冲区。
当通过整个GPU或vGPU传递,并且需要图形输出时,必须要么将显示器物理连接到显卡上,要么在客户端内配置远程桌面软件(例如,VNC或RDP)。
如果你想将GPU作为硬件加速器使用,例如,用于使用OpenCL或CUDA的程序,这是不必要的。
主机设备直通
PCI(e) 透传最常用的一种变体是透传整个 PCI(e) 卡,例如 GPU 或网络卡。
主机配置
{pve}尝试自动使PCI(e)设备对主机不可用。但是,如果这不起作用,有两件事可以做:
-
通过添加将设备ID传递给’vfio-pci’模块的选项
options vfio-pci ids=1234:5678,4321:8765
将以下内容添加到 /etc/modprobe.d/ 目录下的一个 .conf 文件中,其中
1234:5678
和4321:8765
是通过以下方法获得的厂商和设备ID:# lspci -nn
-
完全黑名单中的驱动程序在主机上,确保它自由绑定用于直通。
将 DRIVERNAME 添加到黑名单
在 /etc/modprobe.d/ 的 .conf 文件中。
要找到驱动名,请执行
# lspci -k
例如:
# lspci -k | grep -A 3 "VGA"
将输出类似于
01:00.0 VGA兼容控制器:NVIDIA Corporation GP108 [GeForce GT 1030] (rev a1) 子系统:Micro-Star International Co., Ltd. [MSI] GP108 [GeForce GT 1030] 正在使用的内核驱动:<some-module> 内核模块:<some-module>
现在我们可以通过将它们写入.conf文件来将驱动程序列入黑名单:
echo "blacklist <some-module>" >> /etc/modprobe.d/blacklist.conf
对于这两种方法,您需要再次更新`initramfs`,并在此之后重启。
如果这样做不起作用,你可能需要设置一个软依赖来在加载’vfio-pci’之前加载gpu模块。这可以通过’softdep’标志来完成,更多信息请参阅’modprobe.d’的手册页。
例如,如果你正在使用名为<some-module>的驱动程序:
# echo "softdep <some-module> pre: vfio-pci" >> /etc/modprobe.d/<some-module>.conf
要检查你的更改是否成功,你可以使用
# lspci -nnk
并检查您的设备条目。如果它显示
正在使用的内核驱动程序:vfio-pci
或者完全缺少’正在使用’这一行,设备已经可以用于直通。
虚拟机配置
当通过GPU时,使用’q35’作为机器类型、'OVMF'(对于虚拟机来说是’UEFI')而不是SeaBIOS,以及使用PCIe而不是PCI时,可以达到最佳兼容性。注意,如果你想要对GPU进行直通,而且GPU需要有一个能够支持UEFI的ROM,否则请使用SeaBIOS。要检查ROM是否支持UEFI,可以查看https://pve.proxmox.com/wiki/PCI_Passthrough#How_to_know_if_a_graphics_card_is_UEFI_.28OVMF.29_compatible[PCI Passthrough Examples] wiki。
此外,通过使用OVMF,可能可以禁用VGA仲裁,从而减少启动过程中需要运行的遗留代码量。要禁用VGA仲裁:
echo "options vfio-pci ids=<vendor-id>,<device-id> disable_vga=1" > /etc/modprobe.d/vfio.conf
将 <vendor-id>
和 <device-id>
替换为从以下位置获得的相应值:
# lspci -nn
PCI设备可以在虚拟机的硬件部分的网络界面中添加。或者,您可以使用命令行; 在VM配置中设置*hostpciX*选项,例如通过执行:
# qm set VMID -hostpci0 00:02.0
或者通过向虚拟机配置文件添加一行:
hostpci0: 00:02.0
如果您的设备具有多个功能(例如,“00:02.0”和“00:02.1”),您可以通过简写语法“00:02”将它们一起传递。这等同于在网页界面中勾选“所有功能”复选框。
根据设备和客户端操作系统的不同,可能需要一些选项:
-
x-vga=on|off 将 PCI(e) 设备标记为 VM 的主显卡。启用此选项后,vga 配置选项将被忽略。
-
'''pcie=on|off 告诉 {pve} 使用 PCIe 或 PCI 端口。一些客户/设备组合需要 PCIe 而不是 PCI。PCIe 仅适用于 'q35' 机器类型。'''
-
'''rombar=on|off 使固件ROM对客户可见。默认为开启。一些PCI(e)设备需要禁用此功能。'''
-
'''romfile=<path>, 是一个可选的路径,用于指定设备使用的ROM文件。这是相对于*/usr/share/kvm/*的相对路径。'''
一个将GPU设置为主要设备的PCIe直通示例:
# qm set VMID -hostpci0 02:00,pcie=on,x-vga=on
您可以覆盖宾客操作系统将看到的PCI供应商ID、设备ID和子系统ID。如果您的设备是一个变体,带有宾客驱动程序无法识别的ID,但您仍希望强制加载这些驱动程序(例如,如果您知道您的设备与已支持的变体共享相同的芯片组),那么这样做是有用的。
可用的选项包括`vendor-id`、device-id
、sub-vendor-id`和`sub-device-id
。你可以设置这些中的任何一个或全部,以覆盖你设备的默认ID。
例如:
# qm set VMID -hostpci0 02:00,device-id=0x10f6,sub-vendor-id=0x0000
单根I/O虚拟化
穿透PCI(e)设备的另一种方式是使用设备的硬件虚拟化功能,如果可用的话。
Note
|
启用 SR-IOV
要使用SR-IOV,平台支持尤其重要。首先可能需要在BIOS/UEFI中启用此功能,或者使用特定的PCI(e)端口才能使其工作。如有疑问,请咨询平台的手册或联系其供应商。 |
'''SR-IOV'(单根输入/输出虚拟化)使单个设备能够为系统提供多个’VF'(虚拟功能)。每个’VF’都可以在不同的虚拟机中使用,拥有完整的硬件特性,并且相比软件虚拟化设备,具有更好的性能和更低的延迟。'''
目前,最常见的使用场景是具有SR-IOV支持的NICs(网络接口卡),它可以为每个物理端口提供多个VF。这允许在VM内部使用诸如校验和卸载等功能,从而减少(主机)CPU开销。
主机配置
通常,有两种方法可以在设备上启用虚拟函数。
-
有时驱动模块有一个选项,例如对于某些英特尔驱动程序
max_vfs=4
可以将文件名以
.conf
结尾的文件放置在/etc/modprobe.d/
目录下。 (完成后不要忘记更新你的initramfs)请参阅您的驱动模块文档,以获取确切的参数和选项。
-
第二种,更通用的方法是使用`sysfs`。如果设备和驱动支持这一点,你可以动态地改变虚拟函数(VFs)的数量。例如,要在设备0000:01:00.0上设置4个虚拟函数,执行:
# echo 4 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs
为了使这个更改持久化,你可以使用`sysfsutils` Debian包。安装后通过 /etc/sysfs.conf 或在 /etc/sysfs.d/ 中的一个
FILE.conf
文件来配置它。
虚拟机配置
在创建VF之后,当你使用`lspci`命令输出它们时,你应该可以看到它们作为独立的PCI(e)设备。获取它们的ID,然后像处理正常的PCI(e)设备一样进行透传,参考qm_pci_passthrough_vm_config。
中介设备(vGPU,GVT-g)
中介设备是另一种方法,用于重用物理硬件的特性和性能到虚拟化硬件。这些在虚拟化GPU设置中最为常见,例如英特尔的GVT-g和NVIDIA在其GRID技术中使用的vGPU。
凭借此技术,物理卡能够创建虚拟卡,类似于SR-IOV。不同之处在于,中介设备在主机中不会作为PCI(e)设备出现,因而只适合在虚拟机中使用。
主机配置
一般而言,你的卡的驱动必须支持那个功能,否则它将无法工作。所以请咨询你的供应商,了解兼容的驱动程序以及如何配置它们。
Intel的GVT-g驱动程序已集成到内核中,应该适用于第5代、第6代和第7代Intel Core处理器,以及E3 v4、E3 v5和E3 v6 Xeon处理器。
要为英特尔显卡启用它,你必须确保加载模块’kvmgt'(例如通过`/etc/modules`),并在内核命令行上启用它,并添加以下参数:
i915.enable_gvt=1
在此之后,记得更新`initramfs`,然后重启你的主机。
虚拟机配置
要使用一个中介设备,只需在`hostpciX`虚拟机配置选项上指定`mdev`属性。
您可以通过’sysfs’获取支持的设备。例如,要列出设备'0000:00:02.0’支持的类型,您只需执行:
# ls /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types
每个条目是一个包含以下重要文件的目录:
-
'available_instances' 包含了此类型的实例仍然可用的数量,每个VM中使用的’mdev’都会减少这个数量。
-
"description" 包含了关于该类型功能的简短描述
-
“create”是用来创建这种设备的端点,如果配置了带有`mdev`的`hostpciX`选项,{pve}会自动为您完成这一操作。
一个配备了`Intel GVT-g vGPU`(Intel Skylake 6700k
)的示例配置:
# qm set VMID -hostpci0 00:02.0,mdev=i915-GVTg_V5_4
使用这个设置,{pve}会在虚拟机启动时自动创建这样一个设备,并在虚拟机停止时再次清理。
在集群中使用
它也可能在集群级别映射设备,以便它们可以与HA正确使用,并且可以检测到硬件变化,非根用户可以配置它们。有关该内容的详细信息,请参见资源映射。