VirtIO 与 vHost 深度实战:半虚拟化 I/O 的内核实现与云原生虚拟化性能革命

在云计算基础设施中,虚拟机与宿主机之间的 I/O 路径是决定整体性能的关键因素。全虚拟化方案(如 QEMU 模拟 e1000 网卡)每包需要多次 VM Exit,吞吐难以突破 1Gbps。VirtIO 通过半虚拟化架构将 I/O 吞吐量提升了一个数量级,而 vHost 进一步将数据路径下沉到内核态,配合 DPDK/SPDK 用户态驱动,将单虚机网络吞吐推至 100Gbps 级别。本文从协议规范、内核实现到生产调优,完整拆解这套云原生虚拟化的 I/O 基石。

一、虚拟化 I/O 的性能鸿沟

1.1 全虚拟化的陷阱

在 KVM/QEMU 的经典架构中,Guest OS 发出的每一条特权指令都会触发 VM Exit,CPU 从 Non-Root Mode 切换到 Root Mode,由 KVM 接管处理。全虚拟化模拟的 e1000 网卡在收到数据包时,一次完整的 RX 处理需要经过:

Guest 发起 PIO/MMIO 写操作
        ↓
VM Exit(约 1000-3000 个 CPU 周期)
        ↓
KVM 识别退出原因并分发到 QEMU
        ↓
QEMU 用户态进程模拟 e1000 硬件状态机
        ↓
QEMU 将数据包写入 tap 设备 → 进入宿主机内核网络栈
        ↓
Guest 收到中断(再次 VM Exit 注入虚拟中断)

实测数据显示,纯 QEMU 模拟 e1000 在 1500B 包长下吞吐仅约 600Mbps-1Gbps,小包场景(64B)更是不足 100Mbps。每次 VM Exit 的上下文保存/恢复、寄存器访问、以及 QEMU 进程调度带来的缓存污染,共同构成了难以逾越的性能天花板。

1.2 Hardware Assist:从 VT-x 到 SR-IOV

Intel VT-x/AMD-V 通过在硬件层面引入 VMX Root/Non-Root 模式,将 VM Exit 的开销降低到约 500-800 周期,但无法消除 Exit 本身。SR-IOV(Single Root I/O Virtualization) 通过物理网卡的硬件虚拟化能力,将 PCIe 物理功能(PF)划分为多个虚拟功能(VF),每个 VF 直通给 Guest 独占使用,实现了接近物理机的性能。

但 SR-IOV 代价高昂:

  • 需要支持 SR-IOV 的物理网卡(价格显著高于普通网卡)
  • 丧失了热迁移(Live Migration)能力——VF 绑定在物理硬件上
  • 资源粒度粗:一个 PF 的 VF 数量有限(通常 64-128 个)
  • 安全隔离依赖 IOMMU,配置复杂度高

1.3 半虚拟化:VirtIO 的折中哲学

半虚拟化(Paravirtualization) 的核心思想简单而深刻:与其费力"欺骗"Guest 让它以为在操作真实硬件,不如直接告诉 Guest:"你运行在虚拟机中,请使用这套高效的共享内存协议"。

VirtOS 由 IBM 研究院的 Rusty Russell 在 2008 年设计,现由 OASIS 标准组织维护。其核心优势:

维度全虚拟化 (e1000)SR-IOVVirtIO
吞吐(1500B)~1Gbps~线速5-20Gbps
小包 PPS~100K~线速~5M
热迁移✅❌✅
零硬件成本✅❌✅
Guest 需改内核❌❌✅
延迟(RTT)>100μs<10μs20-50μs

二、VirtIO 协议架构深度拆解

2.1 设备抽象层:PCI 传输 vs MMIO 传输

VirtIO 定义了两种与 Guest 的传输方式:

PCI 传输:在 x86 虚拟机中,VirtOS 设备呈现为一个 PCI 设备,通过 PCI BAR(Base Address Register)暴露寄存器空间。Guest 内核通过 MMIO/PIO 读写这些寄存器完成设备配置。

MMIO 传输:在 ARM/嵌入式场景中,VirtOS 设备通过平台总线(platform bus)暴露 MMIO 寄存器内存区域,无需 PCI 子系统参与。

