深入理解DPDK IOVA模式

背景

缩写词
pa: 物理地址
va: 虚拟地址
mmu: 内存管理单元
dma: Direct memory access
本文基于dpdk版本 22.11

IOVA&IOMMU的起源

在计算机早期的时候,设备访问内存(DMA)只能用物理地址。设备的地址长度比CPU的总线长度短,只能分配低地址来给设备用。CPU 分配pa后,作为dma地址,提供给设备,设备访问这个dma地址,就可以访问内存数据。

后来,设备演进,加了页表,支持地址的映射(把有限长的dma地址转换为和物理空间一样长的物理地址),具有了mmu功能,于是,iommu就诞生了。
同一个物理地址有了3个概念: CPU看到的va,设备看到的dma地址(iova),总线看到的pa。

io地址 in dpdk

DPDK是一个用户空间应用程序框架,因此使用 DPDK的软件使用常规虚拟地址。但是,DPDK 还提供了用户空间 PMD和一组 API,可以完全从用户空间执行 IO 操作。硬件不理解用户空间虚拟地址,它使用的IO地址是物理地址 (PA) 或 IO 虚拟地址 (IOVA)。

如果系统没有开启IOMMU,CPU使用的是MMU映射的VA,设备访问内存只能使用PA。
如果系统开启IOMMU,设备可以使用基于IOMMU映射的IOVA,可以用VA,也可以用PA。

DPDK API不区分物理地址和 IO 虚拟地址,并且始终将二者称为 IOVA,即使没有IOMMU来提供 VA 部分。但是,DPDK 区分了物理地址用作 IOVA 的情况和 IOVA 与用户空间虚拟地址匹配的情况。这些情况在 DPDK API 中称为 IOVA 模式,其中有两种:IOVA 作为 PA 和 IOVA 作为 VA。

IOVA 物理地址模式

当使用 IOVA 作为 PA 模式时,分配给所有 DPDK 内存区域的 IOVA 地址都是实际物理地址,虚拟内存布局与物理内存布局相匹配。

优点: 使用简单,它适用于所有硬件(即不需要 IOMMU),并且它与内核空间配合良好(将实际物理地址转换为内核空间地址很简单)。这是 DPDK 长期以来的工作方式,在许多方面它被认为是默认方式。

缺点一: 它需要特权(root 权限),DPDK 无法在没有系统页面映射访问权限的情况下获取内存区域的实际物理地址。
IOVA PA模式
缺点二: 虚拟内存布局遵循物理内存布局。这意味着,如果物理内存空间碎片化(即存在大量小段而不是少数大段),虚拟内存空间也会遵循该碎片化。在极端情况下,碎片化可能非常严重,以至于独立的物理连续段的数量耗尽了 DPDK 用于存储这些段信息的内部数据结构,DPDK 初始化就会失败。
IOVA PA模式 碎片示例

DPDK 社区的变通方法:
1)使用更大的页面大小减少碎片化影响(1GB大页比2MB大页有用)
2) 重新启动系统并在启动时而不是运行时保留大页面。
但是,上述变通方法都无法解决根本问题,所以大多数的时候,都是额外多分配一些大页内存。

IOVA 虚拟地址模式

IOVA 作为 VA 模式是一种不遵循底层物理内存布局的模式。相反,物理内存会重新排列,以匹配虚拟内存布局。DPDK EAL 依靠内核基础架构来实现这一点,而内核基础架构又使用 IOMMU 来重新映射物理内存。
IOVA VA模式
优点一: 所有内存都是 VA 和 IOVA 连续。这意味着任何需要大量 IOVA 连续内存的内存分配都更有可能成功,因为内存在硬件上看起来是 IOVA 连续的,即使底层物理内存可能不是。由于重新映射,IOVA 空间碎片化的问题变得无关紧要;无论物理内存碎片化程度有多严重,它总是被重新映射为 IOVA 连续的内存块。

优点二: 不需要任何特权,因为它不需要访问系统页面图。这允许以非 root 用户身份运行 DPDK,并且更容易在不需要特权访问的环境(例如云原生环境)中使用 DPDK。

缺点: 存在以下使用场景的限制
● 不支持使用 IOMMU 的硬件
● 平台可能首先没有 IOMMU(例如,没有 IOMMU 模拟的虚拟机)
● 软件设备(例如 DPDK 的内核网络接口 (KNI) PMD)将不支持 IOVA 作为 VA 模式
● 某些 IOMMU(通常是模拟的)可能具有有限的地址宽度,这虽然不会阻止使用 IOVA 作为 VA 模式,但限制了其实用性
● 在 Linux 以外的操作系统上使用 DPDK

IOVA模式 和 DPDK PCI 驱动程序

DPDK 本身并不能完成所有硬件设备注册和中断映射;它需要内核的一点帮助。为此,DPDK 要使用的所有硬件设备都需要绑定到通用外围组件互连 (PCI) 内核驱动程序。通用部分意味着此驱动程序不会像常规驱动程序那样锁定到一组特定的PCI ID,而是可以与任何 PCI 设备一起使用。
Linux 上可用的驱动程序有:

  1. igb_uio 驱动程序
  2. uio_pci_generic 驱动程序
  3. VFIO 驱动程序

