DPDK学习文档(逐步更新)

我也是第一次接触DPDK,只能边学习边总结吧,欢迎各位提出宝贵建议

DPDK的概念

DPDK(Data Plane Development Kit)数据平面开发套件;Intel 处理器架构下用户空间高效的数据包处理提供了库函数和驱动的支持,它不同于 Linux 系统以通用性设计为目的,而是专注于网络应用中数据包的高性能处理,DPDK的主要目标是为数据平面应用程序中的快速数据包处理提供一个简单,完整的框架。

DPDK的优点与缺点

传统网络模块结构和DPDK中的网络结构做对比

在这里插入图片描述
轮询模式取代中断,减少了内存拷贝次数,消除了IO吞吐瓶颈;
避免了内核态和用户态的报文拷贝;用户态下软件崩溃,不会影响系统的稳定性;
Intel提供的PMD驱动,充分利用指令和网卡的性能;
提供2M和1G的hugepages,增加TLB命中率,减少虚拟地址到物理地址的转换时间;
无锁化消息队列,提高多线程性能;
支持大多是intel网卡;

没有网络协议栈,这些都需要自己实现,目前也有一些比较成熟的应用层协议栈实现;
因为是轮询方式,cpu空转现象可能发生;
配置繁琐,如果绑定core和socket方案没有选择好,性能会大幅下降,主要是因为numa+uio架构等原因;

DPDK数据处理原理

DPDK是 Intel 针对芯片技术与高速网络接口技术飞速发展的应用场景而提出的数据平面加速理论框架(Intel Data Plane Development kit)。DPDK旨在对网络数据的高速处理,其中一个重要的技术就是零拷贝技术,将网络数据直接映射到内存空间。同时DPDK可以跳过内核空间,直接获取网卡数据到用户空间进行网络数据操作,大大的加快的网络数据处理速度。下图也是界定了DPDK的作用范围,主要是在物理网卡和内核空间中间,DPDK可以直接获取网卡数据到用户空间处理,同时也可以灵活的将网络数据写回内核走原来内核处理的流程。

在这里插入图片描述

DPDK技术

简单的讲解一下相关知识,后续文章去详细研究

大页(hugepage)

大页技术主要优势在于增加单页的数据量,主要运用于需要较大内存的运用场景可以减少页面的切换,提升查询效率。高速网络的数据存储场景正是需要较大的数据缓存,因此大页技术可以很好的提升其效率。
在这里插入图片描述

用户IO(UIO)

将网卡数据直接转移到用户态空间运行,应用程序和设备解耦。此技术作为DPDK的基石,LinuxUIO技术可以将网卡数据直接转移到用户空间,进行网络数据的处理。 DPDK 应用程序初始化中将网卡硬件寄存器映射到用户态内存空间,因此,DPDK 的驱动程序可以运行在用户态,可以避免不必要的内存拷贝。

KNI技术

KNI也是驱动模块,用于DPDK与系统内核协议栈建立通道,用户可以将网络数据回灌到内核协议栈处理。

核心组件

  1. 环形缓冲区管理(librte_ring)
    Ring数据结构提供了一个无锁的多生产者,多消费者的FIFO表处理接口。 他比无锁队列优异的地方在于它容易部署,适合大量的操作,而且更快。ring还用于不同核之间或是逻辑核上处理单元之间的通信。

  2. 内存池管理(librte_mempool)
    内存池管理的主要职责就是在内存中分配指定数目对象的POOL。 每个POOL以名称来唯一标识,并且使用一个ring来存储空闲的对象节点。 它还提供了一些其他的服务如对象节点的每核备份缓存及自动对齐以保证元素能均衡的处于每核内存通道上。

  3. 网络报文缓冲区管理(librte_mbuf)
    报文缓存管理器提供了创建、释放报文缓存的能力,DPDK应用程序中可能使用这些报文缓存来存储消息。 而消息通常在程序开始时通过DPDK的MEMPOOL库创建并存储。 BUFF库提供了报文申请释放的API,通常消息buff用于缓存普通消息,报文buff用于缓存网络报文。

  4. 定时器管理(librte_timer)
    这个库位DPDK执行单元提供了定时服务,为函数异步执行提供支持。 定时器可以设置周期调用或只调用一次。 使用EAL提供的接口获取高精度时钟,并且能在每个核上根据需要初始化。

  5. 以太网轮询驱动架构
    DPDK的PMD驱动支持1G、10G、40G。 同时DPDK提供了虚拟的以太网控制器,被设计成非异步,基于中断的模式

  6. 报文转发算法支持
    DPDK提供了哈希(librte_hash)、最长前缀匹配的(librte_lpm)算法库用于支持包转发。

  7. 网络协议库(librte_net)
    这个库提供了IP协议的一些定义,以及一些常用的宏。 这些定义都基于FreeBSD IP协议栈的代码,并且包含相关的协议号,IP相关宏定义,IPV4和IPV6头部结构等等

