![将单个设备隔离到单独的 IOMMU 组中以用于 PCI 直通?](https://linux22.com/image/1568386/%E5%B0%86%E5%8D%95%E4%B8%AA%E8%AE%BE%E5%A4%87%E9%9A%94%E7%A6%BB%E5%88%B0%E5%8D%95%E7%8B%AC%E7%9A%84%20IOMMU%20%E7%BB%84%E4%B8%AD%E4%BB%A5%E7%94%A8%E4%BA%8E%20PCI%20%E7%9B%B4%E9%80%9A%EF%BC%9F.png)
我有以下 IOMMU 组和设备。
$ for a in /sys/kernel/iommu_groups/*; do find $a -type l; done | sort --version-sort
/sys/kernel/iommu_groups/0/devices/0000:00:00.0
/sys/kernel/iommu_groups/1/devices/0000:00:02.0
/sys/kernel/iommu_groups/2/devices/0000:00:04.0
/sys/kernel/iommu_groups/3/devices/0000:00:14.0
/sys/kernel/iommu_groups/3/devices/0000:00:14.2
/sys/kernel/iommu_groups/4/devices/0000:00:15.0
/sys/kernel/iommu_groups/4/devices/0000:00:15.1
/sys/kernel/iommu_groups/5/devices/0000:00:16.0
/sys/kernel/iommu_groups/6/devices/0000:00:17.0
/sys/kernel/iommu_groups/7/devices/0000:00:1c.0
/sys/kernel/iommu_groups/7/devices/0000:00:1c.7
/sys/kernel/iommu_groups/7/devices/0000:01:00.0
/sys/kernel/iommu_groups/7/devices/0000:02:00.0
/sys/kernel/iommu_groups/8/devices/0000:00:1f.0
/sys/kernel/iommu_groups/8/devices/0000:00:1f.2
/sys/kernel/iommu_groups/8/devices/0000:00:1f.3
/sys/kernel/iommu_groups/8/devices/0000:00:1f.4
我想将该特定设备隔离/sys/kernel/iommu_groups/7/devices/0000:01:00.0
到其自己的组中,并且不将其与其他设备放在同一组中。
我们如何将单个设备隔离到单独的 IOMMU 组中,以供 KVM 虚拟机进行 PCI 直通?
答案1
我知道这是一个老问题,但最近我不得不尝试解决这个问题。
IOMMU 的经验法则是内核会为您找出映射。当内核启动时,它会查找哪些设备可以映射到 I/O 虚拟映射 (IOVA)。如果设备具有相同的 IOVA,则它们最终会归入同一组。这样做是为了保证每个组都有可以单独寻址和通信的设备。
有几种解决方案。第一种是,您可以尝试将卡移到主板上的另一个位置。如果它是 PCI 卡而不是 PCIe 卡,那么您可能运气不佳,因为所有 PCI 端口可能都映射到同一个 PCIe 桥,因此将共享同一个 IOVA。
如果您确实仍需要这样做,那么您可以将同一组中的所有设备全部分配给 vfio-pci,然后您可以将它们分配到设备需要去的地方。
例如,在我的计算机上,第 13 组有一堆设备,包括一个额外的视频卡(18:00)。这是我从该目录输出的:
root@rwl01:/sys/kernel/iommu_groups/13/devices# ll
total 0
drwxr-xr-x 2 root root 0 Feb 15 15:43 .
drwxr-xr-x 3 root root 0 Feb 15 15:43 ..
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:03:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:03:00.1 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.1
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:03:00.2 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:16:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:16:01.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:01.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:16:02.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:02.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:16:03.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:03.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:16:04.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:04.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:16:08.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:08.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:17:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:00.0/0000:17:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:18:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:01.0/0000:18:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:18:00.1 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:01.0/0000:18:00.1
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:19:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:02.0/0000:19:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:1a:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:03.0/0000:1a:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:1b:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:04.0/0000:1b:00.0
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:1b:00.1 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:04.0/0000:1b:00.1
lrwxrwxrwx 1 root root 0 Feb 15 15:43 0000:1c:00.0 -> ../../../../devices/pci0000:00/0000:00:01.3/0000:03:00.2/0000:16:08.0/0000:1c:00.0
如您所见,目录是一堆链接。以下是事物连接方式的链条:
root@rwl01:/sys/kernel/iommu_groups/13/devices# lspci | grep -E '00:01.3|03:00.2|16:01.0'
00:01.3 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 1453
03:00.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43b0 (rev 02)
16:01.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Device 43b4 (rev 02)
对我来说,所有这些设备都在同一个桥上,我的额外视频卡、突袭控制器等。你无法轻易将它们分开。
但是你可以
您需要申请https://queuecumber.gitlab.io/linux-acs-override/(ACS Override 内核补丁)这将允许您使用命令行参数来公开组的部分内容,这些部分是它们自己的组。安装补丁后,您可以配置所需的内核命令行参数:
pcie_acs_override =
[PCIE] Override missing PCIe ACS support for:
downstream
All downstream ports - full ACS capabilties
multifunction
All multifunction devices - multifunction ACS subset
id:nnnn:nnnn
Specfic device - full ACS capabilities
Specified as vid:did (vendor/device ID) in hex
从这里开始,您应该能够将设备置于其自己的组中,然后您就可以开始比赛了。此方法存在一些问题:
这里有几个很好的链接:
答案2
我知道最初的问题来自 2019 年,但听起来,使用更新的内核可能会容易得多。
对于遇到任何问题的人,我想通过 Broadcom BCM5709 4 端口 NetXtreme II 千兆以太网卡上的 NIC,该卡已插入 HP Z600。我已经在 BIOS 中启用了所有虚拟化、VT-d 等。
我的问题是,如果我通过 4 端口上的一个 NIC,则第 12 组中的任何内容都无法供主机访问,包括我用来连接它的内部 NIC。
本节非常有用,提供了有关如何编辑内核命令行的一些基础知识 https://pve.proxmox.com/pve-docs/chapter-sysadmin.html#sysboot_edit_kernel_cmdline
蛴螬
内核命令行需要放在GRUB_CMDLINE_LINUX_DEFAULT
文件中的变量中/etc/default/grub
。运行update-grub
会将其内容附加到 /boot/grub/grub.cfg 中的所有 linux 条目中。
Systemd 启动
内核命令行需要放在一行中/etc/kernel/cmdline
。要应用更改,请运行proxmox-boot-tool refresh
[不确定如果没有 Proxmox 会用到什么],它会将其设置为 loader/entries/proxmox-*.conf 中所有配置文件的选项行。
然后,此页面给出了有关 PCI Passthrough 的一些详细信息,主要关注 Proxmox,但原理应该仍然相同: https://pve.proxmox.com/wiki/PCI_Passthrough
这个视频对我帮助最大!并且非常实用,能够全面地指导您完成整个过程。它针对的是特定实现,但可以使用上面和下面的信息完成显示的所有内容
https://www.youtube.com/watch?v=qQiMMeVNw-o&ab_channel=SpaceinvaderOne
最后,我不记得从哪里得到它,但这是一个非常有用的命令,可以识别所有设备的所有 IOMMU 组(以 root 身份运行):
for d in $(find /sys/kernel/iommu_groups/ -type l | sort -n -k5 -t/); do n=${d#*/iommu_groups/*}; n=${n%%/*}; printf 'IOMMU Group %s ' "$n"; lspci -nns "${d##*/}"; done;
对我来说,我最初GRUB_CMDLINE_LINUX_DEFAULT="quiet"
我启用了基本 IOMMUGRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on"
这给了我:
IOMMU Group 12 00:1c.0 PCI bridge [0604]: Intel Corporation 82801JI (ICH10 Family) PCI Express Root Port 1 [8086:3a40]
IOMMU Group 12 00:1c.5 PCI bridge [0604]: Intel Corporation 82801JI (ICH10 Family) PCI Express Root Port 6 [8086:3a4a]
IOMMU Group 12 01:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme BCM5764M Gigabit Ethernet PCIe [14e4:1684] (rev 10)
IOMMU Group 12 1c:00.0 PCI bridge [0604]: Microsemi / PMC / IDT PES12T3G2 PCI Express Gen2 Switch [111d:8061] (rev 01)
IOMMU Group 12 1d:02.0 PCI bridge [0604]: Microsemi / PMC / IDT PES12T3G2 PCI Express Gen2 Switch [111d:8061] (rev 01)
IOMMU Group 12 1d:04.0 PCI bridge [0604]: Microsemi / PMC / IDT PES12T3G2 PCI Express Gen2 Switch [111d:8061] (rev 01)
IOMMU Group 12 1e:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 12 1e:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 12 1f:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 12 1f:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
我删除了除我感兴趣的组 12 之外的所有内容。您可以看到 NIC 的 4 个端口,还有另一个 NIC,即板载 NIC。不幸的是,如果我通过一个 NIC,则主机无法访问组 12 中的任何内容。
我发现了一种将网卡一分为二的工作机制,使用GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on pcie_acs_override=downstream"
这给了我
IOMMU Group 12 00:1c.0 PCI bridge [0604]: Intel Corporation 82801JI (ICH10 Family) PCI Express Root Port 1 [8086:3a40]
IOMMU Group 13 00:1c.5 PCI bridge [0604]: Intel Corporation 82801JI (ICH10 Family) PCI Express Root Port 6 [8086:3a4a]
IOMMU Group 18 1c:00.0 PCI bridge [0604]: Microsemi / PMC / IDT PES12T3G2 PCI Express Gen2 Switch [111d:8061] (rev 01)
IOMMU Group 19 1d:02.0 PCI bridge [0604]: Microsemi / PMC / IDT PES12T3G2 PCI Express Gen2 Switch [111d:8061] (rev 01)
IOMMU Group 20 1d:04.0 PCI bridge [0604]: Microsemi / PMC / IDT PES12T3G2 PCI Express Gen2 Switch [111d:8061] (rev 01)
IOMMU Group 21 1e:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 21 1e:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 22 1f:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 22 1f:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet [14e4:1639] (rev 20)
IOMMU Group 23 01:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme BCM5764M Gigabit Ethernet PCIe [14e4:1684] (rev 10)
您可以看到它将 4 端口 NIC 分成了 2 对,并且都不与板载 NIC 组成一个组。我怀疑每对都在卡上的同一总线上(请原谅我使用这个术语),所以这可能是我能得到的最小分割(我确实尝试过其他机制,例如,如视频中所述隔离一个或多个桥接器,但它们比上面的更糟糕)。
希望这对遇到同样问题的人有帮助。