DPDK 与 内存管理知识点汇总(ai)
DPDK 与 内存管理知识点汇总
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底层调用的mmap或sbrk产生)通过大页(通常是 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 使用支持大页的高性能分配器 (如 jemalloc 或 tcmalloc)
- Jemalloc:可以通过配置让其更好地配合大页工作。
- 配合 THP:Jemalloc 默认就很适合配合 THP 使用。
- 显式大页:新版本的 Jemalloc 支持通过配置项直接申请大页(依赖于内核支持)。
1.4 代码级修改 (非普通 malloc)
如果你愿意修改代码,可以使用以下方式替代 malloc:
mmapwithMAP_HUGETLB:直接向操作系统申请大页。- DPDK 方式:DPDK 通常不走
malloc,而是自己管理大页内存池(如rte_malloc)。
2. DPDK 中的 Bifurcated Driver (分叉驱动)
“Bifurcated Driver” 是一种特殊的驱动架构,旨在将网络设备(NIC)的数据面和控制面功能分离。
2.1 核心概念
- 数据面 (Data Plane):负责高性能的数据包处理(收发、查找)。通常由用户空间驱动(如 PMD)直接访问网卡硬件,实现零拷贝和最小延迟。
- 控制面 (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 的结合用途
- 虚拟机设备透传 (PCI Passthrough):将 VF 直接分配给虚拟机,虚拟机获得接近物理硬件的网络性能。
- 高性能用户空间网络 (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_generic 和 igb_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
igb和ixgbe系列网卡(即 1GbE 和 10GbE Intel 网卡)设计的 UIO 驱动。 - 功能:除了提供用户空间访问设备的能力外,还包含了特定于这些 Intel 网卡的逻辑,例如设备复位、中断处理和 PCIe 功能处理。
- 优势:
- 比
uio_pci_generic更稳定:能更好地管理和控制这些特定的 Intel 网卡。 - DPDK 优选:在
vfio-pci出现之前,是 DPDK 用于 Intel 网卡的首选驱动。
- 比
5.3 主要区别总结
| 特性 | uio_pci_generic | igb_uio |
|---|---|---|
| 设备支持 | 任何 PCI 设备 | 专为 Intel igb 和 ixgbe 系列网卡 |
| 通用性 | 通用,不关心设备类型 | 专用,包含设备特定逻辑 |
| 设备管理 | 用户空间需处理所有设备特定逻辑 | 内核驱动包含设备复位、中断处理等逻辑 |
| 安全性 | 较低 | 较高(针对特定设备) |
| IOMMU 支持 | 无 | 无 |
| 使用场景 | 调试、对安全性要求不高的通用设备 UIO | 早期 DPDK 用于 Intel 网卡 |
5.4 现代 DPDK 的首选:vfio-pci
在现代的 DPDK 场景中,uio_pci_generic 和 igb_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 中的所有其他设备都必须满足以下条件之一:- 也被绑定到
vfio-pci。 - 没有绑定任何驱动(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=downstream或pcie_acs_override=downstream,multifunction。这会强行让内核重新划分 IOMMU Group,但会降低硬件层面的隔离安全性。 - 方案 D:使用 VFIO No-IOMMU 模式 (如果不关心安全):如果系统没有 IOMMU 或不关心安全隔离,可以开启
vfio-pci的 No-IOMMU 模式 (modprobe vfio-pci enable_unsafe_noiommu_mode=1),但会使内核 “Tainted”。