dpdk报文处理流程:笔记

本文详细介绍了DPDK中数据包的收发流程,包括网卡与应用的交互、DMA操作、初始化配置、内存管理和优化策略。重点讲解了如何通过DMA和mmap实现零拷贝,以及如何通过PMD驱动和EAL组件提升性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://zhuanlan.zhihu.com/p/644896362 DPDK收发包流程分析 - 知乎 (zhihu.com)

 

通过DMA将网卡数据拷贝至主存(RX buffer);

使用mmap()直接将RX buffer的数据映射到用户用户空间,使用户空间可以直接访问RX buffer的数据,以此实现了零拷贝。

  • 数据包接收的大体流程:

数据包到达网卡

网卡经过DMA操作将数据包从网卡拷贝到收包队列(内存)

DPDK应用从收包队列中取包

  • 数据包发送的大体流程:
DPDK应用将数据包送到发包队列
网卡经过DMA操作将网卡队列(内存)中的数据包拷贝到网卡
数据包从网卡发出
  • 收发包流程中的关键操作,主要是网卡如何与DPDK应用交互:
网卡的初始化配置操作有哪些;
网卡的DMA操作怎么找到DMA 地址(数据包存放的硬件地址),进而将数据包拷贝到指定的硬件地址(内存)中,供DPDK读取;
DMA把数据包成功放到接收队列后如何通知DPDK应用(PMD驱动)去队列中读取;
DPDK应用((PMD驱动))从接收队列中取完数据包后,需要做哪些操作通知DMA为下一次存放包做准备;
DPDK应用((PMD驱动))将数据包送到发送队列中,需要做哪些预操作;
网卡DMA从发送队列中取包需要做哪些操作

 

 

DPDK之网卡收包流程 (baidu.com)

一个网络报文从网卡接收到被应用处理,中间主要需要经历两个阶段:

阶段一:网卡通过其DMA硬件将收到的报文写入到收包队列中(入队)阶段二:应用从收包队列中读取报文(出队)下面以ixgbe网卡在dpdk框架下工作为例,分别介绍下收包队列的构造、启动和收包三个流程。

手把手DPDK实现tcp/ip用户态协议栈 - 知乎 (zhihu.com)

  1. 初始化:在应用程序启动时,DPDK初始化了所有需要的硬件设备、线程和内存池等资源,并且为每个CPU核心分配一个独立的运行环境。
  2. 接收数据:当一个数据包到达网卡时,DPDK会将其缓存在一个环形缓冲区中,并通知应用程序有新数据到达。
  3. 数据包分类:应用程序根据预定义的规则对数据包进行分类(例如流量监控、负载均衡、安全检查等),并将它们发送到相应的队列中。
  4. 数据包处理:DPDK从队列中取出待处理的数据包,并使用用户空间驱动程序(userspace driver)进行数据包解析、协议转换和业务逻辑处理等操作。
  5. 数据包发送:完成处理后,DPDK将结果重新打包成网络报文,并通过网卡发送回网络中。
  6. 回收资源:当应用程序不再需要某些资源时,DPDK会将它们释放回内存池或者硬件设备中,以便其他线程或者进程使用。

基于 OS 内核的数据传输有什么弊端

  1. 中断处理。当网络中大量数据包到来时,会产生频繁的硬件中断请求,这些硬件中断可以打断之前较低优先级的软中断或者系统调用的执行过程,如果这种打断频繁的话,将会产生较高的性能开销。
  2. 内存拷贝。正常情况下,一个网络数据包从网卡到应用程序需要经过如下的过程:数据从网卡通过 DMA 等方式传到内核开辟的缓冲区,然后从内核空间拷贝到用户态空间,在 Linux 内核协议栈中,这个耗时操作甚至占到了数据包整个处理流程的 57.1%。
  3. 上下文切换。频繁到达的硬件中断和软中断都可能随时抢占系统调用的运行,这会产生大量的上下文切换开销。另外,在基于多线程的服务器设计框架中,线程间的调度也会产生频繁的上下文切换开销,同样,锁竞争的耗能也是一个非常严重的问题。
  4. 局部性失效。如今主流的处理器都是多个核心的,这意味着一个数据包的处理可能跨多个 CPU 核心,比如一个数据包可能中断在 cpu0,内核态处理在 cpu1,用户态处理在 cpu2,这样跨多个核心,容易造成 CPU 缓存失效,造成局部性失效。如果是 NUMA 架构,更会造成跨 NUMA 访问内存,性能受到很大影响。
  5. 内存管理。传统服务器内存页为 4K,为了提高内存的访问速度,避免 cache miss,可以增加 cache 中映射表的条目,但这又会影响 CPU 的检索效率。

