在 Ubuntu 主机上绑定/解除绑定 PCI 设备

在 Ubuntu 主机上绑定/解除绑定 PCI 设备

我必须主机上的 NIC 设备:

# list Ethernet PCI devices to find out names
lspci -nn | grep Ethernet
# 04:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 06)
# 05:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 15)

# to get <domain>.<bus>.<slot>.<function>
lspci -n -s 0000:04:00.0
# 04:00.0 0200: 10ec:8168 (rev 06)

我想将设备 0000:04:00.0 传递到KVMubuntu 20.04 虚拟机。虚拟机运行时,主机可能看不到此设备。为了将 PCI NIC 绑定到客户机,我成功地按照说明操作VFIO——“虚拟功能 I/O”.但从客人到主人的束缚却变得更加困难。

我通过以下方式手动将主机的 NIC 设备绑定到客户机:

# find Ethernet controller
ls -l /sys/class/net/ | grep pci
# enp3s0 -> ../../devices/pci0000:00/0000:00:1c.5/0000:03:00.0/net/enp3s0
# enp4s0 -> ../../devices/pci0000:00/0000:00:1c.7/0000:04:00.0/net/enp4s0
lspci -nn | grep Ethernet
# 04:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 06)
# 05:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 15)

# check the IOMMU grouping
for a in /sys/kernel/iommu_groups/*; do find $a -type l; done | sort --version-sort | grep '04:00\|05:00'
# /sys/kernel/iommu_groups/12/devices/0000:04:00.0
# /sys/kernel/iommu_groups/13/devices/0000:05:00.0

# find MAC addresses
for eth in enp4s0 enp5s0; do ifconfig $eth | grep ether | echo "MAC" "$eth:" $(awk '{print $2}'); done
# MAC enp4s0: 50:...
# MAC enp5s0: 18:...

# load the vfio-pci device driver
modprobe vfio_pci

# unbind from host
echo 0000:04:00.0 | sudo tee /sys/bus/pci/devices/0000:04:00.0/driver/unbind
# make available for guests
echo 10ec 8168 | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id

# IOMMU group for device 0000:04:00.0 is 12
# add libvirt-qemu to sudoers
sudo usermod -aG sudo libvirt-qemu
sudo chown libvirt-qemu:libvirt-qemu /dev/vfio/12

# look at what other devices are in the group to free it for use by VFIO
ls -l /sys/bus/pci/devices/0000:04:00.0/iommu_group/devices | awk '{print $9 $10 $11}'
# 0000:04:00.0->../../../../devices/pci0000:00/0000:00:1c.5/0000:04:00.0
# also add other devices if they belong to the same group (not needed in this case)

# make sure the device is not visible from host
ls -l /sys/class/net/ | grep enp4s0

然后我使用以下命令创建了新的 Ubuntu 20.04 VM虚拟机管理器(virt-manager)继续运行虚拟机

我在创建过程中通过编辑 xml 配置将新设备添加到虚拟机virt-manager。具体来说,<devices>该部分包含以下标签

 <hostdev mode="subsystem" type="pci" managed="yes">
   <driver name="vfio"/>
   <source>
     <address domain="0x0000" bus="0x04" slot="0x00" function="0x0"/>
   </source>
   <mac address='50:...'/>
   <address type="pci"> 
     <zpci uid="0x0001" fid="0x00000000"/>
   </address>
 </hostdev>

然后我以常规方式安装了 Ubuntu 20.04。系统正常重启,没有死锁(黑屏)。

当我关闭虚拟机时,我想将 PCI NIC 返回给主机。我在论坛上进行了研究,但没有关于如何执行此操作的明确说明。

如果我重新启动主机,所有设备都会返回到主机,因此 vfio 绑定将被释放。但是如何在不重新启动主机的情况下做到这一点。

答案1

要手动执行此操作,您可以使用与主机解除绑定相同的方法,以使其可供虚拟机使用。

像这样的事情应该做

echo 0000:04:00.0 | sudo tee /sys/bus/pci/devices/0000:04:00.0/driver/unbind
echo 10ec 8168 | sudo tee /sys/bus/pci/drivers/<host-driver-here>/new_id

您需要知道要将设备重新绑定到哪个主机驱动程序,为此您可以使用

 lspci -n -v -s 0000:04:00.0

重新启动后,查找“正在使用的内核驱动程序:”行,您将在那里找到驱动程序的名称

答案2

libvirt为您执行必要的解除绑定和重新绑定,并且显然它还在 VM 关闭时恢复以前的状态。

如果您在虚拟机启动之前不对驱动程序绑定进行任何操作,它应该会执行您想要的操作。

相关内容