二、vhost-user--------踏上vhost-user之旅

这篇文章是关于vhost-user/virtio-pmd架构的技术深入分析,旨在实现使用DPDK的高性能用户态网络,基于解决方案概述帖子提供的介绍。它面向架构师和开发人员,他们希望深入了解这种架构的细节,并将在之后跟随一篇实际操作的博客来亲自探索这些概念。

介绍

在先前的深入分析博客中,我们展示了通过使用vhost-net协议,将网络处理从qemu移到内核驱动程序中的好处。在这篇文章中,我们将进一步迈出一步,展示如何通过使用DPDK(Data Plane Development Kit)将数据平面从内核迁移到客户和主机的用户态,从而实现更好的网络性能。为了实现这一目标,我们还将详细介绍vhost协议的新实现:vhost-user库。

通过阅读本文,您将深入了解vhost-user/virtio-pmd架构中涉及的所有组件,并了解它为何能够提供显著性能改进的原因。

DPDK及其优势

很可能您已经听说过DPDK。这个用户空间快速数据包处理库是许多网络功能虚拟化(NFV)应用程序的核心,使它们能够完全在用户空间实现,绕过内核的网络堆栈。

DPDK是一组用户空间库,使用户能够创建优化性能的数据包处理应用程序。它带来了许多优势,使其在开发人员中非常受欢迎,成为一种强大的工具。以下是其中一些优点:

处理器亲和性 - DPDK将每个不同的线程固定到特定的逻辑核心,以最大程度地提高并行性。

大页面 - DPDK具有多层内存管理(如内存池库或Mbuf库)。但在底层,所有内存都是使用hugetlbfs中
的mmap分配的。使用2MB甚至1GB页面,DPDK减少了高速缓存未命中和TLB查找。

无锁环形缓冲区 - DPDK的数据包处理基于一个Ring库,它提供了一个高效的无锁环形队列,支持批量入队和出队操作。

轮询模式驱动程序 - 为了避免中断开销,DPDK提供了轮询模式驱动程序(PMD)抽象。

VFIO支持 - VFIO(虚拟功能I/O)提供了一个用户空间驱动程序开发框架,允许用户空间应用程序通过
将I/O空间直接映射到应用程序的内存来直接与硬件设备交互。

除了这些功能外,DPDK还支持另外两项技术,为我们提供了在云环境中显著提高网络应用程序性能的工具。这些技术包括:

Vhost-user库 - 一个用户空间库,实现了vhost协议(在“virtio-networking vhost-net”文章中描述)。

Virtio-PMD - 基于DPDK的PMD抽象,virtio-pmd驱动程序实现了virtio规范,并允许以标准和高效的方式使用虚拟设备。

DPDK与OVS:完美组合

DPDK带来的性能提升在已经广受欢迎的Open vSwitch(OVS-DPDK)中得到了很好的体现。Open vSwitch是一个功能丰富、多层次的、分布式虚拟交换机,广泛用作虚拟环境和其他SDN应用程序的主要网络层。

传统上,它被划分为一个基于内核的快速数据路径(fastpath),包括一个流表,以及一个较慢的用户态数据路径(slowpath),用于处理在fastpath中没有匹配的数据包。通过将OVS与DPDK集成,fastpath也在用户空间中运行,最小化了内核与用户空间之间的交互,同时利用了DPDK提供的高性能。结果是OVS与DPDK相比原生OVS的性能提高了约10倍。

那么,如何将OVS-DPDK的功能和性能与基于virtio的架构相结合呢?接下来的部分将逐一向您介绍所需的组件。

DPDK中的vhost-user库

vhost协议是一组消息和机制,旨在将virtio数据路径处理从QEMU(希望卸载数据包处理的主要组件)卸载到外部元素(处理程序,负责配置virtio环和执行实际数据包处理)。最相关的机制包括:

1、一组消息,允许主要组件将virtqueue的内存布局和配置发送到处理程序。

2、一对类似eventfd的文件描述符,允许客户绕过主要组件,直接向处理程序发送通知以及从处理程序接收通知:可用缓冲区通知(从客户发送到处理程序,表示有准备好进行处理的缓冲区)和已使用缓冲区通知(从处理程序发送到客户,表示它已完成缓冲区的处理)。