关于EAL(environment abstraction layer)环境适配层

环境适配层为底层资源如硬件和内存空间的访问提供了接口。 这些通用的接口为APP和库隐藏了不同环境的特殊性。 EAL负责初始化及分配资源(内存、PCI设备、定时器、控制台等等)。
EAL提供的典型服务有:

  1. DPDK的加载和启动:DPDK和指定的程序链接成一个独立的进程,并以某种方式加载。
  2. CPU亲和性和分配处理:DPDK提供机制将执行单元绑定到特定的核上,就像创建一个执行程序一样。
  3. 系统内存分配:EAL实现了不同区域内存的分配,例如为设备接口提供了物理内存。
  4. PCI地址抽象:EAL提供了对PCI地址空间的访问接口
  5. 跟踪调试功能:日志信息,堆栈打印、异常挂起等等。
  6. 公用功能:提供了标准libc不提供的自旋锁、原子计数器等。
  7. CPU特征辨识:用于决定CPU运行时的一些特殊功能,决定当前CPU支持的特性,以便编译对应的二进制文件。
  8. 中断处理:提供接口用于向中断注册/解注册回掉函数。
  9. 告警功能:提供接口用于设置/取消指定时间环境下运行的毁掉函数。

几乎DPDK其他模块的操作都会最终通过rte_eal模块;
在这里插入图片描述
EAL层初始化函数是rte_eal_init(), 它包括对pthread库的调用

环形缓冲区管理(librte_ring)

Ring数据结构提供了一个无锁的多生产者,多消费者的FIFO表处理接口。 他比无锁队列优异的地方在于它容易部署,适合大量的操作,而且更快。
环形缓冲区支持队列管理。rte_ring并不是具有无限大小的链表,它具有如下属性:

  1. 先进先出(FIFO)
  2. 最大大小固定,指针存储在表中
  3. 无锁实现
  4. 多消费者或单消费者出队操作
  5. 多生产者或单生产者入队操作
  6. 批量出队 - 如果成功,将指定数量的元素出队,否则什么也不做
  7. 批量入队 - 如果成功,将指定数量的元素入队,否则什么也不做
  8. 突发出队 - 如果指定的数目出队失败,则将最大可用数目对象出队
  9. 突发入队 - 如果指定的数目入队失败,则将最大可入队数目对象入队
    相比于链表,这个数据结构的优点如下:
    更快;只需要一个sizeof(void *)的Compare-And-Swap指令,而不是多个双重比较和交换指令
    与完全无锁队列像是
    适应批量入队/出队操作。 因为指针是存储在表中的,应i多个对象的出队将不会产生于链表队列中一样多的cache miss。 此外,批量出队成本并不比单个对象出队高。

缺点:
大小固定
大量ring相比于链表,消耗更多的内存,空ring至少包含n个指针

Mempool 库

Mempool是固定大小的对象分配器。 在DPDK中,它由名称唯一标识,并且使用mempool操作来存储空闲对象。Mempool的组织是通过三个部分实现的:

mempool对象节点:mempool的对象挂接在 static struct rte_tailq_elem rte_mempool_tailq 全局队列中,可以通过名字进行唯一标识符;此队列只是mempool的一个对象指示结构,并不是实际的内存区;

mempool实际内存区: struct rte_memzone 是实际分配的连续内存空间,存储所创建的mempool对象;

