bhyve PCI Passthrough快速起步
我在构建 FreeBSD云计算虚拟化bhyve 时,需要构建一个 Machine Learning 工作环境:
- 将 NVIDIA GPU 和 AMD 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:
acpidump -t | grep 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配置中设置:
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 MI50 的 bus/slot/function 值为 4/0/0 (以及 Nvidia Tesla P10 GPU运算卡 为 1/0/0 )
- 在操作系统启动时,需要对Host主机屏蔽掉需要直通的PCI设备,这个设置时通过 - pptdevs参数完成的,如果有多个设备需要屏蔽,则使用空格来分隔设备列表:
/boot/loader.conf ) 这里仅屏蔽 AMD Radeon Instinct MI50pptdevs="4/0/0"
如果屏蔽上述2个设备( ref:amd_radeon_instinct_mi50 和 Nvidia Tesla P10 GPU运算卡 ),则写成:
/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:0和- ppt0@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
- 现在就在虚拟机中使用这个设备了,添加 - -s 7,passthru,1/0/0(假设这里使用 Nvidia Tesla P10 GPU运算卡 ) 类似如下:
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 报错
- 必须向 - bhyveload和- bhyve传递- -S参数来- wire guest memory,否则启动会报错:
bhyve 没有使用 -S 参数会报错bhyve: passthru requires guest memory to be wired
Device emulation initialization error: No such file or directory
- 添加了 - -S运行参数后,提示报错:
Unable to setup memory (17)
参考 bhyve PCI pass-through to Linux guest 提示: 不仅需要给 bhyve 传递 -S 参数,还需要给 grub-bhyve 传递 -S 参数
这个问题有点难搞,我发现只要添加 -S 参数来实现 wire guest memory 就会提示
Unable to setup memory (17)
如果此时还调整虚拟机的内存大小,例如原先是 2G 改成 8G ,则同样报 setup memory 错误,但是错误码却是 22 :
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