DPDK(Data Plane Development Kit)是数据平面开发工具包,由用于加速在各种CPU架构上运行的数据包处理的库组成。


在Linux上捕获数据包有多种方式,常见的有libpcap,pf-ring等。DPDK以高性能著称,想必相比传统的数据包捕获方式,一定有其独到之处。


本文主要就DPDK所使用的技术点进行宏观的说明,并将其与libpcap,pf-ring进行对比,若有写的不对的地方请帮忙指出。


参考文档:

[1]绝对干货!初学者也能看懂的DPDK解析

[2]Linux 设备驱动之 UIO 机制(基本概念)

[3]PF_RING学习笔记


若出现侵权请联系作者删除。


1.DPDK 技术特点


传统的数据包捕获瓶颈往往在于Linux Kernel,数据流需要经过Linux Kernel,就会带来Kernel Spcae和User Space数据拷贝的消耗;系统调用的消耗;中断处理的消耗等。


DPDK针对Linux Kernel传统的数据包捕获模式的问题,进行了一定程度的优化。DPDK的优化可以概括为:


UIO+mmap 实现零拷贝(zero copy)

UIO+PMD 减少中断和CPU上下文切换

HugePages 减少TLB miss

其他代码优化

2.UIO


2.1 UIO简介


UIO(Userspace I/O)是运行在用户空间的I/O技术。Linux系统中一般的驱动设备都是运行在内核空间,而在用户空间用应用程序调用即可,而UIO则是将驱动的很少一部分运行在内核空间,而在用户空间实现驱动的绝大多数功能。



图片引自百度百科

一个设备驱动的主要任务有两个:


存取设备的内存

处理设备产生的中断

如上图所示,对于存取设备的内存 ,UIO 核心实现了mmap();对于处理设备产生的中断,内核空间有一小部分代码用处理中断,用户空间通过read()接口/dev/uioX来读取中断。


2.2 DPDK UIO机制


采用Linux提供UIO机制,可以旁路Kernel,将所有报文处理的工作在用户空间完成。



图片引自参考文档[1]

如上图,左边是传统的数据包获取方式,路径为:

网卡 -> Kernel驱动 -> Kernel TCP/IP协议栈 -> Socket接口 -> 业务

右边是DPDK的方式,基于UIO。数据路径为:

网卡 -> DPDK轮询模式-> DPDK基础库 -> 业务


2.3 DPDK 零拷贝(Zero Copy)


通过UIO+mmap 实现数据零拷贝(zero copy)是DPDK的特点之一。那么常规的Linux Kernel(libpcap)以及pf-ring处理数据包的流程要进行几次数据拷贝呢?


libpcap

libpcap采用的是传统的数据包获取方式,如上图左边路径。

网卡接收到数据包后,第一步需要把数据从网卡拷贝到主存(RX buffer)中。但是在这个拷贝的过程中使用了DMA(Direct Memory Access)技术。DMA 传输将数据从一个地址空间复制到另外一个地址空间。由CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成,CPU是不需要参与,也不会产生CPU资源消耗。因此这个第一步的拷贝可以忽略。

第二步,Kernel会将网卡通过DMA传输进入主存(RX buffer)的内容拷贝一份进行处理,这里进行了一次数据拷贝。

第三步,由于内核空间和用户空间的内存是不共享的,Kernel会将数据包内容再进行一次拷贝用于用户空间使用。

综上,传统的数据包捕获方式(libpcap)会进行两次数据包拷贝。


pf-rfing

pf-ring采用mmap()将传统的两次拷贝减少至一次拷贝。

第一步,同样使用DMA技术,把数据从网卡拷贝到主存(RX buffer)中。

第二步,pf-ring会将网卡通过DMA传输进入主存(RX buffer)的内容拷贝一份放入环形缓冲区中(ring)中,这里进行了一次数据拷贝。

第三步,使用mmap()将环形缓冲区映射至用户空间,用户空间可以直接访问这个环形缓冲区中的数据。


pf-ring zc

pf-ring zc(zero copy)更是将pf-ring的一次拷贝也省去,达到了零拷贝的目的,具体的:

第一步,使用DMA技术,把数据从网卡拷贝到主存(RX buffer)中。

第二步,使用mmap()直接将RX buffer的数据映射到用户用户空间,使用户空间可以直接访问RX buffer的数据。

下图非常清晰地展示了pf-ring zc实现零拷贝的过程:



图片引自参考文档[3]

DPDK

DPDK实现零拷贝的方式与pf-ring zc类似,首先通过DMA将网卡数据拷贝至主存(RX buffer);随后使用mmap()直接将RX buffer的数据映射到用户用户空间,使用户空间可以直接访问RX buffer的数据,以此实现了零拷贝。


由上述可以看出,pf-ring zc和dpdk均可以实现数据包的零拷贝,两者均旁路了内核,但是实现原理略有不同。pf-ring zc通过zc驱动(也在应用层)接管数据包,dpdk基于UIO实现。