ring无锁队列:作为一个无锁环形队列 struct rte_ring ,存储着mempool对象的指针,提供了方便存取使用mempool的空间的办法。

显示了一个缓存操作。
在这里插入图片描述
如图所示,mempool的对象通过与ring无锁队列建立关联方便存取;同时,为了减少多核访问造成的冲突,引入了local_cache对象缓冲区。该local_cache非硬件上的cache,而是为了减少多核访问ring造成的临界区访问,

通过这种方式,每个core都可以访问自己空闲对象的缓存(带锁), 只有当缓存填充时,内核才需要将某些空闲对象重新放回到缓冲池ring,或者当缓存空时,从缓冲池中获取更多对象。

虽然这意味着一些buffer可能在某些core的缓存上处于空闲状态,但是core可以无锁访问其自己的缓存提供了性能上的提升。

coreX app会优先访问该local_cache上的对象。入队的时候优先入local_cache中,出队的时候优先从local_cache中出队

Mbuf库

Mbuf库提供了申请和释放mbufs的功能,为了高效访问数据,DPDK将内存封装在Mbuf(structrte_mbuf)结构体内。Mbuf主要用来封装网络帧缓存,也可用来封装通用控制信息缓存(ol_flags需要加上CTRL_MBUF_FLAG标志位)。
内存结构
https://www.cnblogs.com/ziding/p/4214499.html
buf由缓冲池rte_mempool管理,rte_mempool在初始化时一次申请多个mbuf,申请的mbuf个数和长度都由用户指定

rte_mempool_create("mbuf_pool", NB_MBUF,

MBUF_SIZE, 32,

sizeof(structrte_pktmbuf_pool_private),

rte_pktmbuf_pool_init, NULL,

rte_pktmbuf_init, NULL,

rte_socket_id(), 0);

“mbuf_pool”:创建的rte_mempool的名称。

NB_MBUF:rte_mempool包含的rte_mbuf元素的个数。

MBUF_SIZE:每个rte_mbuf元素的大小。

拷贝操作
dpdk接收报文并把报文上送上层应用的过程中,报文传输是“零拷贝”,即不需要拷贝报文内容,只需要传送mbuf地址。然而在一个报文上送给多个应用时,仍然需要对报文做拷贝并送给不同的应用。Librte_mbuf采用“复制rte_mbuf,共享data数据域”的方式实现报文的拷贝函数rte_pktmbuf_clone(),函数原型如下:

struct rte_mbuf *rte_pktmbuf_clone(struct rte_mbuf *md, struct rte_mempool *mp)

释放操作
用下面函数释放一个mbuf,释放过程即把mbuf归还到rte_mempool中:

void rte_pktmbuf_free(struct rte_mbuf *m);

这个库提供了一些操作数据包mbuf中的数据的功能。 例如:
获取数据长度
获取指向数据开始位置的指针
数据前插入数据
数据之后添加数据
删除缓冲区开头的数据(rte_pktmbuf_adj())
删除缓冲区末尾的数据(rte_pktmbuf_trim())

定时器库

定时器库为DPDK执行单元提供定时器服务,使得执行单元可以为异步操作执行回调函数。定时器库的特性如下:

定时器可以周期执行,也可以执行一次。
定时器可以在一个核心加载并在另一个核心执行。但是必须在调用rte_timer_reset()中指定它。
定时器提供高精度(取决于检查本地核心的定时器到期的rte_timer_manage()的调用频率)。
如果应用程序不需要,可以在编译时禁用定时器,并且程序中不调用rte_timer_manage()来提高性能。

实施细节
定时器以每个逻辑核为基础进行跟踪,并在跳表(skiplist)数据结构中按定时器到期的顺序维护核内的所有待处理定时器。使用的跳表有十个级别,并且表中的每个条目以(¼级)的概率出现在每个级别中。这意味着所有条目都存在于级别0中,每4个条目中就有1个存在于级别1中,每16个条目中就有1个存在于级别2中,依此类推,直到第9级为止。这意味着从一个定时器列表中添加和删除条目的时间复杂度为log(n),每个逻辑核最多能容纳410个条目,即约1,000,000个定时器。
定时器结构包含一个称为状态的特殊字段,该字段是定时器状态(已停止,挂起,正在运行,配置)和所有者(lcore id)的联合体。