在“virtio-networking vhost-net”文章中,我们描述了该协议的具体实现(vhost-net内核模块),以及它如何允许qemu将网络处理卸载到主机内核。现在我们介绍vhost-user库。这个库是在DPDK中构建的,是vhost协议的用户空间实现,允许qemu将virtio设备的数据包处理卸载到任何DPDK应用程序(例如Open vSwitch)。

vhost-user库与vhost-net内核驱动程序之间的主要区别在于通信通道。而vhost-net内核驱动程序使用ioctls实现这个通道,vhost-user库则定义了通过Unix套接字发送的消息的结构

DPDK应用程序可以配置为提供Unix套接字(服务器模式),并允许QEMU连接到它(客户端模式)。然而,也可以反过来,这允许在不重新启动虚拟机的情况下重新启动DPDK。

在此套接字上,所有请求都由主要组件(即QEMU)发起,其中一些请求需要响应,例如GET_FEATURES请求或任何设置了REPLY_ACK位的请求。

与vhost-net内核模块一样,vhost-user库允许主要组件通过执行以下重要操作来配置数据平面卸载:

1、功能协商:virtio功能和vhost-user特定功能都以类似的方式进行协商:首先,主要组件“获取”处理程
序支持的功能位掩码,然后它“设置”自身也支持的一部分功能。

2、内存区域配置:主要组件设置内存映射区域,以便处理程序可以使用mmap()进行映射。

3、Vring配置:主要组件设置要使用的virtqueue数量以及它们在内存区域内的地址。请注意,
vhost-user支持多队列,因此可以配置多个virtqueue以提高性能。

4、Kick和Call文件描述符发送:通常使用irqfd和ioeventfd机制。有关这些机制的更多信息,请参阅“深
入了解Virtio-networking和vhost-net”,有关virtio队列机制的更多信息,请参阅即将发布的virtio数据平面
文章。

通过这种机制,DPDK应用程序现在可以通过与客户共享内存区域来处理数据包,并可以直接与客户发送和接收通知,而无需qemu的干预。

将所有这些元素紧密连接在一起的最后一个元素是QEMU的virtio设备模型。它有两个主要任务:

1、它模拟了一个virtio设备,出现在客户中的特定PCI端口上,可以被客户轻松地探测和配置。此外,它
将ioeventfd映射到模拟设备的内存映射I/O空间,将irqfd映射到全局系统中断(GSI)。其结果是客户不
知道通知和中断正在通过vhost-user库进行转发,而无需QEMU的干预。

2、它不是实现实际的virtio数据路径,而是在vhost-user协议中充当主要组件,将这个处理卸载到DPDK
进程中的vhost-user库中。

3、它处理来自控制virtqueue的请求,这些请求在某些情况下会被转换为vhost-user请求,并转发到从属组件。

这个图表显示了作为DPDK-APP的一部分运行的vhost-user库与qemu和客户之间的交互,使用virtio-device模型和virtio-pci设备:
在这里插入图片描述
关于这个图表需要提到的几个要点:

1、virtio内存区域最初由客户(虚拟机)分配。

2、相应的virtio驱动程序通过virtio规范中定义的PCI BARs配置接口与virtio设备正常交互。

3、virtio-device-model(位于QEMU内部)使用vhost-user协议配置vhost-user库,并设置irqfd和ioeventfd文件描述符。

4、由客户分配的virtio内存区域由vhost-user库(即DPDK应用程序)进行映射(使用mmap系统调用)。

结果是DPDK应用程序可以直接读取和写入来自客户内存的数据包,并使用irqfd和ioeventfd机制直接与客户进行通知。

客户(虚拟机)中的用户空间网络

我们已经介绍了DPDK的vhost-user实现如何使我们能够将数据路径处理从主机内核(vhost-net)卸载到专用的DPDK用户空间应用程序(如Open vSwitch),从而显著提高了网络性能。现在,我们将看到如何在客户(虚拟机)中通过在用户空间运行高性能网络应用程序(如NFV服务)来实现同样的效果,取代了virtio-net内核方法。

为了能够直接在设备上运行用户空间网络应用程序,我们需要三个组件:

1、VFIO:VFIO是一个用户空间驱动程序开发框架,允许用户空间应用程序直接与设备交互(绕过内核)。

2、Virtio-pmd驱动程序:这是一个DPDK驱动程序,建立在轮询模式驱动程序抽象之上,实现了virtio协议。

