QEMU 可组合 SR-IOV 设备Composable SR-IOV完整指南基于 virtio-net-pci 的 PF/VF 组建与配置【免费下载链接】qemuOfficial QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website.项目地址: https://gitcode.com/gh_mirrors/qe/qemu导读本文以 QEMU 官方文档 docs/system/sriov.rst 为主线系统讲解 QEMU 中可组合 SR-IOV 设备Composable SR-IOV device的概念、组建规则与完整命令行配置方案。通过阅读本文你将掌握如何用多个virtio-net-pci设备手动组装出一套带物理功能PF与虚拟功能VF的 SR-IOV 网卡理解sriov-pf属性的语义、PF/VF 在总线上的摆放约束以及如何在内核侧激活 VF实现虚拟机 I/O 软件开销的消除。一、SR-IOV 与可组合设备背景与定位SR-IOVSingle Root I/O Virtualization单根 I/O 虚拟化是 PCI Express 设备的一种可选扩展能力Extended Capability。它的核心思想是让一个物理功能Physical FunctionPF对外表现为多个虚拟功能Virtual FunctionVF从而把虚拟机 I/O 路径上的软件模拟开销交给硬件直通承担——每个 VF 可以直接分配给一台虚拟机绕过中间的软件转发层。按照官方文档的表述SR-IOV 允许单个物理功能PF表现为多个虚拟功能VF主要目的在于消除虚拟机 I/O 中的软件开销。在 QEMU 生态中存在两类 SR-IOV 设备预定义 SR-IOV 配置的设备设备自带固定的 VF 数量、BAR 布局等 SR-IOV 能力用户只能按预设方式使用例如 NVMe 控制器的 SR-IOV 支持详见 docs/system/devices/nvme.rst可组合 SR-IOV 设备用户自己动手把多个 PCI 功能拼成一个带 PF/VF 关系的 SR-IOV 设备。本文聚焦第二种。官方文档明确说明可组合 SR-IOV 设备目前仅由virtio-net-pci支持其能力开关在源码中对应sriov_vf_user_creatable字段——virtio-net-pci.c 中将k-sriov_vf_user_creatable true;正是这一标志开启了用户可创建 VF的能力而 pcie_sriov.c 在注册设备时会检查该标志不支持的设备类型会直接报错user cannot create SR-IOV VF with this device type。二、组建方式与完整命令行示例可组合 SR-IOV 设备的组建思路是把若干virtio-net-pci设备挂到同一条 PCIe 总线上其中一台充当 PF通过id标识其余通过sriov-pf属性声明自己属于哪个 PF。官方文档给出的完整示例如下-netdev user,idn -netdev user,ido -netdev user,idp -netdev user,idq -device pcie-root-port,idb -device virtio-net-pci,busb,addr0x0.0x3,netdevq,sriov-pff -device virtio-net-pci,busb,addr0x0.0x2,netdevp,sriov-pff -device virtio-net-pci,busb,addr0x0.0x1,netdevo,sriov-pff -device virtio-net-pci,busb,addr0x0.0x0,netdevn,idf拆解这条命令行可以看到组建的四个要素四个 user 模式网络后端n/o/p/q分别为四个网卡功能提供网络连接一个 PCIe Root Portpcie-root-port,idb作为承载 PF/VF 的 PCIe 总线——SR-IOV 是 PCIe 扩展能力因此必须挂在 PCIe 总线上源码中pcie_sriov_register_device会校验pci_is_express(dev)非 PCIe 设备直接报错PCI Express is required for SR-IOV VF三台 VF 设备addr0x0.0x1~addr0x0.0x3各自通过sriov-pff指定所属 PF并分别绑定netdevo/p/q一台 PF 设备addr0x0.0x0idf绑定netdevn。最终在 guest 中idf这台virtio-net-pci会呈现为一个带 SR-IOV 扩展能力的 PF其余三台则是它的 VF。三、sriov-pf属性PF 与 VF 的绑定机制virtio-net-pci之所以能认出彼此靠的是sriov-pf这个字符串属性。该属性定义于通用 PCI 设备层 pci.cDEFINE_PROP_STRING(sriov-pf, PCIDevice, sriov_pf),DEFINE_PROP_STRING意味着它接收一个设备 idqdev id而不是总线地址。属性值必须与 PF 设备的id完全一致示例中为f。VF 设备在注册时pcie_sriov_register_device见 pcie_sriov.c会依次校验该设备类型是否允许用户创建 VFsriov_vf_user_creatable标志是否为 PCIe 设备通过pci_qdev_find_device查找sriov-pf指向的 PF 是否真实存在不存在则报错PCI device specified as SR-IOV PF already exists错误信息沿用自该函数的历史文案实际含义为指定的 PF 设备未能找到/存在冲突。所有指向同一 PF 的 VF 会被收集进一张哈希表按 PF 的 id 索引值为 VF 指针数组当 PF 本身完成初始化时再由pcie_sriov_pf_init_from_user_created_vfs统一吸收这些 VF 并推导出 SR-IOV 能力所需的参数。四、组建规则顺序、函数号与步长约束官方文档明确了三条用户必须自行保证的规则它们并非可选项而是源码中的硬性校验规则 1PF 必须最后添加。命令行里 PFidf出现在所有 VF 之后。这是因为 QEMU 需要先收集齐所有 VF才能在 PF 初始化时一次性生成 SR-IOV 扩展能力结构若 PF 先于 VF 注册哈希表中找不到对应的 VF 集合组建将不成立。规则 2VF 的函数号function number必须大于 PF且步长stride一致。在 pcie_sriov.c 的pcie_sriov_pf_init_from_user_created_vfs中首先按devfn对 VF 排序compare_vf_devfns若第一个 VF 的devfn PF 的 devfn直接报错a VF function number is less than the PF function number由vf_offset vfs[0]-devfn - dev-devfn、vf_stride vfs[1]-devfn - vfs[0]-devfn推导偏移与步长逐一校验vfs[i]-devfn - vfs[0]-devfn ! vf_stride * i时报错inconsistent SR-IOV stride。也就是说示例中 0.0x0PF、0.0x1、0.0x2、0.0x3 这种函数号逐 1 递增的布局正是满足规则的标准写法。规则 3PF 与 VF 必须在同一总线、同厂商 ID、同设备 ID且 BAR 布局一致。同样在该函数中逐项校验 VF 的父总线与 PF 一致SR-IOV VF parent bus mismatches with PF、厂商 ID 一致SR-IOV VF vendor ID mismatches with PF、所有 VF 设备 ID 一致inconsistent SR-IOV VF device IDs、各 VF 的PCI_NUM_REGIONS个 I/O 区域大小与类型一致inconsistent SR-IOV BARs。这些一致性校验保证了组合出来的 VF 在 guest 侧具有统一、可预测的 PCI 配置空间。五、ARI 与 255 个 VF 上限官方文档指出PF 与 VF 均为 ARIAlternative Routing-ID Interpretation替代路由 ID 解释能力设备因此最多可拥有 255 个 VF。ARI 允许设备使用全部 8 位函数号0255其中 0 为 PF其余 255 个可作 VF而无须受每槽 8 功能的传统限制。这一特性在源码中由 QEMU 自动补齐pcie_sriov_pf_init_from_user_created_vfs在构建 SR-IOV 扩展能力时会检查 PF 是否已有 ARI 能力若没有则调用pcie_ari_init自动添加见 pcie_sriov.c。因此用户无需手动为 PF/VF 声明 ARI 能力只需确保函数号布局满足上文规则即可。六、PF 初始化与 VF 的底层联动当 PF 设备完成实例化时pcie_sriov.c 的pcie_sriov_pf_init_from_user_created_vfs会执行完整组装流程从哈希表取出该 PF 名下的全部 VF排序推导vf_offset第一个 VF 相对 PF 的函数号偏移与vf_strideVF 间函数号间隔只有 1 个 VF 时为 0逐项完成上文所述的一致性校验调用pcie_sriov_pf_init_common写入 SR-IOV 扩展能力含 VF 数量、VF 偏移、VF 步长、TotalVFs 等字段为这些用户创建的 VF 设置vf_user_created true并依据第一个 VF 的 BAR 布局初始化 VF BAR。此后这些 VF 的状态由register_vfs/unregister_vfspcie_sriov.c管理guest 通过写入 SR-IOV 控制寄存器PCI_SRIOV_CTRL的VFE位来启用/禁用 VFQEMU 据此在 PF 下挂载或卸载对应的 VF 设备——这正是 guest 内核执行sriov_numvfs写入时触发的一整套硬件仿真动作。PF 复位pcie_sriov_pf_reset时则会清零 VF 使能并注销全部 VF。七、guest 侧激活以 Linux 为例QEMU 侧的配置只是第一步guest 内还需要额外步骤才能真正看见并启用 VF。官方文档指向 Linux 内核的 PCI IOV HowTo其核心操作流程与仓库中 NVMe SR-IOV 文档 docs/system/devices/nvme.rst 所述一致为在 guest 内确认 PF 已枚举例如出现在/sys/bus/pci/devices/0000:01:00.0/写入期望的 VF 数量以启用 VFecho N /sys/bus/pci/devices/0000:01:00.0/sriov_numvfsN 不超过 PF 声明的最大 VF 数本例即 3 或更少关闭 VF 时写回 0echo 0 .../sriov_numvfs若内核未开启 IOMMU 或未加载相应驱动需先确认vfio-pci、iommu等内核配置就绪否则 VF 可能无法直通给其他虚拟机。需要注意QEMU 侧组合出的 VF 数量上限是 255受 ARI 函数号空间限制但实际能启用的 VF 数量还受 guest 内核、驱动与直通方案如 vfio的约束这是两个不同层面的限制。八、延伸仓库中其他 SR-IOV 方案速览可组合 SR-IOV 是 QEMU 支持 SR-IOV 的一种方式仓库中还存在预定义 SR-IOV 配置的实现可作为对照参考NVMe 控制器docs/system/devices/nvme.rst通过nvme设备属性sriov_max_vfs、sriov_vq_flexible、sriov_vi_flexible、sriov_max_vi_per_vf、sriov_max_vq_per_vf配置 SR-IOV 与 ARI 能力需要搭配nvme-subsys子系统设备使用属于设备自带 SR-IOV 能力、用户仅调参数的模型IGB 网卡hw/net/igb.c 与 hw/net/igbvf.cigb 设备的 VF 仿真与 igbvf 对应是仓库中另一处 SR-IOV 相关实现。与可组合模型不同这些方案由设备实现内部管理 VF用户无需手工拼装多个设备实例。九、总结与排错要点可组合 SR-IOV 设备把如何布局 SR-IOV 能力的决定权交给了用户让 virtio-net 场景下的 PF/VF 拓扑可以灵活编排。实践中需要重点牢记规则要求源码校验点hw/pci/pcie_sriov.c设备类型仅virtio-net-pci支持用户创建 VFsriov_vf_user_creatable检查L370总线类型必须挂在 PCIe 总线上如 pcie-root-portpci_is_express检查L375添加顺序PF 必须最后添加VF 哈希表收集逻辑L385-L396函数号VF 函数号必须大于 PFdevfn比较L286步长VF 间函数号步长必须一致inconsistent SR-IOV strideL319一致性总线 / 厂商 ID / 设备 ID / BAR 布局一致逐项校验L296-L317VF 上限ARI 能力下最多 255 个 VFARI 自动初始化L330如果启动 QEMU 时报错优先对照上表排查PF 是否最后添加、sriov-pf是否与 PF 的id完全一致、VF 函数号是否严格递增且步长统一、所有virtio-net-pci是否都在同一 PCIe 总线上。按本文示例的布局模板即可快速搭建一套可用的可组合 SR-IOV virtio-net 设备并在 guest 内通过sriov_numvfs完成 VF 的启用与直通。【免费下载链接】qemuOfficial QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website.项目地址: https://gitcode.com/gh_mirrors/qe/qemu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
