设备直通是一种虚拟化资源分配方式,通过将物理设备直通给虚拟机环境,达到虚拟机可以直接访问物理设备的目的,直通功能对设备的要求不高,不需要设备支持PF/VF,18年后的普通家用PC的PCI设备都支持设备直通模式,今天来探索一下它的玩法。
实践平台
环境安装
1.安装QEMU虚拟机环境以及虚拟机管理工具环境:
sudo apt-get install qemu-kvm qemu-system libvirt-bin bridge-utils virt-manager
2.默认BIOS中已经ENABLE了CPU虚拟化和设备虚拟化能力,所以这一步操作忽略。
3.Enable PCI IOMMU,参考如下文章:
Linux ion&dma-buf&iommu的原理_papaofdoudou的博客-CSDN博客
4.确认需要穿透的pci设备和设备号,我们透传的设备如下图所示,Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller。
透传设备的地址BDF为:00000:03:00.0,设备ID为168c:0036.
设置HOST机上的PCI设备
HOST端通过如下命令查看PCI设备信息
virsh nodedev-list --tree
首先在HOST端将PCI以太网卡设备解绑,将其驱动从默认的r8169切换为vfio-pci,这个过程中,主机的以太网络连接会中断,不过没有关系,主机上还有另外一个集成的无线网卡。
执行如下命令查看当前设备信息:
$ virsh nodedev-dumpxml pci_0000_02_00_0
从设备信息中看到,设备驱动是r8169,设备的IOMMU分组是9。
查看IOMMU分组信息确实如此,分组为9
下一步在HOST对设备解绑
$ virsh nodedev-detach pci_0000_02_00_0
解绑后,主机以太网卡功能已经失能,需要连接无线网卡。
此时我们需要加载内核的VFIO模块,由于默认UBUNTU18.04内核已经将vfio.ko,vfio-pci.ko两个模块builtin到内核中,所以这一步操作系统已经帮我们做了,不需要其它操作。
针对以太网卡设备使能VFIO驱动
执行如下命令,将系统的VENDOR和PRODUCT ID作为输入,写入vfio-pci/new_id节点,使能VFIO驱动,bind to vfio-pci Driver.
echo 10ec 8168 > /sys/bus/pci/drivers/vfio-pci/new_id
执行后,再次查看设备信息,会发现其驱动已经从r8196切换为vfio-pci:
确认IOMMU分组,在没有加载vfio-pci驱动时,/dev/vfio/9是不存在的。
至此,HOST端的配置已经结束,可以安装虚拟机了。
安装虚拟机
虚拟机的安装除了要注意下图上的操作之外,其它无需多讲,参考这篇博客即可:
CPU虚拟化技术及QEMU/KVM虚拟机安装实践_qemu集群_papaofdoudou的博客-CSDN博客
虚拟机中透传PCI设备
同时可以看到主机上的以太网被WIFI网络代替,而虚拟机中可以直接使用透传后的以太网,网卡设备和HOST时的设备完全相同,因为本身它们就是同一个设备。
qemu可以脱离virt-manager GUI使用,我们看一下实际的QEMU命令是怎样的,以及透传参数有哪些?在HOST机上查看:
核心的参数有下面几个:
-smp 4 -m 2048
-enable-kvm -name guest=ubuntu18.04-2
-drive file=/var/lib/libvirt/images/ubuntu18.04-2.qcow2
-device vfio-pci,host=02:00.0,id=hostdev0,bus=pci.0,addr=0x8
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x9
我们手动启动一下:
-device vfio-pci,host=02:00.0,id=hostdev0,bus=pci.0,addr=0x8 表示将HOST机上BDF为02:00.0的PCI设备(网卡)透传给虚拟机,并且分配设备号为8,BUS为0,同时在虚拟机上创建一个balloon0设备,设备BUS为0,SLOT为9。
sudo qemu-system-x86_64 -smp 4 -m 2048 -enable-kvm -name guest=ubuntu18.04-2 -drive file=/var/lib/libvirt/images/ubuntu18.04-2.qcow2 -device vfio-pci,host=02:00.0,id=hostdev0,bus=pci.0,addr=0x8 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x9
可以看到,和使用virt-manager界面启动虚拟机类似,用纯粹的QEMU命令行启动的虚拟机同样包含了透传进来的网卡设备,BUS为0,SLOT为8,同时存在一个虚拟设备 balloon,BUS为0,SLOT为9,和命令行参数设置吻合。
HOST机的DMESG输出
其它
如果两台虚拟机透传同一个PCI设备,则在安装第二台虚拟机的时候,会提示设备冲突,这说明PASS-THROUGH的设备是一个独占资源,无法在多个虚拟机之间共享。
vfio.ko/vfio-pci.ko
默认情况下,vfio和vfio-pci两个模块是builtin进内核的,也可以选择编译成模块的形式安装:
安装:
用自定义的内核将VFIO编译成模块进行上面的实验:
参考文章
linux iommu group分析&整理_papaofdoudou的博客-CSDN博客
CPU虚拟化技术及QEMU/KVM虚拟机安装实践_qemu集群_papaofdoudou的博客-CSDN博客
ubuntu以passthrough方式直通pci设备(fpga)到kvm虚拟机(华硕主板)_virsh nodedev-dumpxml_sbbbbbbbbbbbbb的博客-CSDN博客
提升KVM异构虚拟机启动效率:透传(pass-through)、DMA映射(VFIO、PCI、IOMMU)、virtio-balloon、异步DMA映射、预处理