union rte_timer_status {
    RTE_STD_C11
    struct {
        uint16_t state;  /**< Stop, pending, running, config. */
        int16_t owner;   /**< The lcore that owns the timer. */
    };
    uint32_t u32;            /**< To atomic-set status + owner. */
};

根据定时器的状态,我们知道列表中是否存在定时器:

STOPPED停止:没有所有者,不在列表中
CONFIG配置:由一个核拥有,不能被另一个核修改,在不在列表中未知,取决于先前的状态。
PENDING待处理:由一个核拥有,在列表中
RUNNING运行:由一个核拥有,不能被另一个核修改。在列表中。
不允许在CONFIG或RUNNING状态下重置或停止定时器。修改定时器的状态时,应使用CAS(比较并交换)指令来保证状态及所有者被原子地修改。

在rte_timer_manage()函数里面,跳跃表作为常规的链表,通过沿着包含所有计时器条目的第0层链表迭代,直到遇到尚未到期的条目为止。当列表中有条目,但是没有任何条目定时器到期时,为了提高性能,第一个定时器条目的到期时间保存在每个逻辑和计时器列表结构本身内部。在64位平台上,可以直接检查该值,而无需对整个结构进行锁定。(由于到期时间维持为64位值,所以在32位平台上无法直接对该值进行检查,而不使用(CAS)指令或使用锁机制,因此,一旦数据结构被上锁,此额外的检查将被跳过。)在64位和32位平台上,在调用逻辑核的计时器列表为空的情况下,对rte_timer_manage()的调用将直接返回而不进行锁定。

DPDK的源码目录结构
lib/ : DPDK的库源代码
drivers/ : DPDK轮询模式驱动程序源代码
app/ : DPDK应用程序源代码
examples/ : DPDK的一些应用程序例子源代码
config/ : DPDK关于arm和x86平台的一些编译配置
buildtools/ : DPDK一些编译配置的脚本
mk/ : DPDK的Makefile
usertools/ : DPDK提供给用户的一些实用工具

Lib目录包含如下等项目
文件库源码位于目录$(RTE_SDK)/lib中。按照惯例,库指的是为应用程序提供API的任何代码。通常,它会生成一个(.a)文件,这个目录中可能也保存一些内核模块。

lib 
+  -librte_cmdline       #命令行接口
+  -librte_distributor   #报文分发器
+  -librte_eal           #环境抽象层
+  -librte_ether         #PMD通用接口
+  -librte_hash          #哈希库
+  -librte_ip_frag       #IP分片库
+  -librte_kni           #内核NIC接口
+  -librte_kvargs        #参数解析库
+  -librte_lpm           #长期扩展库
+  -librte_mbuf          #报文及控制操作操作库
+  -librte_mempool       #内存池管理器
+ -  librte_meter         #QoS的计量库
+ -  librte_net           #IP相关的一些头部
+ - librte_power         #电源管理库
+  -librte_ring          #软件无锁环形机架
+  -librte_sched         #QoS调度器和丢包器库
+  -librte_timer         #计时器库

驱动
驱动程序是为设备(硬件设备或者虚拟设备)提供轮询模式驱动程序实现的特殊库。 他们包含在drivers子目录中,按照类型分类,各自编译成一个库,其格式为 librte_pmd_X.a ,其中 X 是驱动程序的名称。
驱动程序目录下有个 net 子目录,包括如下项目:

drivers/net
+-- af_packet          # 基于Linux af_packet的pmd
+-- bonding            # 绑定pmd驱动
+-- cxgbe              # Chelsio Terminator 10GbE/40GbE pmd
+-- e1000              # 1GbE pmd (igb and em)
+-- enic               # Cisco VIC Ethernet NIC Poll-mode Driver
+-- fm10k              # Host interface PMD driver for FM10000 Series
+-- i40e               # 40GbE poll mode driver
+-- ixgbe              # 10GbE poll mode driver
+-- mlx4               # Mellanox ConnectX-3 poll mode driver
+-- null               # NULL poll mode driver for testing
+-- pcap               # PCAP poll mode driver
+-- ring               # Ring poll mode driver
+-- szedata2           # SZEDATA2 poll mode driver
+-- virtio             # Virtio poll mode driver
+-- vmxnet3            # VMXNET3 poll mode driver
+-- xenvirt            # Xen virtio poll mode driver

