Post

DPDK 与 内存管理知识点汇总(ai)

DPDK 与 内存管理知识点汇总

DPDK 与 内存管理知识点汇总(ai)

DPDK 与 内存管理知识点汇总

本文档整理了关于 malloc 与大页内存、DPDK Bifurcated Driver、VFIO-PCI Virtual Functions 以及 VFIO Platform 的相关概念。

1. 普通 malloc 函数能使用大页内存吗?

普通的 malloc 函数默认情况下不会直接使用大页内存(Huge Pages),它通常分配的是标准的 4KB 页面。

但是,可以通过以下几种方式让 malloc 或者程序利用大页内存,而无需修改代码中对 malloc 的调用:

1.1 透明大页 (Transparent Huge Pages - THP)

这是最常见且无需修改代码的方法。

  • 原理:Linux 内核会自动尝试将大的连续内存分配(由 malloc 底层调用的 mmapsbrk 产生)通过大页(通常是 2MB)来映射,而不是使用 4KB 小页。
  • 如何启用: 确保系统开启了 THP:
    1
    2
    
    cat /sys/kernel/mm/transparent_hugepage/enabled
    # 如果显示 [always] 或 [madvise],则说明已启用
    

    如果是 [madvise],则程序需要显式调用 madvise(..., MADV_HUGEPAGE) 才能生效。如果是 [always],系统会尽可能为所有程序使用大页。

1.2 使用 libhugetlbfs (通过 LD_PRELOAD)

这个库可以“劫持”系统调用,让 malloc 使用大页,而不需要改写源代码。

  • 原理:它重载了 malloc 相关的底层内存申请行为,将其重定向到大页内存池(HugeTLB)。
  • 使用方法
    1
    2
    
    # 假设你已经分配了足够的大页 (在 /proc/sys/vm/nr_hugepages 中设置)
    LD_PRELOAD=libhugetlbfs.so HUGETLB_MORECORE=yes ./your_program
    

1.3 使用支持大页的高性能分配器 (如 jemalloctcmalloc)

  • Jemalloc:可以通过配置让其更好地配合大页工作。
    • 配合 THP:Jemalloc 默认就很适合配合 THP 使用。
    • 显式大页:新版本的 Jemalloc 支持通过配置项直接申请大页(依赖于内核支持)。

1.4 代码级修改 (非普通 malloc)

如果你愿意修改代码,可以使用以下方式替代 malloc

  • mmap with MAP_HUGETLB:直接向操作系统申请大页。
  • DPDK 方式:DPDK 通常不走 malloc,而是自己管理大页内存池(如 rte_malloc)。

2. DPDK 中的 Bifurcated Driver (分叉驱动)

“Bifurcated Driver” 是一种特殊的驱动架构,旨在将网络设备(NIC)的数据面和控制面功能分离

2.1 核心概念

  1. 数据面 (Data Plane):负责高性能的数据包处理(收发、查找)。通常由用户空间驱动(如 PMD)直接访问网卡硬件,实现零拷贝和最小延迟。
  2. 控制面 (Control Plane):负责网卡的配置、管理(IP、链路状态、ethtool)。通常由内核驱动(如 Linux 标准驱动)处理。

2.2 为什么需要它?

  • 解决痛点:传统的内核驱动数据路径太慢(上下文切换、中断),而纯用户空间驱动又难以实现完整的控制面功能(如难以使用 ifconfig/ip 等标准工具)。
  • 优点
    • 高性能:数据面绕过内核。
    • 兼容性:保留内核驱动管理网卡的能力,允许使用标准 Linux 工具管理接口。
    • 安全与隔离:控制面操作依然经过内核安全检查。

3. vfio-pci 的 Virtual Functions (VFs)

vfio-pci 的语境下,Virtual Functions (VFs) 是基于 SR-IOV (Single Root I/O Virtualization) 技术的一个核心概念。

3.1 PF vs. VF

  • PF (Physical Function):物理网卡本身。拥有完全控制权(全局配置、创建 VF)。
  • VF (Virtual Function):由 PF 创建的轻量级“虚拟”网卡实例。
    • 在 OS 看来是独立的 PCIe 设备。
    • 拥有独立的收发队列(Rx/Tx Queues)。
    • 不能更改物理链路等全局配置。

3.2 VF 与 vfio-pci 的结合用途

  1. 虚拟机设备透传 (PCI Passthrough):将 VF 直接分配给虚拟机,虚拟机获得接近物理硬件的网络性能。
  2. 高性能用户空间网络 (DPDK):DPDK 程序通过 vfio 接口直接接管 VF,实现内核旁路(Kernel Bypass),同时宿主机保留 PF 用于管理。

3.3 类比

  • PF 是公寓大楼的管理员(有大门钥匙,管水电)。
  • VF 是大楼里的独立房间
  • vfio-pci房卡,让租客(VM 或 DPDK)直接进出房间,无需每次经过管理员批准。

4. VFIO Platform

VFIO Platform 是 Linux 内核 VFIO 框架的一个子模块,作用与 vfio-pci 相似,但针对的是 Platform 设备

4.1 PCI vs. Platform 设备

  • PCI 设备 (vfio-pci):可自动发现(扫描总线),有标准配置空间和复位机制。常见于 PC/服务器(独立显卡、网卡)。
  • Platform 设备 (vfio-platform):通常不可自动发现(依赖 Device Tree),集成在 SoC 内部。常见于 ARM 嵌入式/边缘设备(SoC 内置网卡、加密引擎)。

4.2 核心功能与难点

  • 功能:将 SoC 内部的硬件模块安全地暴露给用户空间(用于虚拟机直通或用户态驱动)。
  • 难点 (Reset):Platform 设备没有统一的硬件复位标准。vfio-platform 必须依赖特定的 Reset 驱动逻辑来确保设备在分配给用户前被重置,防止状态残留。