DPDK解决方案 

  1. 控制层和数据层分离。将数据包处理、内存管理、处理器调度等任务转移到用户空间去完成,而内核仅仅负责部分控制指令的处理。这样就不存在上述所说的系统中断、上下文切换、系统调用、系统调度等等问题。
  2. 使用多核编程技术代替多线程技术,并设置 CPU 的亲和性,将线程和 CPU 核进行一比一绑定,减少彼此之间调度切换。
  3. 针对 NUMA 系统,尽量使 CPU 核使用所在 NUMA 节点的内存,避免跨内存访问。
  4. 使用大页内存代替普通的内存,减少 cache-miss。
  5. 采用无锁技术解决资源竞争问题。

 

核心部件库

该模块构成的运行环境是建立在 Linux 上,通过环境抽象层(EAL)的运行环境进行初始化,包括:HugePage 内存分配、内存/缓冲区/队列分配与无锁操作、CPU 亲和性绑定等;其次,EAL 实现了对操作系统内核与底层网卡 I/O 操作的屏蔽(I/O 旁路了内核及其协议栈),为 DPDK 应用程序提供了一组调用接口,通过 UIO 或 VFIO 技术将 PCI 设备地址映射到用户空间,方便了应用程序调用,避免了网络协议栈和内核切换造成的处理延迟。另外,核心部件还包括创建适合报文处理的内存池、缓冲区分配管理、内存拷贝、以及定时器、环形缓冲区管理等。

DPDK主要有六个核心组件:

  • 1、 环境抽象层(EAL):为DPDK其他组件和应用程序提供一个屏蔽具体平台特性的统一接口,环境抽象层提供的功能主要有:DPDK加载和启动;支持多核和多线程执行类型;CPU核亲和性处理;原子操作和锁操作接口;时钟参考;PCI总线访问接口;跟踪和调试接口;CPU特性采集接口;中断和告警接口等。
  • 2、 堆内存管理组件(Malloc lib):堆内存管理组件为应用程序提供从大页内存分配对内存的接口。当需要分配大量内存小块时,使用这些接口可以减少TLB缺页。
  • 3、 环缓冲区管理组件(Ring lib):环缓冲区管理组件为应用程序和其他组件提供一个无锁的多生产者多消费者FIFO队列API:Ring。Ring是借鉴了Linux内核kfifo无锁队列,可以无锁出入对,支持多消费/生产者同时出入队。
  • 4、 内存池管理组件(Mem pool lib):为应用程序和其他组件提供分配内存池的接口,内存池是一个由固定大小的多个内存块组成的内存容器,可用于存储相同对象实体,如报文缓存块等。内存池由内存池的名称来唯一标识,它由一个环缓冲区和一组核本地缓存队列组成,每个核从自己的缓存队列分配内存块,当本地缓存队列减少到一定程度时,从内存缓冲区中申请内存块来补充本地队列。
  • 5、网络报文缓存块管理组件(Mbuf lib):提供应用程序创建和释放用于存储报文信息的缓存块的接口,这些MBUF存储在内存池中。提供两种类型的MBUF,一种用于存储一般信息,一种用于存储报文信息。
  • 6、 定时器组件(Timer lib):提供一些异步周期执行的接口(也可以只执行一次),可以指定某个函数在规定的时间异步的执行,就像LIBC中的timer定时器,但是这里的定时器需要应用程序在主循环中周期调用rte_timer_manage来使定时器得到执行。定时器组件的时间参考来自EAL层提供的时间接口。

除了以上六个核心组件外,DPDK还提供以下功能:

  • 1) 以太网轮询模式驱动(PMD)架构:把以太网驱动从内核移到应用层,采用同步轮询机制而不是内核态的异步中断机制来提高报文的接收和发送效率。
  • 2)报文转发算法支持:Hash 库和LPM库为报文转发算法提供支持。
  • 3) 网络协议定义和相关宏定义:基于FreeBSD IP协议栈的相关定义如:TCP、UDP、SCTP等协议头定义。
  • 4)报文QOS调度库:支持随机早检测、流量整形、严格优先级和加权随机循环优先级调度等相关QOS 功能。
  • 5)内核网络接口库(KNI):提供一种DPDK应用程序与内核协议栈的通信的方法、类似普通Linux的TUN/TAP接口,但比TUN/TAP接口效率高。每个物理网口可以虚拟出多个KNI接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值