美文网首页
DPDK与SPDK(三)DPDK技术原理简介

DPDK与SPDK(三)DPDK技术原理简介

作者: hcci | 来源:发表于2023-09-17 16:04 被阅读0次

    DPDK 是intel 基于其自家 x86 芯片上开发的一系列的用于快速包处理的驱 动及相关基础库。DPDK 大部分跑在linux 用户态(除 UIO 接口部分会跑在内核态),目前 DPDK 以 BSD license 对外分发,它包括以下几个主要的组件:

    . multicore framework:多核框架, dpdk 库面向 intel i3/i5/i7/ep 等 多核架构芯片,内置了对多核的支持

    . hugepage memory: 内存管理,dpdk 库基于 linux hugepage 实现了一套 内存管理基础库,为应用层包处理做了很多优化

    . ring buffers:共享队列,dpdk 库提供的无锁多生产者-多消费者队列, 是应用层包处理程序的基础组件

    . poll-mode drivers:轮询驱动, dpdk 库基于 linux uio 实现的用户 态网卡驱动

    这些库被用于:

    . 在最小的 CPU cycles 内发送或是接收数据包(通常小于 80 个 cycles, DDIO 功能实现)

    . 开发快速的报文捕获算法(如 tcpdump 之类的)

    . 用于加速第三方的协议栈

    典型的 DPDK 组件如下图所示:

    上图中 DPDK Libraries 及 Environment Abstraction Layer 均为 DPDK 提供,其中 EAL 模块必须是最先初始化的代码, 同一系统下只有一个 EAL 进程为主进程, 其它的均为 slave 进程。内核态 EAL 为一驱动,需要事先加载。这部分详见后文

    描述。下面分别对 DPDK 的各个组件进行简单的介绍。

    环境抽象层概述

    环境抽象层(Environment Abstraction Layer)提供了一层通用的接口给 DPDK 的各种库使用, 同时屏蔽了硬件的各种形态带来的差异化,它提供了以下服务:

    . DPDK 的加载及各个 core 间的分发

    . CPU CORE 的亲和设置

    . 系统内存的申请及描述

    . 原子操作及锁操作

    . 时间参考源

    . PCI 总线访问

    . Trace 及 debug 功能

    核心组件分析

    从上图中可以看出, DPDK 所有的核心组件均基于 EAL,通过 EAL 提供的相关 功能, DPDK 提供了 timer,malloc,mempool,mbuf,ring,debug 等核心功能, 另外上图中没有画出的功能还有 FLOW classification 功能,此功能在当前 DPDK(1.7.0)版本中暂未提供,后续版本中会实现;另外关于 POLL-MODE driver  在上图中也没有描述, 在接下来的文档中, 会有详细的描述。上图中的核心组件

    分别简要描述如下:

    . 内存管理(librte_malloc):提供 API 从堆中申请内存

    . Ring 管理(librte_ring):从特定大小的表中申请无锁 FIFO。

    . 内存池管理(librte_mempool):从内存中申请对象池,每个内存池由

    name 及一个 ring 组成。可提供基于 core 的对象 cache 及对齐,能够保 证对象在所有的 RAM 通道的一致性。

    . 网络报文缓冲管理(librte_mbuf):提供基于 DPDK 的应用存储消息所需 的 buffer 的创建及销毁, 所有的 mbuf 都存储在内存池中,使用 DPDK  的内存池管理(librte_mempool)。

    . 定时器管理(librte_timer):向 DPDK 的应用提供定时器服务用于执行异 步功能,它使用 EAL 模块提供的 HPET 接口来获取精确的时间参考源。

    DPDK 的 C 运行库选用的是 newlib,一个是基于 license 的考虑,newlib 使用的是 BSD 的 license,另外就是在嵌入式的系统里面, newlibc 也能够有比较 优秀的表现,可方便基于 DPDK 的 APP 的移植。Newlib 的所有库函数都建立在 20 个桩函数的基础上,这 20 个桩函数完成一些 newlib 无法实现的功能:

    1) I/O 和文件系统访问(open、close、read、write、lseek、stat、fstat、 fcntl、link、unlink、rename);

    2) 扩大内存堆的需求(sbrk)

    3) 获得当前系统的日期和时间(gettimeofday、times);

    4) 各种类型的任务管理函数(execve、fork、getpid、kill、wait、_exit);

    这 20 个桩函数在语义、语法上与 POSIX 标准下对应的 20 个同名系统调用是 完全兼容的。 Newlib 为每个桩函数提供了可重入的和不可重入的两种版本。两种版本的区别在于, 如果不可重入版桩函数的名字是 xxx,则对应的可重入版桩 函数的名字是_xxx_r,如 close 和_close_r,open 和_open_r,等等。此外, 可 重入的桩函数在参数表中含有一个_reent 结构指针,这个指针使得系统的实现者能在库和目标操作环境之间传送上下文相关的信息,尤其是发生错误时, 能够 便捷的传送 errno 的值到适当的任务中。 DPDK 内使用的大多数是可重入版本的桩函数。

    DPDK环境抽象层

    环境抽象层用于 APP 访问底层资源, 如硬件、内存等。它提供了一种通用的 接口来屏蔽底层硬件或是库定义的接口,用于初始化运行环境(内存空间、 PCI设备、定时器、控制台等)。

    典型的 EAL 层提供的服务包括:

    . DPDK 的加载与运行: intel DPDK 必须与应用程序一起链接成一个 APP, 并且必须以某种方式来进行加载并运行。

    . 核的亲和设置及工作分配: EAL 提供一种机制将特定的执行单元分配到 不同的 core 运行。

    . 系统内存预留: EAL 预留不同的内存区域供使用,如预留物理内存给设 备交互使用。

    . PCI 地址抽象: EAL 提供接口去访问 PCI 设备的地址空间。

    . 公用接口:提供 libc 里没有的 spinlock 及原子操作

    本章节仅主要介绍 EAL 实现的功能, 其中会涉及到多个库的实现, 关于这些库的详细实现,请见后面原理分析章节,本章节只做简要描述。

    LIBC与EAL的区别

    从前面的描述中,我们可以看出 libc 实际上也完也了 EAL 提供的相关接口, 关于它们之间的区别实际上是很,对于一个应用程序来说,使用 EAL+LIBC 基本上就可以使用任何应用程序或是库的接口了:

    C 标准库基本上提供了通用的操作, 如输入/输出、字符处理、类型以及 ISOC 标准里面定义的功能。

    而 EAL 是 DPDK 特定使用的,提供了一系列访问特定硬件或是在用户态访问内核的接口供 APP 使用。

    在实际的应用编写过程中, 可以灵活的使用这两种方式, 下图是一个典型的混合用 libc+EAL 的程序框架。

    EAL加载过程

    在 linux 用户态的运行环境,DPDP 所有的实例都使用 pthread 库来运行,PCI设备所有的信息及地址空间的发布是通过内核提供的/sys 下面的文件接口来实 现的。同时 EAL 使用 hugetlbfs 来保留一段内存,然后通过 mmap 的方式来使用 这些物理内存,并且使用了 huge page 来提高性能, mmap 出来的内存会暴露给 DPDK 的 mempool 使用。DPDK 被初始化后,会通过 pthread 的调用将特定的执行单元绑定到逻辑 core 上去作为用户态的线程运行。

    下图是 linux 用户态模式下基于DPDK 的APP 初始化及 core 任务分发的过程:

    在 APP 运行的时候, 首先调的是 main 函数,这个是 glibc 调用,然后在main 函数内部会去调用 ret_eal_init,这个函数是 DPDK 环境建立起来的初始化函数, 会进行 core 的初始化及任务分发操作、内存初始化、LOG 初始化、PCI 设备初始 化等操作,这些和硬件强相关的操作完成后,就会根据 core 的数量及配置文件 进行线程的创建及线程的绑定, 然后紧接着进行其它库及驱动的初始化,所有初 始化完成后,就会将最小的执行单元通过 rte_eal_remote_lanch 分发到不同的core 上去执行。

    需要注意的是, 在PCI 访问的时候, EAL 是使用的/sys(具体点就是 /sys/bus/pci 及/sys/bus/pci_express)下面的文件去扫描总线上的 PCI 设备,而访问 PCI 设备的内存则是通过 UIO 或是 libpciaccess 来实现的。

    注: DPDK 也可以用在裸环境下面,即没有任何操作系统的环境,在这种环境下 需要将 DPDK 的镜象通过 GRUB 来进行引导。由于我们没有使用这个功能,本文暂不介绍。

    内存分片介绍

    由于与硬件交互时必须要使用连续的物理内存,而DPDK的内存申请是依赖 OS 的机制的(如 huge page),OS 并没有办法保证所有申请的物理内存的地址是 连续的(因为有空洞存在),所以申请的内存是以在一个表中的多个描述符的形 式进行分片组织起来的, 每一个分片描述符(rte_memseg)表示了一部分物理内 存、虚拟地址都连续,并且都在同一个socket,pagesize 也相同的 hugepage页面的集合,这样做的好处就是优化内存。而memzone 是通过 rte_memzone_reserve 来从 rte_memseg 中分配那些基 dpdk hugepage 的属于同一个物理 cpu 的物理内存连续的虚拟内存也连续的一块 地址。Memzone 是 DPDK 内存管理最终向用户程序提供的基础接口, ret_mempool内的组件均依于 rte_memzone 来实现。

    相关文章

      网友评论

          本文标题:DPDK与SPDK(三)DPDK技术原理简介

          本文链接:https://www.haomeiwen.com/subject/zfavvdtx.html