4.3 总结对比

| 特性 | VFIO-PCI | VFIO-Platform | | :— | :— | :— | | 针对设备 | 独立 PCIe 设备 | SoC 内部集成设备 | | 常见架构 | x86 服务器 | ARM / 嵌入式 | | 设备发现 | 自动扫描 | Device Tree / ACPI |


5. uio_pci_generic 与 igb_uio 的区别

uio_pci_genericigb_uio 都是用于将 PCI 设备暴露给用户空间(Userspace I/O - UIO)的驱动程序,尤其在 DPDK (Data Plane Development Kit) 中被用来实现高性能网络。

5.1 uio_pci_generic

  • 通用性:这是一个通用的 UIO 驱动。设计目标是尽可能支持任何 PCI 设备。它不关心设备的具体类型或功能,只是简单地将设备的 PCI 配置空间、BAR (Base Address Registers) 映射到用户空间。
  • 功能:提供一个通用的接口,允许用户空间的应用程序(如 DPDK)直接访问设备的内存映射寄存器和中断。
  • 局限性
    • 安全性较低:无法对设备进行细粒度的隔离或管理。
    • 缺乏设备感知:不知道如何正确地复位(reset)一个 PCI 设备,或处理设备特定的中断。
    • 不支持 IOMMU:通常不与 IOMMU 配合使用,无法提供内存保护和 DMA 重新映射功能。

5.2 igb_uio

  • 专用性:这是一个专为 Intel igbixgbe 系列网卡(即 1GbE 和 10GbE Intel 网卡)设计的 UIO 驱动。
  • 功能:除了提供用户空间访问设备的能力外,还包含了特定于这些 Intel 网卡的逻辑,例如设备复位、中断处理和 PCIe 功能处理。
  • 优势
    • uio_pci_generic 更稳定:能更好地管理和控制这些特定的 Intel 网卡。
    • DPDK 优选:在 vfio-pci 出现之前,是 DPDK 用于 Intel 网卡的首选驱动。

5.3 主要区别总结

特性uio_pci_genericigb_uio
设备支持任何 PCI 设备专为 Intel igbixgbe 系列网卡
通用性通用,不关心设备类型专用,包含设备特定逻辑
设备管理用户空间需处理所有设备特定逻辑内核驱动包含设备复位、中断处理等逻辑
安全性较低较高(针对特定设备)
IOMMU 支持
使用场景调试、对安全性要求不高的通用设备 UIO早期 DPDK 用于 Intel 网卡

5.4 现代 DPDK 的首选:vfio-pci

在现代的 DPDK 场景中,uio_pci_genericigb_uio 都已经被更先进、更安全的 vfio-pci 驱动所取代,其优势在于基于 IOMMU 的强大内存隔离和 DMA 保护,以及更好的设备复位和厂商中立性。


6. EAL: VFIO group is not viable 错误解析

当 DPDK 打印 EAL: ... VFIO group is not viable! Not all devices in IOMMU group bound to VFIO or unbound 这样的错误时,表示在尝试使用 vfio-pci 驱动时遇到了 IOMMU Group 隔离性问题

6.1 错误含义分解

  • EAL: ... VFIO group is not viable!:DPDK 发现你尝试接管的 PCI 设备(例如 0000:02:02.0)所在的 IOMMU Group 处于“不可用”状态。
  • Not all devices in IOMMU group bound to VFIO or unbound:这是核心原因。VFIO 的安全规则要求,如果一个 IOMMU Group 中的任何一个设备要绑定到 vfio-pci,那么该 Group 中的所有其他设备都必须满足以下条件之一:
    1. 也被绑定到 vfio-pci
    2. 没有绑定任何驱动(Unbound)。
      • 如果同组中有其他设备正被宿主机的标准内核驱动控制,VFIO 会拒绝你的请求,以防止潜在的 DMA 攻击。
  • PCI_BUS: Requested device ... cannot be used:因此,DPDK 无法使用该设备。

6.2 排查和解决步骤

1. 找出 Group 内所有设备

查看设备(例如 0000:02:02.0)所属的 IOMMU Group 编号,并列出该 Group 下的所有设备:

1
2
readlink /sys/bus/pci/devices/0000:02:02.0/iommu_group
ls /sys/kernel/iommu_groups/<GROUP_NUM>/devices/

2. 检查“捣乱”设备的状态

确认同组中其他设备(例如 0000:02:02.1)当前被哪个内核驱动占用:

1
lspci -s 0000:02:02.1 -k

3. 解决方案

  • 方案 A:把同组的所有设备都给 VFIO (推荐):将 Group 内所有设备都解绑原驱动,并绑定到 vfio-pci
  • 方案 B:把同组的其他设备解绑 (Unbind):如果不需要同组的其他设备,只让其处于“unbound”状态。
    1
    
    echo "<PCI_ADDRESS>" > /sys/bus/pci/drivers/<KERNEL_DRIVER_NAME>/unbind
    
  • 方案 C:开启 PCIe ACS Override (高级/黑客做法):在内核启动参数中添加 pcie_acs_override=downstreampcie_acs_override=downstream,multifunction。这会强行让内核重新划分 IOMMU Group,但会降低硬件层面的隔离安全性。
  • 方案 D:使用 VFIO No-IOMMU 模式 (如果不关心安全):如果系统没有 IOMMU 或不关心安全隔离,可以开启 vfio-pci 的 No-IOMMU 模式 (modprobe vfio-pci enable_unsafe_noiommu_mode=1),但会使内核 “Tainted”。
This post is licensed under CC BY 4.0 by the author.