壹
vfio-user实现分析
在虚拟化应用中,借助内核vfio机制,hypervisor已经支持Host下的PCIe设备以pass-through的方式提供给VM使用,其中就包括了常见的NVMe设备。但同样由于在线迁移方面的限制以及无法扩展使用更多形态的后端资源,NVMe的pass-throgh使用比较有限。
vfio-user技术的提出,使得用户态模拟PCIe设备成为可能,给NVMe设备在虚拟化场景中的使用带来了新的应用形式。
vfio-user的思路和vhost-user有点类似,例如在VM所在的Qemu进程之外来模拟设备并提供给Qemu进程中的VM使用,但使用的协议是vfio-user对应的协议,遵循PCIe的相关语义。当然也可以提供模拟的设备给非VM的应用使用。
vfio-user机制
如同vhost-user的实现,vfio-user的实现也不需要内核态模块和接口的支持,可以完全在用户态完成。vfio-user的框架包含了两部分:第一,vfio-user client,通常存在于hypervisor中,其扩展了hypervisor中用户态通过ioctl与内核vfio-pci模块进行交互的接口,以unix socket方式和在用户态模拟的PCIe设备进行通信;第二,vfio-user server, 独立于VM所在的hypervisor进程之外的单独进程,主要是在用户态实现模拟的PCIe设备。
vfio-user server侧模拟设备的语义逻辑与内核vfio-pci模块的实现相似,这样hypervisor(如Qemu)中与vfio-pci模快交互的逻辑可以很大程度的复用,vfio-user client侧主要是要需要基于unix socket接口封装一套API来让hypervisor(如Qemu)可以像使用ioctl的接口一般来访问目标PCIe设备的资源。以Qemu多进程的方式为例,可以将vfio-user server与vfio-user client的关系表示如图所示(其中libvfio-user库和vfio client之间的接口通道是unix socket)。
图1. vfio-user server和vfio-user client的关系示意
(以Qemu多进程实现为例)
在vfio-user server侧与vfio-user client进行交互的功能由libvfio-user库来提供(可以从https://github.com/nutanix/libvfio-user 获取源码 )。基于libvfio-user提供的接口,vfio-user server侧理论上可以对各种PCIe设备进行用户态的模拟实现。
vfio-user的协议正在标准化过程中,目前vfio-user client侧主已在Qemu中支持,对于vfio-user server在Qemu及SPDK中也都都有对应的实现。在这里主要基于在SPDK中实现的vfio-user 情况进行分析。
SPDK vfio-user集成
SPDK在2021年的版本中已经实现了基于vifo-user标准对NVMe设备的模拟实现,且为了对模拟的NVMe设备进行测试,也为了可能的在非Qemu使用场景(如container等)下的应用,在SPDK NVMe initiator的驱动中增加了vfio-user协议的支持,作为vfio-user client的角色。
SPDK vfio-user server实现
SPDK对 vfio-user server的实现是基于NVMf Target来做的 --- 在NVMf Target模块增加了一种transport(与rdma、tcp并列)来基于libvfio-user库提供的接口与vfio-user client进行通信,NVMe设备的语义模拟,仍由NVMf模块原有的逻辑实现。
SPDK NVMf Target通过vfio-user协议对vfio-client侧(如Qemu)提供服务的基本结构关系可见图2所示。
图2. NVMf Target与Qemu对接的模块关系示意
NVMf Target新增的vfio-user transport的代码在 “SPDK/lib/nvmf”目录下,其中主要依赖libvfio-user的接口完成transport数据结构定义的各个接