vfio-pci是内核驱动,网卡和NVME盘等设备就可以使用这个驱动,使用vfio-pci就会调用到vfio-pci的probe。 vfio-pci和mdev-vfio的probe都调用vfio_add_group_dev添加自己的ops,同时生成一个dev,qemu通过/dev/vfio获取这个dev,再操作这个dev时就调用到vfio-pci /vfio/81/dev vfio group不是凭空造出的一个概念,vfio group和IOMMU硬件的group紧密相关,所以vfio还有一个重要的函数就是vfio_register_iommu_driver qemu调用内核vfio,irqbypass用于把vfio和kvm连接起来。 vfio_msi_enable->vfio_enable_vectors(qemu代码)->vfio_pci_set_irqs_ioctl(内核vfio代码)->vfio_pci_set_msi_trigger
传输层(软件仿真Nvme盘) 图片 SPDK IPU K8S结合: 图片 VFIO-USER简介 VFIO-USER 是一种协议,允许在虚拟机监视器 (VMM) 之外的单独进程中模拟设备。 ▪ VFIO-USER 规范主要基于 Linux VFIO ioctl 接口,以将其实现为通过 UNIX 域套接字发送的消息。 ▪ VFIO-USER 有两个部分: • VFIO-USER 客户端在 VMM 或应用程序中运行。 • VFIO-USER 服务器用于在单独进程中模拟设备。 */ enum vfio_user_device_mig_state { VFIO_USER_DEVICE_STATE_ERROR = 0, VFIO_USER_DEVICE_STATE_STOP = 1, VFIO_USER_DEVICE_STATE_RUNNING = 2, VFIO_USER_DEVICE_STATE_STOP_COPY = 3, VFIO_USER_DEVICE_STATE_RESUMING
vfio-pci是内核驱动,网卡和NVME盘等设备就可以使用这个驱动,使用vfio-pci就会调用到vfio-pci的probe。 vfio-pci和mdev-vfio的probe都调用vfio_add_group_dev添加自己的ops,同时生成一个dev,qemu通过/dev/vfio获取这个dev,再操作这个dev时就调用到vfio-pci /vfio/81/dev vfio group不是凭空造出的一个概念,vfio group和IOMMU硬件的group紧密相关,所以vfio还有一个重要的函数就是vfio_register_iommu_driver qemu调用内核vfio,irqbypass用于把vfio和kvm连接起来。 vfio_msi_enable->vfio_enable_vectors(qemu代码)->vfio_pci_set_irqs_ioctl(内核vfio代码)->vfio_pci_set_msi_trigger
容器/组/设备的关 VFIO与PCI关系 Qemu/容器/组/设备间的数据结构关系 组/IOMMU/容器/IOMMU域/VFIO_PCI设备间的数据结构关系 VFIO内核源码分析 加载vfio-pci模块 modprobe vfio-pci enable_sriov=1 -> module_init(vfio_pci_init) -> vfio/pci:将 pci_driver 代码从 vfio_pci_core.c _vfio_alloc_device vfio_init_device(device, dev, ops) -> vfio:添加统一 vfio_device 生命周期的帮助程序,其想法是让 > vfio:为 vfio_device 添加 cdev,这会添加对 vfio_device 的 cdev 支持。 ("vfio") -> /dev/vfio/$GROUP alloc_chrdev_region(&vfio.group_devt, 0, MINORMASK + 1, "vfio")
主要研究VFIO在虚拟化中的应用,但VFIO的应用不止于虚拟化. VFIO的全称是Virtual Function IO,但这个名字并不能反应它的特点,以下两个假名字更能反应VFIO的特点: Very Fast IO 由于VFIO是将设备直接透传给虚拟机,所以Guest 上使用VFIO,需要将该group下的所有device与其对应的驱动解绑. ---- VFIO Container 在IOMMU_GROUP的基础上,VFIO封装了一层Container Class,Container 虚拟化中VFIO的应用 这里演示一个将网卡设备利用VFIO透传到虚拟机中的例子.需要注意的是,利用VFIO将PCI设备透传到虚拟机之后,Host将无法使用该设备. 要使用VFIO,必须在Linux启动时添加启动项intel_iommu=on,因为VFIO的底层依赖IOMMU.
在内核源码中代码路径为:drivers\vfio\vfio.c。 VFIO_DEVICE_GET_IRQ_INFO:得到设备的中断信息 VFIO_DEVICE_RESET:重置设备 下图展示了用户态app,内核态VFIO, vfio-pci驱动,VFIO IOMMU 1)vfio 驱动分析 在vfio.ko驱动加载和卸载的时候会执行vfio_init(),vfio_cleanup()函数。 :将vfio_group 和vfio_iommu 绑定 VFIO_GROUP_UNSET_CONTAINER:将vfio_group 和vfio_iommu 解绑定 VFIO_GROUP_GET_DEVICE_FD 通过对vfio驱动框架中的vfio_container,vfio_iommu, vfio_group, vfio_device, vfio_pci的分析,可以看出如下操作调用关系: 图4 VFIO驱动框架通信接口
" >> /etc/modules root@pve:~# echo "vfio_iommu_type1" >> /etc/modules root@pve:~# echo "vfio_pci" >> # Generated by sensors-detect on Fri Sep 24 17:22:44 2021 # Chip drivers coretemp vfio vfio_iommu_type1 vfio_pci vfio_virqfd 复制代码 接着添加模块(驱动)黑名单,即让GPU设备在下次系统启动之后不使用这些驱动,把设备腾出来给vfio驱动用: Intel核显: echo "blacklist vfio_pci 57344 1 vfio_virqfd 16384 1 vfio_pci irqbypass 16384 11 vfio_pci,kvm vfio_iommu_type1 36864 1 vfio 36864 5 vfio_iommu_type1,vfio_pci
现在Intel和NVIDIA的GPU虚拟化方案都是采用的VFIO mediated passthrough framework。 Linux4.10内核中对VFIO添加了Mediated Device(vfio-mdev) Interface,用来支持Intel GVT-g, NVIDIA vGPU,并提供统一的框架。 Intel和NVDIA采用的VFIO mediated passthrough方式不依赖硬件IOMMU,只需要VFIO模块添加type1 IOMMU的驱动。 VFIO mediated passthrough的性能损耗主要在MMIO的模拟,而AMD的SRIOV方案,VM中对vGPU的MMIO访问完全没有虚拟化开销。 而VFIO mediated passthrough可以通过Host端对vGPU性能指标进行监控,因为VM对GPU的访问要绕道Host端。
因为我们想要把VGA设备透传到虚拟机中,首先我们需要将设备从物理机上分离(可能分离的 说法并不准确,暂且这么认为),实现的方法是将设备使用的默认驱动禁用,然后将设备加入到vfio模块,让设备使用vfio 如果出现该问题,请检查每个设备的使用的驱动是否已经是vfio。 vfio_pci#下面的内容也是参考网上的配置,有可能不需要pci_stubvfiovfio_iommu_type1kvmkvm_intel配置vfio加载的设备配置使用vfio驱动的设备(这里的设备就是上面我们查到的设备的 模块是否加载dmesg | grep -i vfio[root@ostack-nmcs-001-026 ~]# dmesg | grep -i vfio [ 5.365031] VFIO - User driver in use: vfio-pci注:如果有设备的驱动不是vfio,可能会导致报错:Please ensure all devices within the iommu_group are
internal->vfio_container_fd = rte_vfio_container_create() internal->vfio_group_fd = rte_vfio_container_group_bind pci_rte_vfio_setup_device pci_vfio_setup_interrupts vfio_enable_msi = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area 内核设置中断集, 设置硬件中断回调函数 vfio_msihandler case VFIO_DEVICE_SET_IRQS vfio_pci_ioctl_set_irqs(vdev fd, 并通过VFIO接口设置到内核态: vdpa_enable_vfio_intr -> VFIO_DEVICE_SET_IRQS, 内核VFIO申请硬件中断, 并设置中断回调:vfio_msihandler
中的vfio-pic是一个简易符合VFIO框架PCIe驱动。 3.1.2 VFIO VFIO(Virtual Function I/O)是基于IOMMU为HostOS的用户空间暴露PCIe设备的配置空间和DMA。 VFIO的组成主要有以下及部分,见图3.1.2.1: 图3.1.2.1 l VFIO Interface: VFIO通过设备文件向用户空间提供统一访问接口: • Container文件描述符:打开/dev /vfio字符设备可得 • IOMMU group文件描述符:打开/dev/vfio/N文件可得 • Device文件描述符:向IOMMU group文件描述符发起相关ioctl可得 l vfio_iommu_type1 l vfio-pci: vfio支持pci设备直通时以vfio-pci作为pci设备驱动挂载到pci总线, 将pci设备io配置空间、中断暴露到用户空间。
" >> /etc/modules root@pve:~# echo "vfio_iommu_type1" >> /etc/modules root@pve:~# echo "vfio_pci" >> # Generated by sensors-detect on Fri Sep 24 17:22:44 2021 # Chip drivers coretemp vfio vfio_iommu_type1 vfio_pci vfio_virqfd 接着添加模块(驱动)黑名单,即让GPU设备在下次系统启动之后不使用这些驱动,把设备腾出来给vfio驱动用: Intel核显: echo "blacklist vfio_pci 57344 1 vfio_virqfd 16384 1 vfio_pci irqbypass 16384 11 vfio_pci,kvm vfio_iommu_type1 36864 1 vfio 36864 5 vfio_iommu_type1,vfio_pci
L2-3 英伟达案例:VFIO模式 VFIO 场景 图解释了为何在虚拟机中使用 NVMe Express® 配合 虚拟功能 I/O (VFIO 模式): 高性能 I/O当虚拟机配置为需要最高性能时,通常会使用直接设备访问 VFIO 和 SR-IOV 技术有什么区别? 1. VFIO (Virtual Function I/O) 定义VFIO 是一种驱动程序架构,用于允许虚拟机直接访问物理设备,通常通过 PCIe 设备的 Passthrough 方式。 VFIO 模式使虚拟机变成一个用户空间驱动程序,直接与设备通信,从而实现低延迟和高带宽。 2. 图讨论了 VFIO NVM Express® 实时迁移 的实现过程: 支持实时迁移包括创建 vfio-nvme 实现,该实现支持 VFIO 实时迁移的有限状态机 (FSM)。
先把硬件网卡passthrough给虚拟机,然后在虚拟机中把网卡绑定内核模块igb_uio,问题是igb_uio的代码没有upstream,依赖于内核版本,提前编译好的内核模块换个版本就不能运行,就想着用vfio-pci vfio-pci内核模块的probe函数返回了错误: [51376781.097090] vfio-pci: probe of 0000:00:06.0 failed with error -22 static = PCI_HEADER_TYPE_NORMAL) return -EINVAL; group = vfio_iommu_group_get(&pdev->dev); if (! group) return -EINVAL; ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); if (ret) { vfio_iommu_group_put 这和虚拟机中DPDK用不用vfio-pci没关系。
重启 proxmox 主机验证IOMMU是否启用待服务器启动后,登录服务器验证IOMMU是否启用:dmesg | grep -E "DMAR|IOMMU"验证并 配置VFIO验证VFIO模块:dmesg A] [# 添加PCI设备echo "options vfio-pci ids=10de:1e07 disable_vga=1" > /etc/modprobe.d/vfio.conf] (rev a1 :# 添加PCI设备echo "options vfio-pci ids=10de:1e07 disable_vga=1" > /etc/modprobe.d/vfio.conf注意请一定注意这里的将设备 Id添加到vfio.conf操作。 **,如果未显示则需要执行 验证并配置VFIO部分。
,qemu参数-device vfio-pci,host=b1:00.0,最终也调用了iommu的代码domain_pfn_mapping。 vfio_iommu_type1_ioctl └─vfio_dma_do_map └─vfio_pin_map_dma └─vfio_iommu_map /i40e都调用到了函数domain_pfn_mapping,相比于kvm和vfio,i40e多了一个if判断,条件是函数iommu_no_mapping的返回值。 补充 kvm一定要用intel_iommu=on,DPDK/SPDK如果绑定vfio-pci那也一定要求intel_iommu=on,如果绑定uio/igb_uio那么就不需要intel_iommu=on ,推荐都用vfio-pci,后面kvm中的pci-assign,DPDK/SPDK用到的igb_uio都得淘汰。
GRUB_CMDLINE_LINUX_DEFAULT=”quiet intel_iommu=on video=efifb:off,vesafb:off” update-grub vi /etc/modules 添加 vfio vfio_iommu_type1 vfio_pci vfio_virqfd vi /etc/modprobe.d/blacklist.conf 添加 vfio vfio_iommu_type1 vfio_pci vfio_virqfd echo “options vfio-pci ids=[igpu vender id],[声卡 vender id]” > /etc/modprobe.d/vfio.conf 如果是J3455的机子直接操作这行 echo “options vfio-pci ids=8086:5a85,8086:5a98” > /etc/modprobe.d/vfio.conf 8086:5a98 这是集成声卡 如果是其他CPU自行去用lspci -n -s XX:XX查看XX:XX先用lspci查看 update-initramfs -u 以上是前期准备工作 echo “options vfio_iommu_type1
的感觉,vfio只能处理pci通用结构和流程,vfio-mdev处理那些硬件实现不了sr-iov功能的设备,也就是硬件不能模拟出pci标准结构的哪些硬件,vfio-mdev给虚拟机假象以为自己独占硬件, 站在另一个角度考虑,vfio没有vhost中关于virtio的ioctl实现,vdpa两者都需要,如果qemu用了viommu,vhost也得支持viommu,vhost迟早得添加地址转换的ioctl, vhost和vfio ioctl结合在一起用的,都没能成功upstream代码。 已经和vdpa没什么关系了,又回到vfio,好处就是虚拟机加速和裸金属统一了。 总结 device emulation花样百出,新想法层出不穷,例如我的文章中从来没有提起过的vfio-user和muser,总之技术发展太快,刹也刹不住,感觉自己已经赶不上时代的脚步了。
先把硬件网卡passthrough给虚拟机,然后在虚拟机中把网卡绑定内核模块igb_uio,问题是igb_uio的代码没有upstream,依赖于内核版本,提前编译好的内核模块换个版本就不能运行,就想着用vfio-pci vfio-pci内核模块的probe函数返回了错误: [51376781.097090] vfio-pci: probe of 0000:00:06.0 failed with error -22 static = PCI_HEADER_TYPE_NORMAL) return -EINVAL; group = vfio_iommu_group_get(&pdev->dev); if (! group) return -EINVAL; ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); if (ret) { vfio_iommu_group_put 这和虚拟机中DPDK用不用vfio-pci没关系。
在PVE的shell中输入: nano /etc/modules 在文件下面添加新内容 vfio vfio_iommu_type1 vfio_pci vfio_virqfd 编辑完文件后按“Ctrl