3、IOMMU驱动程序:IOMMU驱动程序用于管理虚拟IOMMU(I/O内存管理单元),这是一个模拟设备,用于为支持DMA的设备执行I/O地址映射。

让我们逐个详细描述这些组件

VFIO

VFIO代表Virtual Function I/O。然而,vfio-pci内核驱动程序的维护者Alex Williamson建议将其称为“用于用户空间I/O的多功能框架”,这可能更准确。VFIO基本上是一个用于构建用户空间驱动程序的框架,提供以下功能:

1、将设备的配置和I/O内存区域映射到用户内存

2、基于IOMMU组的DMA和中断重映射和隔离。我们将在本文后面更深入地讨论IOMMU是什么以及它
的工作原理。现在,让我们说它允许创建虚拟I/O内存空间,将其映射到物理内存(类似于正常的MMU
将非IO虚拟内存映射),因此当设备要DMA到虚拟I/O地址时,IOMMU将重新映射该地址并可能应用隔
离和其他安全策略。

3、基于eventfd和irqfd(还记得吗?)的信号机制,支持与用户空间应用程序之间的事件和中断。

引用内核文档的话:“如果您想在VFIO之前编写驱动程序,您要么必须经过完整的开发周期,以成为合格的上游驱动程序,要么在树外维护,要么利用没有IOMMU保护概念、有限的中断支持并需要root权限访问PCI配置空间之类的UIO框架。”

VFIO提供了一个用户友好的API,创建字符设备(位于/dev/vfio/)支持ioctl调用,用于描述设备、I/O区域以及它们在设备描述符上的读/写/mmap偏移量,以及描述和注册中断通知的机制。

Virtio-pmd

DPDK提供了一个称为Poll Mode Driver(PMD)的驱动程序抽象,位于设备驱动程序和用户应用程序之间。它为用户应用程序提供了很大的灵活性,同时保持了可扩展性,即实现新设备的驱动程序的能力。

以下是一些其更显著的特点:

1、一组API允让特定驱动程序实现特定于设备的接收和传输功能。

2、可以静态和动态配置每个端口和每个队列的硬件卸载

3、可用的统计信息是可扩展的,允许驱动程序定义自己特定于驱动程序的统计信息,应用程序可以探测可用的统计信息并检索它们。

virtio Poll Mode Driver(virtio-pmd)是使用PMD API的众多驱动程序之一,为使用DPDK编写的应用程序提供了对virtio设备的快速且无锁的访问,使用virtio的virtqueue提供数据包接收和传输的基本功能。

除了任何PMD都具有的所有特性外,virtio-pmd驱动程序还支持:

1、在接收时每个数据包的灵活可合并的缓冲区,以及在传输时每个数据包的分散缓冲区

2、多播和混杂模式

3、MAC/vlan过滤

结果是一个高性能的用户空间virtio驱动程序,允许任何DPDK应用程序无缝使用virtio的标准接口。

介绍IOMMU

IOMMU在I/O空间(设备使用DMA直接访问内存的地方)中与MMU相当。它位于主内存和设备之间,为每个设备创建一个虚拟I/O空间,并提供一种动态将虚拟I/O内存映射到物理内存的机制。因此,当驱动程序配置设备的DMA(例如网络卡)时,它配置虚拟地址,当设备尝试访问它们时,IOMMU会重新映射它们。

在这里插入图片描述
它提供了许多优势,如:

1、可以分配大的连续虚拟内存区域,而无需在物理内存中连续。

2、一些设备不支持足够长的地址来访问整个物理内存,IOMMU解决了这个问题。

3、内存受到来自恶意或故障设备的DMA攻击的保护,这些设备试图访问未专门为它们分配的内存。设
备只“看到”虚拟地址空间,运行中的操作系统专门控制IOMMU的映射。

4、在某些体系结构中,支持中断重映射,可以实现中断隔离和迁移。

正如通常情况下,一切都有代价,在IOMMU的情况下,缺点包括:

1、与页面转换服务相关的性能降低

2、增加了页面转换表的物理内存消耗

最后,IOMMU提供了一个PCIe地址转换服务接口,设备可以使用它来查询并缓存地址转换在其内部的设备表查找缓冲区(TLB)中。

vIOMMU - 用于客户(虚拟机)的IOMMU

当然,如果有物理IOMMU(例如Intel VT-d和AMD-VI),那么在qemu内部就会有一个虚拟IOMMU。具体来说,QEMU的vIOMMU具有以下特点:

