0%

DPDK Exception path 方案:Virtio-user

DPDK 作为旁路内核方案,其接受和转发的包可以不经过内核进行高速转发,但其中可能存在部分“异常”的包(比如发给该节点本身的包)不需要转发,而是需要通过内核处理,这就是 Exception path,virtio-user 则实现 Exception path 的方案之一。

Virtio-user

Virtio-user 一系列概念原本是用来处理虚拟机与主机之间的 I/O。

  • virtio:即 virtual I/O,用于虚拟机和主机间高速 I/O 操作的开放标准。
  • vhost:主机中加速 virtio 的后端驱动实现方案。最初 virtio 在主机中的后端处理由 QEMU 进程实现,后升级为 vhost 加速方案,vhost 又分为内核态的 vhost-net 和在用户态的 vhost-user
  • virtio-net:在虚拟机内部的前端驱动,遵循 virtio 标准收发网络包,需要主机有对应的后端来配合。
  • vhost-net:在主机的内核空间的后端驱动,可以处理来自虚拟机 virtio-net 的包,并将包交给内核网络协议栈。
  • vhost-user:在主机的用户空间的后端规范,规定了如何绕过内核,通过用户态应用(如 OVS-DPDK)来实现一个后端驱动,用来处理来自虚拟机 virtio-net 的包
  • virtio-user:DPDK 对 virtio-net 的具体实现的后端驱动,在主机的用户空间,如通过 DPDK 创建端口与虚拟机通信使用的就是这种驱动。

由此便有了虚拟机与主机之间的 I/O 的三种后端路径:

  1. 传统的 QEMU 进程:速度很慢
  2. 内核态的 vhost-net 后端驱动:速度快于 QEMU
  3. 用户态基于 vhost-user 协议的 virtio-user 后端驱动:速度最快

image-20250905014859933

DPDK Exception Path — Virtio_user

Virtio_user,作为虚拟设备,原本是与 vhost-user 后端(另一个进程)一起作为 IPC(进程间通信) 和用户空间容器网络的高性能解决方案。但在 Exception Path 中,其舍弃了 vhost-user 后端,而是与 vhost-net 进行通信,从而将包转入内核。

下图展示了 Virtio_user 作为 DPDK Exception Path 的架构。

图中共有两条包路径:

  • Fast Path (NIC <-> other PMDs <-> ETHFEV API <->):包的快速转发路径, 纯用户态转发,包从网卡通过各种 DPDK 的 PMD 驱动收发,DPDK 应用通过调用如 rte_eth_rx_burst()rte_eth_tx_burst() 等 ETHDEV API 来与 PMD 驱动交互,实现包处理后,不经内核,快速转出
  • Exception Path (NIC -> other PMDs -> ETHFEV API -> ... -> ETHFEV API -> virtio PMD -> tap -> kernel network stack):包的异常路径
    • DPDK -> 内核(发送路径)
      1. DPDK 应用调用 rte_eth_tx_burst(virtio_user0, ...) 控制 PMD 驱动
      2. virtio PMD 驱动将包通过 vhost 协议,将数据包经过 /dev/vhost-net 文件交给内核的 vhost-net 驱动
      3. vhost-net 驱动将包写入 tap 设备
      4. 内核网络协议栈中 tap 设备中读到包,开始处理
    • 内核 -> DPDK(接收路径)
      1. 内核网络协议栈决定发一个包,将包写入 tap 设备
      2. vhost-net 驱动从 tap 设备抓取包
      3. vhost-net 驱动通过 vhost 协议和共享内存,将包放到 virtio_user0 的接受队列
      4. DPDK 应用调用 rte_eth_rx_burst(virtio_user0, ...) 从 virtio_user0 的接受队列收包

DPDK 通过下面代码示例来创建 virtio_user 端口

1
rte_eal_hotplug_add("vdev", "virtio_user0", "path=/dev/vhost-net");
  • rte_eal_hotplug_add 函数用于动态添加一个设备
  • vdev 指这个设备的类型是虚拟设备(Virtual Device),而不是物理 PCI 设备
  • virtio_user0 指定设备名称,对应图中的 virtio PMD,之后 DPDK 就可通过rte_eth_tx_burst(virtio_user0, ...)rte_eth_rx_burst(virtio_user0, ...) 来操作这个端口
  • path=/dev/vhost-net 指定的设备的后端路径,即使用 vhost-net 内核驱动与内核交互,对应了图中的对 vhost.ko(vhost-net 的内核模块)的用户态 vhost adapter 适配行为

此处添加的 virtio_user0 虚拟设备并非 Linux 内核的虚拟网卡 tap,该 virtio_user0 是用户态的 DPDK 的 virtio PMD 的一个虚拟端口,tap 是与之在内核对应的那种虚拟网卡,可以同样命名为 virtio_user0,但不是同一个东西。

Virtio-user Exception Path 示例

  1. DPDK 从物理网卡的 RX 取下包
  2. DPDK 判断收包是否走 Exception Path
  3. 如果是走 Exception Path 的包,DPDK 将其放到 EP ring 中,之后统一发到 virtio_user0 的 TX(推荐使用一个 ring 来作为中间缓冲)
  4. virtio_user0 通过 vhost-net 将包发到内核协议栈,最后交给相应用户态进程
  5. 用户态进程收包后,将响应的回包交给内核协议栈
  6. vhost-net 将回包放到 virtio_user0 的 RX
  7. DPDK 从 virtio_user0 的 RX 收包,并通过物理网卡的 TX 发出

注:RX、TX 都是相对 DPDK 而言的

参考