现代 Linux 内核的 `drivers/virtio/` 目录实现了统一的 virtio 核心层,上层驱动(`virtio_net`、`virtio_blk`、`virtio_scsi`、`virtio_fs` 等)只关注协议语义,传输细节由底层 `virtio_pci` 或 `virtio_mmio` 模块封装。

2.2 Virtqueue:共享内存环形队列

VirtIO 的数据传输核心是 Virtqueue(简称 VQ)——一段由 Guest 分配、Guest 和 Host 双方均可直接访问的连续物理内存区域,分为三个环形缓冲区结构:

┌────────────────────────────────────────────────────────────┐
│                    Virtqueue Layout                         │
├──────────────────┬──────────────────┬─────────────────────┤
│ Descriptor Table │ Available Ring   │ Used Ring            │
│ (间接描述符数组)   │ (可用的请求队列)  │ (完成的请求队列)      │
│ 大小: desc_size  │ 大小: num * 2    │ 大小: num * 8        │
│ 对齐要求: 2字节   │ 对齐要求: 2字节   │ 对齐要求: 4字节      │
└──────────────────┴──────────────────┴─────────────────────┘

Descriptor Table:包含 `num` 个 16 字节的描述符,每个描述符定义了一块 Guest 物理内存区域的地址和长度:

struct vring_desc {
    __le64 addr;    /* Guest 物理地址 */
    __le32 len;     /* 内存块长度 */
    __le16 flags;   /* VRING_DESC_F_NEXT / VRING_DESC_F_WRITE / VRING_DESC_F_INDIRECT */
    __le16 next;    /* 下一个描述符索引(链式连接) */
};

Available Ring:驱动程序将要提交给设备的 descriptor 头索引放入此环形缓冲区。包含:

struct vring_avail {
    __le16 flags;              /* VRING_AVAIL_F_NO_INTERRUPT */
    __le16 idx;                /* 驱动写入的位置 */
    __le16 ring[num];          /* descriptor head 索引数组 */
    __le16 used_event;         /* 仅 VIRTIO_F_EVENT_IDX */
};

Used Ring:设备处理完请求后将结果写回此环形缓冲区:

struct vring_used {
    __le16 flags;
    __le16 idx;
    struct vring_used_elem ring[num];  /* { id, len } */
        __le32 id;     /* descriptor chain head */
        __le32 len;    /* 设备写入的总字节数 */
    __le16 avail_event;    /* 仅 VIRTIO_F_EVENT_IDX */
};

2.3 间接描述符(Indirect Descriptors)

默认情况下,一条 descriptor chain 中的每个 buffer 对应一个 vring_desc 表项。当一条 I/O 请求需要大量散集/聚集(scatter-gather)buffer 时,descriptor table 可能不够用。

VirtIO 引入了间接描述符机制:一个 vring_desc 项的 `flags` 包含 `VRING_DESC_F_INDIRECT`,其 `addr` 指向一个独立的间接表(Secondary Descriptor Table),该间接表可以容纳 `desc` 个额外的描述符:

__le32 desc[][4];  /* 二级间接描述符表,每个条目 16 字节 */

这对 virtio-blk 的多段 scatter-gather I/O 和 virtio-net 的 TSO/UFO 大包卸载至关重要——单次 I/O 可以跨越上千个物理 page。

2.4 通知机制:VIRTIO_NOTIFICATION 的两种模式

Guest 告知 Host "有新请求待处理"的方式:

  • Notification:驱动写 `Queue Notify` 地址(MMIO/PIO),触发 VM Exit 通知 QEMU 或 Host 内核
  • VIRTIO_F_DEVICE_STATS (VirtIO 1.2+):通过共享内存的更新,减少通知时的 VM Exit

Device 告知 Host "I/O 完成"的方式:

  • 中断注入:Host 通过 irqfd 向 Guest 注入虚拟中断,触发 VM Exit(在高速场景下是主要瓶颈)
  • VIRTIO_F_EVENT_IDX:驱动和驱动各自维护 `avail_event`/`used_event`,仅在超过阈值时才通知,这是中断抑制的关键手段

三、virtio-net 数据包路径

3.1 RX 流程:从物理网卡到 Guest 应用

物理网卡 (物理设备)
    ↓ 写入 tap 设备
宿主机内核桥 (linux bridge / ovs)
    ↓ tap 设备可读事件
