![在 Ubuntu 主机上绑定/解除绑定 PCI 设备](https://linux22.com/image/771427/%E5%9C%A8%20Ubuntu%20%E4%B8%BB%E6%9C%BA%E4%B8%8A%E7%BB%91%E5%AE%9A%2F%E8%A7%A3%E9%99%A4%E7%BB%91%E5%AE%9A%20PCI%20%E8%AE%BE%E5%A4%87.png)
我必须主机上的 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 传递到KVM
ubuntu 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 关闭时恢复以前的状态。
如果您在虚拟机启动之前不对驱动程序绑定进行任何操作,它应该会执行您想要的操作。