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