QEMU 线程 (在 virtio 模式):
    ↓ qemu_set_irq() → irqfd
        → KVM 注入中断到 vCPU
Guest 内核 virtio-net 中断处理 (NAPI)
    ↓ virtnet_poll() 收包
        → napi_gro_receive()
Guest 网络栈 → socket → 应用

QEMU 侧的实际代码流程(以 `vhost-net` 模式为例):

// QEMU 在 vhost-net 模式下不再亲自移动数据
// 而是配置 vhost 内核模块直接在 Host 内核内转发
// QEMU 仅负责中断注入和配置管理

// 传统的 QEMU 路径(纯 virtio 模式):
virtio_net_handle_rx()                        // 收到 Tap 事件
  → virtio_net_flush_rx()                     // 刷新 RX vq
    → virtqueue_pop()                          // 从 Used Ring 获取 buffer
    → qemu_sendv_packet_async()                // 从 Available Ring 取 buffer
    → virtio_net_receive()                     // 拷贝数据到 Guest 内存

3.2 多队列 virtio-net:mq 与 RSS

现代 virtio-net 支持多队列(multi-queue,简称 mq),Guest 可以同时在多个 vqueue 上收发包,实现 CPU 级别的并行:

# 查看 virtio-net 的队列数
ethtool -l eth0
# 设置发送队列数
ethtool -L eth0 combined 4

# 验证多 RX 队列
cat /proc/interrupts | grep virtio
# 会看到 virtio0-input.0 / virtio0-input.1 / virtio0-input.2 / ...

Guest 侧的流量分发由 Host 端的 RPS(Receive Packet Steering) 或 OVS 的对称哈希实现。Host 端也可以用 `ethtool` 查看:

# 查看 MQ 配置
ethtool -S virtio-net-pci | grep tx_queue

3.3 卸载特性:Checksum、TSO、LRO

virtio-net 将大量数据面卸载交给了 Host 处理,Guest 不再需要计算校验和或分段:

特性Guest 角色Host 角色
TX checksum offload提交校验和为 0 的包Host 内核/reverse-path 计算
TSO (TCP Segmentation Offload)Guest 发送超 MTU 的大包Host 切割为 MTU 段后发出
UFO (UDP Fragmentation Offload)Guest 发送超大 UDP DatagramHost 分片
LRO (Large Receive Offload)-Host 合并小包减少 Guest 中断次数
GRO (Generic Receive Offload)Guest 侧合并-
RX checksum validation-Host 提前计算,标记 CHECKSUM_UNNECESSARY

`ethtool -k eth0` 可以查看当前激活的卸载特性状态。

四、vHost:将数据路径下沉到内核

4.1 QEMU 的性能瓶颈

纯 VirtIO 方案中,所有数据包都需要经过 QEMU 用户态进程转发。QEMU 进程的调度本身就是性能瓶颈:

  • QEMU 进程被宿主机内核调度器抢占,Guest 的 I/O 等待时间不可控
  • QEMU 的地址转换(GPA → HVA)消耗大量 CPU 周期(通过 mmap ioctl)
  • 若启用 vhost,QEMU 只保留控制面(配置 vqueue、中断注入),数据面完全旁路

4.2 vHost-net 架构

vHost-net 是 Linux 内核模块,它实现了 vhost 协议的服务端。在 vhost-net 模式下:

  ┌─────────────┐        ioctl(fd, VHOST_SET_VRING_*)         ┌───────────────┐
  │  QEMU 控制面  │ �────────────────────────────────────────► │  vhost-net    │
  │ (设置 vqueue, │                                           │  (内核模块)    │
  │  注入中断)    │                                           │               │
  └─────────────┘                                            │  ┌─────────┐  │
                                                               │  │ Worker  │  │
                                                               │  │ Thread  │  │
                                                               │  └────┬────┘  │
                                                               │       │       │
                                                     直接处理  │  RX/TX vring  │
                                                    数据包     │  数据面       │
                                                    ┌─────────▼─────────────┐ │
                   物理网卡                         │     Guest 内存         │ │
                    ◄──────────────────────────►   │  (共享 virtqueue)      │ │
                                                     └───────────────────────┘ │
                                                               └───────────────┘

关键配置步骤(简化版):