部分 driver/net 目录包含一个base子目录,这个目录通常包含用户不能直接修改的代码。 任何修订或增强都应该X_osdep.c或X_osdep.h文件完成。请参阅base目录中本地的自述文件以获取更多的信息。

应用程序
应用程序是包含 main() 函数的源文件。 他们位于 $(RTE_SDK)/app 和 $(RTE_SDK)/examples 目录中。

应用程序目录包含用于测试DPPDK(如自动测试)或轮询模式驱动程序(test-pmd)的实例应用程序:

app
+-- chkincs            # Test program to check include dependencies
+-- cmdline_test       # Test the commandline library
+-- test               # Autotests to validate DPDK features
+-- test-acl           # Test the ACL library
+-- test-pipeline      # Test the IP Pipeline framework
+-- test-pmd           # Test and benchmark poll mode drivers

Example目录包含示例应用程序,显示了如何使用库:

examples
+-- cmdline            # Example of using the cmdline library
+-- exception_path     # Sending packets to and from Linux TAP device
+-- helloworld         # Basic Hello World example
+-- ip_reassembly      # Example showing IP reassembly
+-- ip_fragmentation   # Example showing IPv4 fragmentation
+-- ipv4_multicast     # Example showing IPv4 multicast
+-- kni                # Kernel NIC Interface (KNI) example
+-- l2fwd              # L2 forwarding with and without SR-IOV
+-- l3fwd              # L3 forwarding example
+-- l3fwd-power        # L3 forwarding example with power management
+-- l3fwd-vf           # L3 forwarding example with SR-IOV
+-- link_status_interrupt # Link status change interrupt example
+-- load_balancer      # Load balancing across multiple cores/sockets
+-- multi_process      # Example apps using multiple DPDK processes
+-- qos_meter          # QoS metering example
+-- qos_sched          # QoS scheduler and dropper example
+-- timer              # Example of using librte_timer library
+-- vmdq_dcb           # Example of VMDQ and DCB receiving
+-- vmdq               # Example of VMDQ receiving
+-- vhost              # Example of userspace vhost and switch

** 一些常用的缩写说明和术语说明**

  1. ACL:Access Control List,访问控制列表,是路由器和交换机接口的指令列表,用来控制端口进出的数据包;简而言之就是用来控制数据流。
  2. SSL:Secure Sockets Layer,安全套接层,是为网络通信提供安全及数据完整性的一种安全协议,在传输层对网络连接进行加密。
  3. RSS:Receive Side Scaling,是一种能够在多处理器系统下使接收报文在多个CPU之间高效分发的网卡驱动技术。
  4. NUMA:Non Uniform Memory Access Architecture,非统一内存访问架构;
  5. QOS:Quality of Service,服务质量,指一个网络能够利用各种基础技术,为指定的网络通信提供更好的服务能力, 是网络的一种安全机制, 是用来解决网络延迟和阻塞等问题的一种技术。
  6. NIC:Network Interface Card,网卡,网卡是局域网中最基本的部件之一,它是连接计算机与网络的硬件设备。
  7. PCI:Peripheral Component Interconnect,计算机一种标准总线,NIC就是使用的这种总线方式。
  8. PMD:Poll Mode Drive,轮询模式驱动,DPDK就是采用的这种模式。
  9. RTE:Run Time Environment,通过PMD实现快速分组处理数据的一个框架。
  10. MPLS:Multi-Protocol Label Switching,多协议标签交换,是一种用于快速数据包交换和路由的体系,它为网络数据流量提供了目标、路由地址、转发和交换等能力。更特殊的是,它具有管理各种不同形式通信流的机制。

DPDK详细介绍文档

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值