bhyve PCI Passthrough快速起步

我在构建 FreeBSD云计算虚拟化bhyve 时,需要构建一个 Machine Learning 工作环境:

  • NVIDIA GPUAMD GPU 通过 IOMMU 技术实现PCI Passthrough 给 Linux bhybe 虚拟机

  • 模拟出不同的GPU分布集群(单机多卡,多机多卡)

在FreeBSD中bhyve支持将host主机上的CPI设备透传给虚拟机使用:

  • CPU必须支持Intel IOMMU (也称为 VT-d )

  • PCI设备(和驱动)支持 MSI/MSI-x 中断

通过搜索ACPI表的DMAR表可以获知是否支持Host VT-d:

DMAR表
acpidump -t | grep DMAR

在我的组装台式机上可以看到如下输出:

DMAR表输出
  DMAR: Length=168, Revision=1, Checksum=169,

备注

如果 DMAR 输出内容是空白,则表明不支持 Intel VT-d ,例如Intel Atom处理器在这项检查输出就是空白的( Not working with pci passthru )

通过 pciconf 可以查看PCI卡的 MSI/MSI-x 支持:

通过 pciconf 查看PCI卡的 MSI/MSI-x 支持
pciconf -lc | grep MSI

在我的组装台式机上可以看到如下输出:

通过 pciconf 查看PCI卡的 MSI/MSI-x 支持
    cap 05[90] = MSI supports 1 message
    cap 05[90] = MSI supports 1 message
    cap 05[ac] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 8 messages, 64 bit enabled with 1 message
    cap 05[8c] = MSI supports 1 message, 64 bit
    cap 05[80] = MSI supports 1 message enabled with 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[80] = MSI supports 1 message
    cap 05[60] = MSI supports 1 message, 64 bit enabled with 1 message
    cap 05[a0] = MSI supports 1 message, 64 bit
    cap 05[a0] = MSI supports 1 message, 64 bit
    cap 05[a0] = MSI supports 1 message, 64 bit
    cap 11[d0] = MSI-X supports 9 messages, enabled
    cap 05[e0] = MSI supports 8 messages, 64 bit
    cap 05[50] = MSI supports 1 message, 64 bit, vector masks
    cap 11[70] = MSI-X supports 5 messages, enabled
    cap 05[50] = MSI supports 1 message, 64 bit, vector masks
    cap 11[70] = MSI-X supports 5 messages, enabled
    cap 05[50] = MSI supports 1 message, 64 bit, vector masks
    cap 11[70] = MSI-X supports 5 messages, enabled
    cap 05[50] = MSI supports 1 message, 64 bit, vector masks
    cap 11[70] = MSI-X supports 5 messages, enabled
    cap 11[d0] = MSI-X supports 9 messages, enabled
    cap 05[e0] = MSI supports 8 messages, 64 bit

配置

  • 确保 vmm.ko/boot/loader.conf 配置中设置:

配置启动时加载模块 vmm.ko (已经在 bhyve快速起步 设置)
echo 'vmm_load="YES"' >> /boot/loader.conf
echo 'nmdm_load="YES"' >> /boot/loader.conf
echo 'if_tap_load="YES"' >> /boot/loader.conf
echo 'if_bridge_load="YES"' >> /boot/loader.conf
  • 使用 pciconf -vl 检查需要pass through 设备的 bus/slot/function :

通过 pciconf 获取设备信息
pciconf -vl

我需要传递的设备是 AMD Radeon Instinct MI50 (和 Nvidia Tesla P10 GPU运算卡 ) :

通过 pciconf 获取设备信息
...
vgapci0@pci0:1:0:0:	class=0x030200 rev=0xa1 hdr=0x00 vendor=0x10de device=0x1b39 subvendor=0x10de subdevice=0x1217
    vendor     = 'NVIDIA Corporation'
    device     = 'GP102GL [Tesla P10]'
    class      = display
    subclass   = 3D
...
pcib3@pci0:2:0:0:	class=0x060400 rev=0x01 hdr=0x01 vendor=0x1002 device=0x14a0 subvendor=0x0000 subdevice=0x0000
    vendor     = 'Advanced Micro Devices, Inc. [AMD/ATI]'
    class      = bridge
    subclass   = PCI-PCI
pcib4@pci0:3:0:0:	class=0x060400 rev=0x00 hdr=0x01 vendor=0x1002 device=0x14a1 subvendor=0x1002 subdevice=0x14a1
    vendor     = 'Advanced Micro Devices, Inc. [AMD/ATI]'
    class      = bridge
    subclass   = PCI-PCI
vgapci1@pci0:4:0:0:	class=0x038000 rev=0x01 hdr=0x00 vendor=0x1002 device=0x66a1 subvendor=0x1002 subdevice=0x0834
    vendor     = 'Advanced Micro Devices, Inc. [AMD/ATI]'
    device     = 'Vega 20 [Radeon Pro VII/Radeon Instinct MI50 32GB]'
    class      = display