1、它将客户(虚拟机)的I/O虚拟地址(IOVA)转换为客户(虚拟机)的物理地址(GPA),然后可以
通过QEMU的内存管理系统将其转换为QEMU的主机虚拟地址(HVA)。

2、执行设备隔离。

3、实现了I/O TLB API,以便可以从qemu外部查询映射。

因此,为了使虚拟设备与虚拟IOMMU一起正常工作,我们必须:

使用可用的API之一创建必要的IOVA映射到vIOMMU中。目前,这些API包括:

1、内核的DMA API用于内核驱动程序

2、用于用户空间驱动程序的VFIO

使用虚拟I/O地址配置设备的DMA。

vIOMMU与DPDK集成

虚拟IOMMU与任何用户空间网络应用程序之间的集成通常通过VFIO驱动程序完成。正如我们已经提到的,这个驱动程序将执行设备隔离并自动向IOMMU添加iova到gpa的映射。

除了支持使用VFIO设置网络设备之外,使用DPDK还有另一个与IOMMU相关的非常重要的好处。由于DPDK使用的内存管理机制,它分配一个静态内存池,然后用于存储数据包缓冲区和虚拟队列,因此设备TLB同步消息的数量大大减少,与之相关的性能损失也降低了。使用大页还有助于优化TLB查找,因为较少数量的内存页面可以覆盖相同数量的内存。

vIOMMU与vhost-user集成

当QEMU中正在模拟的设备尝试DMA到虚拟机的virtio I/O空间时,它将使用vIOMMU TLB来查找页面映射并执行安全的DMA访问。问题是,如果实际的DMA被卸载到外部进程(如使用vhost-user库的DPDK应用程序)会发生什么情况?

当vhost-user库尝试直接访问共享内存时,它必须将所有地址(I/O虚拟地址)转换为自己的内存。它通过通过设备TLB API向QEMU的vIOMMU请求翻译来实现这一点。Vhost-user库(以及vhost-kernel驱动程序)使用PCIe的地址转换服务标准一组消息来请求页面翻译,使用IOMMU支持配置时创建的次要通信通道(另一个unix套接字)进行与QEMU的通信。

总的来说,有3个地址翻译必须进行:

1、QEMU的vIOMMU将IOVA(I/O虚拟地址)转换为GPA(Guest Physical Address)。

2、QEMU的内存管理将GPA(Guest Physical Address)转换为HVA(qemu进程的地址空间内的Host Virtual Address)。

3、Vhost-user库将(QEMU的)HVA转换为自己的HVA。这通常很简单,只需将QEMU的HVA添加到
vhost-user库映射QEMU内存时由mmap(2)返回的地址即可。

显然,所有这些翻译可能会对性能产生重要的影响,特别是如果使用动态映射。但是,静态、大页分配(这正是DPDK所做的)可以最小化这种性能损失。

以下图示增强了先前的vhost-user架构,包括IOMMU组件:
在这里插入图片描述

图中有几个需要注意的要点,这是一个相当复杂的图示:

1、虚拟机的物理内存空间是虚拟机感知为物理的内存,但显然它位于QEMU进程(主机)的虚拟地址
中。当分配virtqueue内存区域时,它最终位于虚拟机的物理内存空间中的某个位置。

2、当为包含virtqueues的内存范围分配I/O虚拟地址时,将在vIOMMU的TLB表中添加一个与其关联的虚
拟机物理地址(GPA)的条目。

3、另一方面,QEMU的内存管理系统知道虚拟机的物理内存空间位于其自己的内存空间中的位置。因
此,它能够将虚拟机物理地址转换为主机(QEMU的)虚拟地址。

4、当vhost-user库尝试访问没有翻译的IOVA时,它会通过次要的unix套接字发送IOTLB缺失消息。

5、IOTLB API接收请求并查找地址,首先将IOVA转换为GPA,然后将GPA转换为HVA。然后,它将转
换后的地址通过主unix套接字发送回vhost-user库。

6、最后,vhost-user库必须进行最后一次翻译。由于它已将qemu的内存映射到自己的内存中,因此必
须将qemu的HVA转换为自己的HVA并访问共享内存。

总的来说

在这篇文章中,我们涵盖了许多组件,包括DPDK、virtio-pmd、VFIO、IOMMU等等…