int vhost_fd = open("/dev/vhost-net", O_RDWR);
ioctl(vhost_fd, VHOST_SET_OWNER, NULL);               // 声明 ownership
ioctl(vhost_fd, VHOST_SET_MEM_TABLE, &mem);           // 传递 Guest 内存映射
ioctl(vhost_fd, VHOST_SET_VRING_NUM, &num);            // 设置 ring 大小
ioctl(vhost_fd, VHOST_SET_VRING_BASE, &base);           // current 指针
ioctl(vhost_fd, VHOST_SET_VRING_ADDR, &vring_addr);     // 关键:GPA → HVA 映射地址
ioctl(vhost_fd, VHOST_SET_VRING_KICK, &kickfd);         // 通知 fd(eventfd)
ioctl(vhost_fd, VHOST_SET_VRING_CALL, &callfd);         // 中断注入 fd
ioctl(vhost_fd, VHOST_NET_SET_BACKEND, &tap_fd);        // 绑定 tap 设备

4.3 vHost-user:用户态进程介入的理想桥梁

`vhost-user` 是 vHost 协议在用户态进程(而非内核)中实现的版本,已成为 DPDK/SPDK 与虚拟化平台之间的标准接口:

 ┌──────────┐    Unix Domain Socket
 │  QEMU    │ ◄────────────────────► ┌────────────────────────────┐
 │          │    vhost-user protocol  │  OVS-DPDK / SPDK vhost-user │
 └──────────┘                        └────────────────────────────┘
       │                                        │
       │  virtqueue 通过共享内存映射到用户态       │  直接操作网卡硬件
       │  (通过 VFIO 或 IVSHMEM)                 │  (PMD 驱动)

vhost-user 协议通过 Unix Domain Socket 传递控制消息,Guest 的 virtqueue 内存则通过以下两种机制共享给 Host 用户态进程:

  • IVSHMEM:KVM 提供的 PCI 共享内存设备,将其 BAR2 映射为 Host 和 Guest 都能访问的共享内存区域
  • VFIO:将 Host 进程的匿名/文件映射区域绑定到 Guest 的 HPA(Hypervisor Physical Address)

OVS-DPDK 的典型部署流程:

# 1. 配置大页内存(DPDK 需要)
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# 2. 启动 ovs-ctl 使用 DPDK datapath
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev

# 3. 添加 vhost-user 端口(来自 Guest 的 virtqueue)
ovs-vsctl add-port br0 vhost-user-1 -- set Interface vhost-user-1 \
    type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user.sock

# 4. Guest 侧使用 ivshmem 设备暴露 virtqueue 内存给 Host 用户态

4.4 vHost-blk 与 vHost-scsi

vhost-blk 将块设备的数据面从 QEMU 卸载到内核(`drivers/vhost/vhost.c` + `blk-mq`),而 vhost-scsi 则让内核直接处理 SCSI 命令。

对比矩阵:

特性vhost-netvhost-blkvhost-scsivhost-user
协议块/SCSI 的 virtio-scsivirtio-scsi CDB块/CDB-
后端实现tap/内核网络栈blk-mq LIO/SGPPLIO自定义
场景块设备VM加速完整SCSI语义通用块加速
典型吞吐~线速 (100G+)~5-10M IOPS~8-15M IOPS取决于后端

五、VDPA:硬件直通的终极进化

5.1 背景:SmartNIC/DPU 的兴起

随着 SmartNIC(智能网卡)和 DPU(数据处理单元) 的普及,网卡硬件本身内置了 VirtIO 协议的硬件实现(virtio 1.1 规范定义的 virtio over PCI 的硬件版本)。硬件可以直接将 virtqueue 中的描述符翻译成 DMA 操作,完成 Guest 应用程序到网卡硬件之间的零拷贝直通。

5.2 vDPA 架构:virtio 到硬件的标准通路

vDPA(virtio Data Path Acceleration) 是 Linux 5.8 引入的框架,旨在建立一个从 VirtOS 驱动到硬件的标准通路,屏蔽不同厂商 SmartNIC/DPU 之间的差异:

Guest 应用
    ↓ (VirtOS 驱动)
virtio_net/virtio_blk (标准内核驱动,无需修改)
    ↓ (标准 virtqueue 操作)
vDPA 框架 (drivers/vdpa/)
    ↓ (厂商注册的 vdpa_device_ops)
