ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

[virtio](八):vhost-user 与独立用户态数据面

2026/8/5 15:16:37 拓冰建站 浏览量
[virtio](八):vhost-user 与独立用户态数据面 第七篇讨论了 virtio-net 和 vhost-net。本篇继续看 vhost-user如果 virtio 数据面不在 QEMU也不在 host kernel而是在另一个用户态进程里QEMU 如何把 guest memory、virtqueue 和 eventfd 交给它1. vhost-user 解决什么问题vhost-kernel 把数据面下沉到 host kernel。vhost-user 则把数据面交给一个独立的用户态 backend process。典型场景是高性能网络例如 DPDK 相关后端。模型如下QEMU process | | vhost-user protocol over Unix socket v vhost-user backend process | v high-performance packet processing它的目标是让数据面独立演进让 backend 使用 DPDK/SPDK 等用户态高性能框架避免 QEMU 主循环处理高频数据包在 QEMU 之外部署专门的 I/O backend代价是系统结构更复杂。2. vhost-user 与 vhost-kernel 的区别vhost-kernelQEMU | | ioctl to kernel vhost device v host kernel vhost backendvhost-userQEMU | | Unix socket messages v user-space backend process二者都接管 virtqueue 数据面。区别在于 backend 运行位置不同。vhost-kernel 适合利用内核网络栈和 tap。vhost-user 适合独立用户态包处理、DPDK、用户态存储后端或定制数据面。3. QEMU 仍然是控制面即使使用 vhost-userQEMU 仍然负责 virtio 设备控制面。包括创建设备暴露 transportfeature negotiationdevice statusqueue setupresetmigration coordination管理接口与 backend 建立连接vhost-user backend 处理的是数据面。结构是QEMU control plane | | vhost-user protocol v backend data plane这和 vhost-net 的思想一致只是 backend 从 kernel 变成了另一个用户态进程。4. vhost-user 协议传什么QEMU 和 vhost-user backend 通过 Unix socket 交换控制消息。常见信息包括feature bitsprotocol feature bitsguest memory regionsvring addressesvring sizekick eventfdcall eventfdqueue enable statebackend configurationmigration/inflight state其中 guest memory region 和 vring 信息最关键。backend 要直接处理 guest virtqueue就必须知道guest physical address 如何映射到 backend 可访问的 host virtual address descriptor table 在哪里 avail ring 在哪里 used ring 在哪里 kick/call eventfd 是哪些5. guest memory 如何共享给 backendvhost-user backend 是独立进程。它不能天然访问 QEMU 进程中的 guest RAM。因此 QEMU 需要通过协议把 guest memory region 描述和文件描述符传给 backend。常见方式是基于共享内存 fd。抽象模型QEMU owns guest RAM mappings | | send memory region metadata fd v vhost-user backend maps same memory | v backend can access virtqueue and packet buffers这一步非常敏感。如果 memory table 错误backend 解析 descriptor 时就无法正确访问 guest buffer。6. vring 如何交给 backendGuest 配置 virtqueue 后QEMU 知道 vring 的地址和大小。QEMU 会通过 vhost-user 协议告诉 backendqueue index queue size descriptor table address avail ring address used ring addressbackend 拿到这些信息后就可以像 QEMU 或 vhost-kernel 一样解析 descriptor chain。路径是Guest writes descriptors | v virtqueue in guest RAM | v vhost-user backend maps memory and reads vring | v backend processes I/OQEMU 不再逐个解析高频 descriptor。7. kick 和 call eventfdvhost-user backend 还需要通知机制。QEMU 会把 eventfd 传给 backend。kick fd: guest - backend有新 descriptor call fd: backend - guest有 completion完整路径Guest updates avail ring | | kick eventfd v vhost-user backend wakes | v backend processes descriptors | | call eventfd v KVM injects interrupt / QEMU handles notify | v Guest sees completion如果配置了 irqfdcompletion 可以更快进入 guest interrupt injection 路径。8. vhost-user-net 的典型场景vhost-user-net 常见于 DPDK 场景。结构类似Guest virtio-net driver | v virtqueue in guest RAM | v vhost-user socket | v DPDK backend process | v physical NIC / userspace switch数据包可以在用户态网络栈中高速处理减少传统内核网络栈和 QEMU 主循环开销。常见后端可以是OVS-DPDKVPP自定义 DPDK 程序用户态虚拟交换机9. vhost-user 的复杂度vhost-user 的灵活性来自进程解耦。但复杂度也来自进程解耦。需要处理的问题包括backend 进程生命周期socket 重连feature 兼容memory region 更新queue 启停顺序migration 协调backend 崩溃恢复安全隔离NUMA 和 hugepage placement如果 backend 崩溃QEMU 需要决定 VM 如何表现。如果 memory mapping 不一致backend 可能读错 guest buffer。如果 migration 时 backend 状态没保存target 恢复后可能丢包或 queue 卡住。10. vhost-user 与迁移vhost-user 迁移比基础 QEMU device model 更复杂。因为设备状态分散在 QEMU 和 backend 中。迁移时需要pause or quiesce backend data plane | v collect virtqueue state and inflight descriptors | v serialize QEMU virtio state | v coordinate backend state | v restore on target | v reconnect or start target backend | v resume queues如果存在 in-flight packet 或 request需要确保它不会丢失或重复完成。这也是 vhost-user protocol feature 和 backend migration 能力重要的原因。11. vhost-user 的安全边界vhost-user backend 能访问 guest memory 中的 virtqueue 和 data buffer。这意味着它处在敏感边界上。安全设计需要考虑backend 进程权限shared memory 范围fd 传递sandboxingbackend 输入验证descriptor 合法性检查guest 和 backend 之间的隔离vhost-user 并不因为在用户态就天然安全。它获得了高性能访问能力也承担了正确解析 guest 提供数据结构的责任。12. 源码阅读入口本篇可以看hw/virtio/vhost-user.chw/virtio/vhost.cinclude/hw/virtio/vhost.hinclude/hw/virtio/vhost-user.hhw/net/vhost_net.cnet/vhost-user.cdocs/interop/vhost-user.rst阅读问题QEMU 如何连接 vhost-user socketmemory region 如何发送给 backendvring address 如何设置kick/call eventfd 如何传递backend feature 如何协商backend 启停和 reset 如何处理migration 相关状态如何协调13. 本篇小结vhost-user 把 virtio 数据面交给独立用户态 backend。QEMU 通过 Unix socket 把 guest memory、vring、eventfd、feature 和 queue 状态传递给 backend。backend 直接处理 guest virtqueueQEMU 保留控制面和迁移编排。可以把本篇压缩成一句话vhost-user 用进程边界换取数据面灵活性让 virtio backend 可以独立优化但也把 memory sharing、queue state、迁移和故障恢复变成必须认真处理的系统问题。14. 下一篇预告virtio 设备迁移状态下一篇讨论 migration。会回答virtio 迁移为什么不只是复制 guest RAMqueue index、feature、config 和 pending interrupt 如何保存in-flight request 如何处理vhost backend 如何配合迁移下一篇的问题可以写成一台 VM 迁移到 target host 后guest driver 为什么还能相信 virtio 设备只是暂停了一下