以下图表显示了这些构建块如何一起工作,以实现vhost-user/virtio-pmd架构:
实现vhost-user/virtio-pmd架构

对于这个图表,有几个需要注意的要点:

与前一个图表相比,我们已经添加了连接主机的OVS-DPDK应用程序到物理NIC的组件,使用硬件
IOMMU、VFIO和供应商特定的PMD驱动程序。到目前为止,这应该不会引起任何疑虑,因为这相当于
为客户机执行的操作。

以下流程图展示了设置virtio高性能数据平面所需的步骤:
在这里插入图片描述

控制平面

以下是设置控制平面所需的步骤:

1、当主机中的DPDK应用程序(OvS)启动时,它创建一个用于与qemu进行virtio相关协商的套接字(以服务器模式使用)。

2、当qemu启动时,它连接到主套接字,并且如果vhost-user提供了特性VHOST_USER_PROTOCOL_F_SLAVE_REQ,它将创建第二个套接字并将其传递给vhost-user,以便它连接并发送iotlb同步消息。

3、当QEMU <-> vhost-library协商结束时,它们之间共享了两个套接字。一个用于virtio配置,另一个用于iotlb消息交换。

4、客户机启动并将vfio驱动程序绑定到PCI设备。它创建了对iommu组的访问(这取决于硬件拓扑)。

5、当客户机中的dpdk应用程序启动时,它执行以下初始化步骤:

1、初始化PCI-vfio设备。此外,vfio驱动程序将PCI配置空间映射到用户内存。
2、分配了virtqueue。
3、使用vfio,执行了virtqueue内存空间的DMA映射请求,通过IOMMU内核驱动程序将DMA映射添加到vIOMMU设备中。
4、然后进行virtio特性协商。在这种情况下,用作virtqueue基地址的地址是IOVA(在I/O虚拟地址空间
中)。还设置了eventfd和irqfd的映射,以便可以在不经过QEMU干预的情况下在客户机和vhost-user库
之间直接路由中断和通知。
5、最后,dpdk应用程序为网络缓冲区分配了一大块连续内存。还通过VFIO和IOMMU驱动程序将此内
存区域的映射添加到vIOMMU中。

此时,配置完成,数据平面(virtqueues和通知机制)已准备就绪。

数据平面

为了传输数据包,会执行以下步骤:

1、客户机中的DPDK应用程序命令virtio-pmd发送数据包。它写入缓冲区并在可用的描述符环中添加相应的描述符。

2、主机中的vhost-user PMD正在轮询virtqueue,因此它立即检测到新的描述符可用并开始处理它们。

3、对于每个描述符,vhost-user PMD会将其缓冲区映射(即将其IOVA转换为HVA)。在极少数情况
下,缓冲区内存可能是尚未映射在vhost-user的IOTLB中的页面,将会发送请求给QEMU。但是,客户
机中的DPDK应用程序分配了静态的巨大页面,因此将IOTLB请求发送给QEMU的次数很少。

4、vhost-user PMD将缓冲区复制到mbufs(DPDK应用程序使用的消息缓冲区)中。

5、描述符被添加到已使用的描述符环中。这些描述符会立即被客户机中也在轮询virtqueues的DPDK应用程序检测到。

6、mbufs由主机中的DPDK应用程序处理。

总结

DPDK是一项备受关注的技术,因其为用户态高性能网络带来的好处而逐渐流行起来。此技术与Open vSwitch结合使用,不仅可以提供现代虚拟环境所需的灵活性和性能,还将在NFV部署中发挥关键作用。

为了充分利用这项技术,既可以作为数据中心交换数据通道,也可以作为宿主机中的NFV应用程序的启用器,需要在宿主机和虚拟机之间创建一个安全高效的数据通道。这就是virtio-net技术发挥作用的地方。

Vhost-user提供了一种可靠且安全的机制,可将网络处理卸载到基于DPDK的应用程序中。它与vIOMMU集成,提供了隔离和内存保护,同时解放了QEMU,使其不必处理所有数据包。

在虚拟机中,DPDK中对virtio规范的实现(virtio-pmd)使得可以创建一个快速的虚拟机中的数据通道,利用了DPDK的高效内存管理和Poll Mode Driver提供的高速功能。

如果你想了解更多关于virtio技术、vhost-user和DPDK的内容,并且不怕动手实践,千万不要错过我们关于vhost-user的实际操作帖子!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写一封情书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值