┌─────────────────────────────────────────────────┐
│ SmartNIC/DPU Hardware                            │
│   - NVIDIA ConnectX (mlx5_vdpa)                   │
│   - Intel AVF (Intel VFIO-VDPA)                   │
│   - Alibaba ANS (弹性 RDMA 网卡)                  │
│   - AWS Nitro (Ena)                               │
└─────────────────────────────────────────────────┘

vDPA 的关键接口定义:

struct vdpa_device_ops {
    int (*set_vq_address)(...);           // 将 virtqueue 配置到硬件
    int (*set_vq_num)(...);
    void (*set_vq_ready)(...);
    int (*set_vq_state)(...);
    int (*get_vq_state)(...);
    int (*suspend)(...);
    int (*resume)(...);
    int (*set_map)(...);                  // IOMMU 内存映射
    int (*reset)(...);                    // 硬件复位
    size_t (*get_config_size)(...);
    void (*get_config)(...);
    u64 (*get_generation)(...);
    u32 (*get_device_id)(...);
    u32 (*get_vendor_id)(...);
    u8 (*get_status)(...);
    void (*set_status)(...);
    void (*get_vq_align)(...);
    int (*get_vq_group)(...);
    u64 (*get_device_features)(...);
    int (*set_driver_features)(...);
    void (*set_config_cb)(...);
    int (*set_map)(...);
    int (*get_vq_num_max)(...);
    int (*get_vq_num_min)(...);
    int (*dev_add)(...);                  // 创建 vDPA 设备
    void (*dev_del)(...);
};

5.3 直通 vs 模拟:性能对比

在 100Gbps 网卡环境下的实测对比(包大小 1500B,单 RX 队列):

模式吞吐 (Mpps)CPU 占用 (单核)VM Exit 频率
纯 QEMU virtio-net2-4100%极高
vhost-net10-2060-80%中等
vhost-user + DPDK20-5030-50%低
vDPA (硬件直通)80-120<10%几乎没有

六、生产环境调优实战

6.1 中断亲和性(IRQ Affinity)

在多队列 virtio-net 中,每个队列绑定不同 vCPU 的中断可以最大化并行度:

# 查看当前网卡中断分配
cat /proc/interrupts | grep virtio

# 获取 RX 队列数量
ethtool -l eth0

# 为每个 RX 队列绑定不同物理 CPU
# 假设 virtio2-input.0 的中断号是 55
echo 01 > /proc/irq/55/smp_affinity   # 绑定 CPU0
echo 02 > /proc/irq/56/smp_affinity   # 绑定 CPU1
echo 04 > /proc/irq/57/smp_affinity   # 绑定 CPU2
echo 08 > /proc/irq/58/smp_affinity   # 绑定 CPU3

对于 TX 队列,推荐将发送队列绑定到应用所在的 vCPU,使 cache-line 数据尽可能在本地 CPU 上复用。

6.2 队列大小调优

Virtqueue 的标准大小是 256 个描述符(可以通过 `Queue Size` 寄存器调整到 32768):

# 使用 virtio-net-pci 设备时的 QEMU 参数
qemu-system-x86_64 \
    ...
    -device virtio-net-pci,mq=on,vectors=10,rx_queue_size=1024,tx_queue_size=1024

队列大小与吞吐/延迟的权衡:

  • 大队列(1024-4096):能缓冲更多吞吐,减少丢包风险,但延迟增加(描述符等待时间变长)
  • 小队列(128-256):延迟最低,但高吞吐时可能填满导致降级
  • 推荐生产配置:`rx_queue_size=1024, tx_queue_size=1024`(云场景默认)

6.3 中断合并(Interrupt Coalescing)

对于高吞吐场景,VirtIO 的中断注入是主要障碍。利用 `VIRTIO_F_EVENT_IDX` 特性,Guest 可以按需控制中断通知频率:

# Guest 侧配置中断合并
ethtool -C eth0 rx-usecs 100 tx-usecs 100
# 表示等待 100μs 或攒够多个包后再注入中断

对于生产中的 NFV(网络功能虚拟化) 工作负载(虚拟路由器、负载均衡器),激进的中断合并是常见调优手段。典型配置为 `rx-usecs 0`(在 PMD 模式下禁用所有中断)或 `rx-usecs 64`(约 64μs 的中断节流)。

