Cloud Hypervisor VFIO-user 设备接入指南:socket 化的用户态 PCI 设备与热插拔实践
【免费下载链接】cloud-hypervisorA Virtual Machine Monitor for modern Cloud workloads. Features include CPU, memory and device hotplug, support for running Windows and Linux guests, device offload with vhost-user and a minimal compact footprint. Written in Rust with a strong focus on security.项目地址: https://gitcode.com/GitHub_Trending/cl/cloud-hypervisor
VFIO-user 是一种实验性协议,它允许 PCI 设备在独立进程中实现,并通过 Unix socket 与虚拟机监控器通信——类比来说,VFIO-user 之于 VFIO,正如 vhost-user 之于 virtio。本文基于 Cloud Hypervisor 官方文档docs/vfio-user.md,结合仓库源码(vmm/src/config.rs、vmm/src/device_manager.rs、cloud-hypervisor/src/bin/ch-remote.rs)完整讲解--user-device参数的配置语法、GPIO 与 NVMe 两个真实设备示例,以及热插拔与已知限制,读完即可在本地复现两种 vfio-user 设备接入场景。
VFIO-user 与 Cloud Hypervisor 的支持现状
VFIO-user 协议允许设备实现者把 PCI 设备的配置空间、MMIO BAR 与 DMA 全部封装进另一个用户态进程中,VMM 只需连接该进程暴露的 socket 即可把设备"挂"到 guest 的 PCI 总线上。这样做的好处是设备模型与 VMM 完全解耦,设备可以独立开发、独立部署,甚至可以复用 SPDK 等成熟生态中已有的设备实现。
Cloud Hypervisor 对这一协议的支持目前仍是实验性的,且存在明确的功能边界:
- 不支持 virtio-mem(内存热插拔类设备无法以 vfio-user 形式接入);
- 不支持 iommu:源码中
UserDeviceConfig::validate()会直接对设置了iommu的配置返回ValidationError::IommuNotSupported(见 vmm/src/config.rs)。
这意味着 vfio-user 设备目前适用于直通式、无 IOMMU 隔离场景的 PCI 外设模拟(如 GPIO、NVMe 控制器、网络控制器等)。
使用方法:创建时挂载与运行中热插拔
vfio-user 设备有两条接入路径:
- VM 创建时静态挂载:使用启动参数
--user-device socket=<path>; - 运行中热插拔:使用
ch-remote add-user-device socket=<path>,通过 HTTP APIPUT /vm.add-user-device动态加入(该端点定义见 vmm/src/api/http/mod.rs,对应 OpenAPI 定义见 vmm/src/api/openapi/cloud-hypervisor.yaml)。
参数完整语法与源码解析
--user-device在 CLI 定义中支持重复出现(num_args(1..)+ArgAction::Append,见 cloud-hypervisor/src/main.rs),即一个 VM 可以挂载多个 vfio-user 设备。其完整语法在源码中声明为(见 vmm/src/config.rs):
--user-device socket=<socket_path>,id=<device_id>,pci_segment=<segment_id>,pci_device_id=<pci_slot>各字段含义与约束如下:
| 参数 | 是否必选 | 说明 |
|---|---|---|
socket | 必选 | vfio-user 设备进程监听的 Unix socket 路径。缺失时parse()会返回ParseUserDeviceSocketMissing错误(vmm/src/config.rs) |
id | 可选 | 设备标识符,用于后续设备管理与去重校验(validate_identifier保证 id 全局唯一,见 vmm/src/config.rs) |
pci_segment | 可选 | 设备所在 PCI 段号 |
pci_device_id | 可选 | 设备在 PCI 总线上的槽位号(BDF 中的 device 号) |
其中id、pci_segment、pci_device_id是PciDeviceCommonConfig的通用 PCI 选项(见 vmm/src/config.rs)。
内存要求:必须共享内存
使用 vfio-user 设备时,guest 内存必须开启共享。源码校验逻辑为:只要配置了 user devices 且内存未开启共享,就返回ValidationError::UserDevicesRequireSharedMemory(见 vmm/src/config.rs)。原因在于 vfio-user 设备进程需要通过共享内存直接访问 guest 物理内存以完成 DMA 读写。因此无论哪个示例,启动参数都必须包含:
--memory size=1G,shared=on示例一:接入 libvfio-user 的 GPIO 设备
libvfio-user 仓库自带一个简单的 GPIO 设备示例(gpio-pci-idio-16),适合作为第一个上手实验:它演示了 vfio-user 的最小闭环——设备进程监听 socket、VMM 连接、guest 内驱动访问。
第 1 步:运行设备进程
rm /tmp/vfio-user.sock ./build/dbg/samples/gpio-pci-idio-16 -v /tmp/vfio-user.sock &先删除可能残留的旧 socket 文件,再以 verbose 模式把 GPIO 设备进程挂在/tmp/vfio-user.sock上。
第 2 步:启动 Cloud Hypervisor
target/debug/cloud-hypervisor \ --memory size=1G,shared=on \ --disk path=~/images/focal-server-cloudimg-amd64.raw,image_type=raw \ --kernel ~/src/linux/vmlinux \ --cmdline "root=/dev/vda1 console=hvc0" \ --user-device socket=/tmp/vfio-user.sock注意--memory必须带shared=on(原因见上文);--user-device的 socket 路径要与设备进程的监听路径完全一致。
第 3 步:在 guest 内验证设备
启动后,guest 内核会枚举到该 GPIO 控制器(gpiochip480)。导出并读取引脚状态:
cat /sys/class/gpio/gpiochip480/base > /sys/class/gpio/export for ((i=0;i<12;i++)); do cat /sys/class/gpio/OUT0/value; done第一条命令把 GPIO 控制器的基础编号写入 export 导出设备;循环依次读取 12 路输出(OUT0)的当前电平值,验证 guest 与用户态设备进程之间的 MMIO/DMA 通路是否正常工作。
示例二:用 SPDK 提供 NVMe 控制器
SPDK(Storage Performance Development Kit)原生支持 vfio-user,可以把一个 AIO 块设备封装成 NVMe 控制器暴露给 Cloud Hypervisor,从而为 guest 提供一块基于用户态 NVMe 协议的磁盘。这是 vfio-user 在真实存储场景中最典型的用法。
第 1 步:编译带 vfio-user 支持的 SPDK
./configure --with-vfio-user第 2 步:准备后端块设备并启动 NVMe-oF target
sudo scripts/setup.sh rm ~/images/test-disk.raw truncate ~/images/test-disk.raw -s 128M mkfs.ext4 ~/images/test-disk.raw sudo killall ./build/bin/nvmf_tgt sudo ./build/bin/nvmf_tgt -i 0 -e 0xFFFF -m 0x1 & sleep 2 sudo ./scripts/rpc.py nvmf_create_transport -t VFIOUSER sudo rm -rf /tmp/nvme-vfio-user sudo mkdir -p /tmp/nvme-vfio-user sudo ./scripts/rpc.py bdev_aio_create ~/images/test-disk.raw test 512 sudo ./scripts/rpc.py nvmf_create_subsystem nqn.2019-07.io.spdk:cnode -a -s test sudo ./scripts/rpc.py nvmf_subsystem_add_ns nqn.2019-07.io.spdk:cnode test sudo ./scripts/rpc.py nvmf_subsystem_add_listener nqn.2019-07.io.spdk:cnode -t VFIOUSER -a /tmp/nvme-vfio-user -s 0 sudo chown $USER.$USER -R /tmp/nvme-vfio-user这段脚本逐步完成:创建 128M 的 raw 测试盘并格式化为 ext4 → 以指定 CPU 亲和性启动nvmf_tgt→ 创建 VFIOUSER 传输类型 → 用 AIO 后端把测试盘注册为名为test的 bdev → 创建 NVMe 子系统并添加命名空间 → 在/tmp/nvme-vfio-user目录上添加 VFIOUSER 监听器 → 最后把 socket 目录的所有权还给当前用户,否则 Cloud Hypervisor 进程无法连接。监听器最终会生成/tmp/nvme-vfio-user/cntrl这个控制 socket。
第 3 步:启动 Cloud Hypervisor
target/debug/cloud-hypervisor \ --memory size=1G,shared=on \ --disk path=~/images/focal-server-cloudimg-amd64.raw,image_type=raw \ --kernel ~/src/linux/vmlinux \ --cmdline "root=/dev/vda1 console=hvc0" \ --user-device socket=/tmp/nvme-vfio-user/cntrlguest 内会枚举出一块 NVMe 磁盘(通常为/dev/nvme0n1),可正常分区、格式化与读写。SPDK bdev 的更多配置选项与 NVMe-oF target 的详细设置,分别对应 SPDK 官方文档中的 bdev 与 nvmf 两节,可按需查阅。
运行机制与源码级补充说明
- 设备添加流程:VM 启动时,
DeviceManager::add_user_devices()会遍历配置中的所有UserDeviceConfig,逐个调用add_vfio_user_device()创建设备(见 vmm/src/device_manager.rs)。设备以 PCI 设备形式挂到总线上,因此同样受id唯一性与 PCI 资源分配约束。 - socket 冲突检查:热插拔时若目标 socket 已被某设备占用,会返回
DeviceManagerError::UserDeviceSocketInUse,避免同一 socket 被重复使用(见 vmm/src/device_manager.rs)。 - 测试覆盖:仓库集成测试中包含对
add-user-device热插拔路径的验证(见 cloud-hypervisor/tests/integration.rs),可作为复现与排查问题的参考。
已知限制与注意事项
- 实验性特性:协议与 Cloud Hypervisor 侧实现均处于实验阶段,API 与行为可能随版本演进变化;
- 不支持 iommu:配置中不得设置
iommu选项,否则启动校验直接失败; - 不支持 virtio-mem:内存热插拔类场景无法使用 vfio-user 设备;
- 必须
shared=on:缺少共享内存配置将导致启动校验失败; - socket 生命周期:必须先启动设备进程并确保 socket 就绪,再启动 Cloud Hypervisor;清理环境时需先删除残留 socket 文件。
总结
通过--user-device与ch-remote add-user-device,Cloud Hypervisor 可以在创建 VM 时或运行中以热插拔方式接入基于 vfio-user 协议的用户态 PCI 设备。本文给出的 GPIO 示例用于验证最小通路,SPDK NVMe 示例则展示了如何将成熟的用户态存储栈以 NVMe 控制器形式接入 guest。若希望在项目中使用该特性,请先对照本文的"已知限制"评估适用性,并确保使用支持shared=on的共享内存配置。
【免费下载链接】cloud-hypervisorA Virtual Machine Monitor for modern Cloud workloads. Features include CPU, memory and device hotplug, support for running Windows and Linux guests, device offload with vhost-user and a minimal compact footprint. Written in Rust with a strong focus on security.项目地址: https://gitcode.com/GitHub_Trending/cl/cloud-hypervisor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考