virtio 学习随笔 —— 六、virtio后端硬件化加速框架vDPA
六、virtio后端硬件化加速框架vDPA
参考文档:
Achieving network wirespeed in an open standard manner: introducing vDPA
vDPA - virtio Data Path Acceleration
vDPA support
在前几篇文档中,我们已经介绍了 virtio 与 vhost 的相关内容,并在 SR-IOV 的篇章中分析了其存在的不足。vDPA(virtio Data Path Acceleration)正是为了解决这些缺陷而应运而生的。
与讨论virtio时类似,现在将对NIC的访问分解为控制平面与数据平面:
- 控制平面:用于网卡与客户机之间建立及终止数据平面时的配置变更与能力协商
- 数据平面:用于网卡与客户机之间传输实际数据(数据包)。当网卡被直通到虚拟机时,这意味着网卡需支持virtio环形队列布局
Virtio协议的全硬件卸载
在这种方案中,virtio 的数据平面和控制平面都被完全卸载到硬件中。这意味着物理网卡必须原生支持 virtio 协议,包括设备发现、特性协商,以及数据平面连接的建立与终止等功能。此外,为了让 NIC 能够在自身与映射到虚拟机的内存之间高效交换数据,设备还必须支持 virtio 的环形队列结构(virtio ring)。
采用此方案时,Hypervisor不需要安装额外驱动,虚拟机能够直接通过PCI总线与NIC进行交互。不过这就要求NIC厂商需要在NIC中实现完整的virtio协议栈,包括通常由Hypervisor内核中通过软件实现的控制平面。
vDPA——数据平面卸载
虚拟数据路径加速(vDPA)本质上是一种标准化网卡数据平面的方法,它采用virtio环形布局架构,在虚拟机内部署与厂商实现解耦的统一标准virtio驱动,同时通过通用控制平面和软件基础设施提供支持。
跟virtio全硬件卸载类似,vDPA的数据传输也是直接在物理NIC进行虚拟机之间进行,不过NIC厂商能够继续使用自己的驱动(只需添加小型vDPA附加模块),同时需要在内核中加入通用的vDPA驱动,该驱动负责将厂商网卡的控制平面转换成virtio的控制平面。相比于完全依赖硬件卸载,vDPA 具备更高的灵活性。NIC 厂商只需以较低的成本实现对 virtio ring 的支持,即可在数据平面上实现接近线路速率(wirespeed)的转发性能。
vDPA有望成为为虚拟机提供线速以太网接口的解决方案,这是因为vDPA具备这些优势:
- 开放公共规范:Virtio规范,无需受限于特定供应商。
- 线速性能:与设备直通类似,无需中间转换层或转译层。
- 实时迁移能力:鉴于环状缓冲区布局已成为虚拟机标准,现可实现不同厂商网卡及版本间的实时迁移。
- 统一通用网卡驱动:从长远看,virtio-net驱动可作为裸金属驱动启用,同时利用内核中的vDPA软件基础设施,实现单个通用网卡驱动适配不同硬件网卡(类似于存储设备的NVMe驱动方案)。
目前的 NIC 驱动生态非常分散,不同厂商、不同型号都需要各自的驱动程序,这给系统维护和迁移带来了很大负担。相比之下,NVMe SSD 在标准化方面做得更好——只要硬件遵循 NVMe 协议,Linux 就可以用同一个 NVMe 驱动进行管理。
vDPA 框架的引入,为网络设备提供了类似的标准化思路:通过在内核中统一 virtio-net 前端驱动,并在底层由不同厂商提供各自的 vDPA 设备驱动适配硬件,实现一种“通用网络驱动”的模式。这样,物理机和虚拟机都可以使用相同的 virtio-net 驱动与不同的 NIC 对接,从而降低上层软件的依赖和适配成本。
不过,这种模式的前提是底层 NIC 必须支持 vDPA 所需的 virtio 数据结构,且厂商需要提供对应的 vDPA 驱动。因此,短期内它无法覆盖所有现有的网卡。
传统驱动框架(厂商专用驱动 )
+---------------------------+
| 用户应用(socket, DPDK) |
+---------------------------+
| TCP/IP 协议栈 / PMD驱动 |
+---------------------------+
| NIC 厂商驱动(内核或DPDK)|
+---------------------------+
| 厂商硬件NIC |
+---------------------------+
vDPA + virtio-net(理想通用模式)
+------------------------------+
| 用户应用(socket, DPDK) |
+------------------------------+
| TCP/IP 协议栈 / virtio PMD |
+------------------------------+
| virtio-net 驱动(通用) |
+------------------------------+
| vDPA 核心框架(内核) |
+------------------------------+
| vDPA 设备驱动(厂商提供) |
+------------------------------+
| 硬件 NIC(支持 virtio ring) |
+------------------------------+
vDPA驱动代码解析
Linux version: v5.7
本小节将对 Linux Kernel 中的 vDPA 框架进行解析,梳理其各组成部分之间的关系,帮助读者对 vDPA 的整体架构形成清晰、直观的认识。
vDPA是在v5.7版本中被正式加入到Linux内核中1,其驱动代码位于drivers/vdpa
文件夹中,该版本中引入了两款vDPA设备,分别是Intel的IFCVF以及vdpa_sim,前者是Intel的FPGA 100G VF,后者是一个vDPA模拟设备,用于在没有vDPA设备时验证驱动使用。
以IFCVF设备为例,整体的框架如下:
+-------------------+ +---------------------+
| virtio 框架 | <------ | virtio_vdpa.c | <-- vDPA驱动(适配层)
+-------------------+ +---------------------+
^
|
+---------------------+
| vdpa.c | <-- vDPA总线核心
+---------------------+
^
|
+---------------------+
| ifcvf_main.c | <-- vDPA设备驱动
| ifcvf_base.c | <-- 硬件操作
+---------------------+
|
+---------------------+
| 硬件/PCI设备 |
+---------------------+
在这个框架图中能够非常清楚的观察到,vDPA驱动由两部分构成:
-
vDPA总线驱动(vdpa.c)
- 负责实现 vDPA 总线,管理 vDPA 设备和 vDPA驱动的注册、注销、匹配和生命周期。
- 提供
vdpa_register_device
、vdpa_register_driver
等接口,统一管理所有挂载到 vDPA 总线上的设备和驱动。
-
vDPA设备驱动/转换驱动(如 ifcvf_main.c、virtio_vdpa.c、vdpa_sim.c)
- 负责具体设备的功能实现(如硬件网卡、模拟设备等),实现
vdpa_config_ops
接口,把设备能力通过 vDPA总线暴露给上层。 - 其中“转换驱动”通常指将底层设备能力转换为 virtio/vhost 能力,比如
virtio_vdpa.c
,它把 vDPA设备适配到 virtio 框架。
- 负责具体设备的功能实现(如硬件网卡、模拟设备等),实现
在drivers/vdpa/vdpa.c
中实现了 vDPA 虚拟总线。vDPA 设备通常首先作为 PCI 设备被系统枚举。当 PCI 总线枚举到 vDPA 设备并驱动匹配成功后,会调用设备驱动的 probe
函数,在该函数中将 vDPA 设备注册到 vDPA 虚拟总线。随后,vDPA 总线会根据已注册的 vDPA 驱动(如 virtio_vdpa
)进行设备与驱动的匹配,并调用驱动的回调函数,实现设备与驱动的绑定和初始化。