前言
作为高性能的数据转发面套件库,DPDK为了最大化发挥系统效能,它基于系统大页内存构建了自己独有的内存管理机制,并提供了常用的内存管理设施,包括Mempool、堆内存分配以及DMA内存管理等功能。
内存管理层次
DPDK的内存管理构筑于系统大页内存之上,应用程序在启动或运行时会向系统申请需要的大页内存,然后,DPDK会对这些内存进行层次化管理,构建完整的内存管理框架。DPDK管理内存的层次结构如下:
- 对于从系统中每个拿到的内存大页,DPDK会使用专门的数据结构进行描述,称为Memseg;
- Memseg只是单纯描述了物理大页内存,并不能直接由其它组件或上层应用使用,因此DPDK在Memseg上又构建了一套堆内存管理机制,在DPDK的代码中,使用Malloc_heap进行描述,同时向上提供堆内存分配接口;
- 其它的内存设施,如Memzone、Mempool则通过Malloc Heap申请内存,进行更精细的管理。
内存预留
DPDK使用Hugepage来实现大块连续物理内存的分配,因此DPDK需要在系统时确认大页内存的申请方式。针对启动时大页内存预留的方式,DPDK也经历了传统内存模式到动态内存模式的演进。在当前的DPDK版本,可以通过参数选择使用其中某一种模式。
传统内存模式
在早期的DPDK版本中,EAL在默认参数启动时会保留系统中所有可用的大页内存,并且不允许在运行时从系统获取或释放大页内存。此外,在这种模式下,EAL还会将所有申请的内存按照物理地址进行排序,从而构建一块巨大的IOVA连续的内存区域,以满足应用或驱动对IOVA连续内存的需求。
动态内存模式
在更新的DPDK版本中,EAL默认不启用传统内存模式来保留内存,转而切换到动态内存模式。在这种模式下,DPDK应用程序会根据实际应用的内存需求,动态增加和减少大页内存的使用。通过rte_malloc、rte_memzone_reserve或其它内存分配接口会自动从系统中保留更多的内存,并在不再需要时将内存释放回给系统。当然,在动态内存模式下分配的内存通常不会是IOVA连续的,如果驱动程序需要大块的IOVA连续内存块,则建议使用VFIO驱动。
IOVA模式
DPDK提供的是一个用户态驱动框架,因此就必然涉及到与硬件设备的交互。硬件设备无法使用用户空间的虚拟地址,驱动必须将申请的DMA内存虚拟地址转换为物理地址配置到硬件;在
有了IOMMU的支持后,硬件设备也可以使用虚拟地址,IOMMU负责完成IO虚拟地址到物理地址的转换。为了区分于CPU访问的虚拟地址,DPDK把设备使用的虚拟地址称作IOVA。
DPDK API对物理地址和IO虚拟地址不作区分,即使不是由IO内存管理单元(IOMMU)提供VA部分,也都以IOVA来代表两种地址;但DPDK内部使用IOVA模式来区分硬件设备使用的实际地址类型,当前定义的IOVA模式:PA模式和VA模式。
PA模式
作为PA的IOVA模式下,分配到整个DPDK存储区的IOVA地址都是实际的物理地址,而虚拟内存的分配与物理内存的分配相匹配。
PA模式适用于所有硬件设备,因为设备访问的都是实际的物理地址,中间不需要再有额外的地址转换。实际上,这就是DPDK长期以来的运作方式,在很多方面它都被认为是默认的选项。
VA模式
VA模式不需要再关心底层物理内存的布局,DPDK从系统分配物理内存,然后利用IOMMU硬件将物理内存映射到IO虚拟地址。设备访问IO虚拟地址,IOMMU会自动完成地址转换。