igb_uio

它是DPDK 代码库中最古老的内核驱动程序,自 DPDK 诞生之初就一直存在,因此它是使用最广泛驱动程序。
该驱动程序依靠内核UIO基础架构来工作,并支持所有中断类型(传统中断、消息信号中断 (MSI) 和 MSI-X),以及创建虚拟功能。它还通过/dev/uio文件系统公开硬件设备的寄存器和中断句柄,然后 DPDK EAL 使用这些寄存器和句柄将它们映射到用户空间并使其可用于 DPDK PMD。
igb_uio 驱动程序非常简单,功能不多。它不支持使用完整 IOMMU 模式,它只支持直通模式的 IOMMU,而且仅限于该模式在 IOVA 和物理地址之间建立了 1:1 的映射。因此,igb_uio 驱动程序仅支持 IOVA 作为 PA 模式,而根本无法在 IOVA 作为 VA 模式下工作。

uio_pci_generic

与 igb_uio 类似的内核驱动程序:uio_pci_generic。它的工作原理与 igb_uio 基本相同,只是功能更有限。例如,igb_uio 支持所有中断类型(传统、MSI 和 MSI-X),而 uio_pci_generic 仅支持传统中断。igb_uio 还可以创建虚拟功能,而 uio_pci_generic 不能;因此,如果在使用 DPDK 物理功能驱动程序时需要创建虚拟功能,不能使用uio_pci_generic。
因此,一般情况下,优先选择igb_uio。

vfio-pci

它是虚拟功能 I/O (VFIO) 内核基础架构的一部分,在 Linux 版本 3.6 中引入。VFIO 基础架构使设备寄存器和设备中断都可供用户空间应用程序使用,并且可以使用 IOMMU 设置 IOVA 映射以从用户空间执行 IO。此驱动程序是专门为与 IOMMU 一起使用而开发的,在较旧的内核上,如果不启用 IOMMU,它甚至无法工作。

它支持使用 VFIO 驱动程序允许同时使用 IOVA 作为 PA 和 IOVA 作为 VA 模式。这是因为,虽然建议使用 IOVA 作为 VA 模式来利用该模式的所有优势,但没有什么可以阻止 DPDK 的 EAL 以遵循 1:1 的物理内存布局的方式设置 IOMMU 映射;毕竟,IOVA 映射是任意的。在这种情况下,即使使用了 IOMMU,DPDK 也将在 IOVA 作为 PA 模式下工作,从而允许 DPDK KNI 之类的东西工作。但是,它仍然需要 root 权限才能使用 IOVA 作为 PA 模式。

在较新的内核(4.5+,已移植到一些较旧的版本)中,有一个enable_unsafe_noiommu_mode选项可用,允许在没有 IOMMU 的情况下使用 VFIO。此模式在所有意图和目的上都与基于 UIO 的驱动程序相同,并且具有它们所具有的所有相同优点和局限性。

小结

PCI驱动功能比较
驱动程序如何选择,基本流程如下:
PCI驱动程序选择流程图

IOVA in dpdk具体使用

DPDK中使用rte_mempool和rte_mbuf来管理报文的收发,设备dma收发数据的数据放在rte_mbuf中。

在rte_mbuf中,给pcie设备使用的iova,即rte_mbuf中是buf_iova字段。

struct rte_mbuf {
...
    void *buf_addr;           /**< Virtual address of segment buffer. */
#if RTE_IOVA_AS_PA
    /**
     * Physical address of segment buffer.
     * This field is undefined if the build is configured to use only
     * virtual address as IOVA (i.e. RTE_IOVA_AS_PA is 0).
     * Force alignment to 8-bytes, so as to ensure we have the exact
     * same mbuf cacheline0 layout for 32-bit and 64-bit. This makes
     * working on vector drivers easier.
     */
    rte_iova_t buf_iova __rte_aligned(sizeof(rte_iova_t));
#else
    ...
#endif
...
}

iova地址模式设置

dpdk应用启动的时候,可以通过设置参数–iova_mode=pa|va 来显式指定iova是使用物理地址还是虚拟地址。

如果没有传入这个参数,默认值是RTE_IOVA_DC,表示没有定义过。那么dpdk会根据系统当前的配置(有没有开启iommu、有没有vfio)启动选择地址模式。在大多数情况下,VA 和 PA 模式并不互相排斥,可以使用其中任何一种,但在某些情况下,IOVA 作为 PA 模式将是唯一可用的选项。如果无法使用 IOVA 作为 VA 模式,DPDK 会自动切换到 IOVA 作为 PA 模式,即使通过 EAL 参数请求使用 IOVA 作为 VA 模式。

总结

本文阐述了DPDK应用中,IO设备可以使用的地址模式,以及各个模式的差异性,地址模式和PCI驱动的关系。一般情况下,PA/VA各有长短,PA适用的场景更广,对环境依赖更少,VA则更具有安全性,更加灵活。具体使用哪种模式,视具体场景而定,并没有通用的方式。

  1. https://www.intel.com/content/www/us/en/developer/articles/technical/memory-in-dpdk-part-2-deep-dive-into-iova.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值