...

这里根据输出 vgapci0@pci0:4:0:0 可以知道这个 AMD Radeon Instinct MI50bus/slot/function 值为 4/0/0 (以及 Nvidia Tesla P10 GPU运算卡1/0/0 )

  • 在操作系统启动时,需要对Host主机屏蔽掉需要直通的PCI设备,这个设置时通过 pptdevs 参数完成的,如果有多个设备需要屏蔽,则使用空格来分隔设备列表:

设置屏蔽的直通的PCI设备( /boot/loader.conf ) 这里仅屏蔽 AMD Radeon Instinct MI50
pptdevs="4/0/0"

如果屏蔽上述2个设备( ref:amd_radeon_instinct_mi50Nvidia Tesla P10 GPU运算卡 ),则写成:

设置屏蔽的直通的PCI设备( /boot/loader.conf ) 这里同时屏蔽 AMD Radeon Instinct MI50 Nvidia Tesla P10 GPU运算卡
pptdevs="1/0/0 4/0/0"

注意,每行 pptdevs 只支持最多 128 个字符,所以如果有更多的直通设备需要配置的画,可以使用 pptdevN 来设置,例如 pptdevs2

  • 重启操作系统,再次检查 pciconf -vl 就会看到原先设备 vgapci0 变成了 ppt (这里看到的是 ppt0@pci0:1:0:0ppt0@pci0:4:0:0 )类似如下:

重启系统后检查 pptdevs 设备的开头会变成 ppt
...
ppt0@pci0:1:0:0:	class=0x030200 rev=0xa1 hdr=0x00 vendor=0x10de device=0x1b39 subvendor=0x10de subdevice=0x1217
    vendor     = 'NVIDIA Corporation'
    device     = 'GP102GL [Tesla P10]'
    class      = display
    subclass   = 3D
...
ppt1@pci1:4:0:0:	class=0x038000 rev=0x01 hdr=0x00 vendor=0x1002 device=0x66a1 subvendor=0x1002 subdevice=0x0834
    vendor     = 'Advanced Micro Devices, Inc. [AMD/ATI]'
    device     = 'Vega 20 [Radeon Pro VII/Radeon Instinct MI50 32GB]'
    class      = display
设置 fedora 虚拟机使用这个passthru设备
bhyve -c 2 -m 4G -w -H -S \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zroot/vms/fedora \
-s 5,virtio-net,tap1 \
-s 7,passthru,1/0/0 \
-s 29,fbuf,tcp=0.0.0.0:5901,w=800,h=600,wait \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
fedora

异常排查

当我使用了 -s 7,passthru,1/0/0 出现 passthru requires guest memory to be wired 报错

  • 必须向 bhyveloadbhyve 传递 -S 参数来 wire guest memory ,否则启动会报错:

如果 bhyve 没有使用 -S 参数会报错
bhyve: passthru requires guest memory to be wired
Device emulation initialization error: No such file or directory
  • 添加了 -S 运行参数后,提示报错:

提示setup memory错误
Unable to setup memory (17)

参考 bhyve PCI pass-through to Linux guest 提示: 不仅需要给 bhyve 传递 -S 参数,还需要给 grub-bhyve 传递 -S 参数

这个问题有点难搞,我发现只要添加 -S 参数来实现 wire guest memory 就会提示

提示setup memory错误
Unable to setup memory (17)

如果此时还调整虚拟机的内存大小,例如原先是 2G 改成 8G ,则同样报 setup memory 错误,但是错误码却是 22 :

提示setup memory错误
Unable to setup memory (22)

该怎么改进这个配置呢?我对比了 Using bhyve on FreeBSD 大致明白了思路:

  • 修订 /etc/remote 添加一个针对虚拟机的控制台访问配置,这样就可以不使用VNC而直接使用字符终端

  • 为虚拟机创建一个 device.map 文件来指示 grub-bhyve ,并且可以通过 grub-bhyve 来设置虚拟机的内存和传递参数(例如需要传递 -S 参数来wrap内存

解决

  • 创建远程终端配置,即修订 /etc/remote :

创建终端配置
# 为名为 fedora 的虚拟机创建终端配置
echo 'fedora:dv=/dev/nmdb0B:br#9600:pa=none:' >> /etc/remote
  • 创建针对每个虚拟机的 device.map 文件,以 <vm_name>.map 命名,存放在 /zroot/vms/<vm_name> 目录下:

fedora 虚拟机创建 /zroot/vms/fedora/fedora.map
(hd0) /dev/zvol/zroot/vms/fedora
(cd0) /home/admin/Fedora-Server-dvd-x86_64-42-1.1.iso

参考