6.4 使用 hugepage 提升性能

VirtIO 设备需要访问 Guest 物理内存(GPA),Guest 侧使用大页可以减少页表项数量,降低 GPA → HPA 转换的开销:

# 在 QEMU 配置中使用 memory-backend-file 预分配大页
-object memory-backend-file,id=mem0,size=8G,mem-path=/dev/hugepages,share=on \
-machine memory-backend=mem0

使用 1GB 大页相比默认 4K 页可以显著提升 Page Table Walk 效率,对 virtio-blk 场景尤为重要(大块 I/O 访问大量不同 page)。

6.5 IRQBalance 与 CPU 隔离

在多租户环境中,建议关闭 irqbalance(或配置 IRQ 亲和性固化),避免中断在服务器 CPU 之间跳跃导致 cache 失效:

# 关闭 irqbalance
systemctl stop irqbalance

# 为每个 vCPU 配置 CPU cgroup 限制
# 避免 vCPU 线程在不同物理 CPU 之间迁移

七、未来展望:VirtIO 的演进方向

7.1 VirtIO 1.3 规范(2024+)

OASIS VirtIO 1.3 规范引入了多项现代化特性:

  • packed virtqueue:传统 vring 的三个独立环形缓冲区被合并为一个紧凑结构,消除跨 cache-line 读取,减少 PCI 事务数量
  • Shared Memory Region:允许 VirtIO 设备通过 PCI BAR 提供的共享内存实现与 Guest 驱动更高效的零拷贝通信
  • Driver Notification Delay:驱动可以显式告知设备延迟通知的时间窗口,进一步减少 VM Exit
  • Per-VQ Reset:针对单个 virtqueue 进行软重置,无需重置整个设备
  • Statistics Reporting:设备的细粒度统计报告接口

7.2 virtiofs:共享文件系统

`virtiofs` 是 VirtIO 家族中专注于文件系统共享的成员,相比 9pfs(9p filesystem)有量级的性能提升:

  • 利用 FUSE 协议在 Guest 和 Host 之间传递文件操作
  • 通过 DAX(Direct Access)映射将 Host 的 page cache 直接暴露给 Guest,避免额外的数据拷贝
  • QEMU 启动参数:`-chardev socket,id=char0,path=/tmp/vhost-fs.sock -device vhost-user-fs-pci,chardev=char0,tag=myfs`
  • Guest 挂载:`mount -t virtiofs myfs /mnt`

7.3 与机密计算(Confidential Computing)整合

AMD SEV-SNP、Intel TDX、ARM CCA 等机密计算技术需要加密 Guest 内存,传统 VirtIO 的共享内存模型需要调整:

  • VirtIO 的 SWIOTLB:当 Guest 内存加密时,通过 bounce buffer 实现设备与 Guest 之间的数据交换,代价是性能损失
  • 未来方向:硬件提供的"共享内存区域"(如 AMD SEV-SNP 的 VMPL)允许在受信任的 TE 环境中使用 VirtIO 直通

八、总结与工程建议

VirtIO/vHost 的技术选型矩阵:

场景推荐方案理由
通用云虚拟机vhost-net + 多队列性能与兼容性的最佳平衡
高性能 NFV/SDNvhost-user + OVS-DPDK线速转发,支持自定义流表
裸金属容器virtio-user (cloud-hypervisor)进程级虚拟化,极低启动开销
SmartNIC 直通vDPA (mlx5_vdpa/ena)硬件卸载,CPU 开销最低
边缘轻量 VMvirtio-mmio (MMCONFIG)无 PCI 依赖,启动速度最快
高安全机密计算virtio + SWIOTLB 或 CVM 专用方案TEE 兼容,牺牲部分性能

无论选择哪种方案,理解 VirtIO virtqueue 的环形缓冲区设计、掌握 vhost 的控制面/数据面解耦思想、以及在中断合并和 CPU 亲和性上做精细调优,都是云原生虚拟化工程师的必备能力。


关键参考文档 - OASIS VirtIO 规范: https://docs.oasis-open.org/virtio/virtio/v1.3/virtio-v1.3.html - Linux 内核 virtio 子系统: `drivers/virtio/` 目录 - QEMU vHost 代码: `hw/net/vhost_net.c` - DPDK vHost-user 驱动: `drivers/net/vhost/`
点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部