阅读 DPDK 中文论文两则

基于DPDK的高效数据包捕获技术分析与应用

本文应用场景

网络安全领域的数据包捕获技术,对系统有高性能需求,要在短时间内成功收集、分析、处理大量数据,实时捕获效率低下。

旧有传统数据包处理机制

  • BPF,伯克利封包处理器,是 Unix Linux 上的链路层的一种原始接口,许多功能以此为基础。
  • libpcap,linux 下的 C 语言网络数据包捕获函数库,大多数网络包分析软件以此为基础。
  • pf-ring 是 Luca Deri 发明的一种 API 函数库。

有所缺陷:

  • 在 Linux 内核中完成,导致程序要随着 Linux 的各种功能紧密耦合,难以维护,降低可移植性和通用性
  • 在内核网络协议栈中,涉及系统调用(用户应用程序角度)、中断(网卡驱动角度)、多次内存拷贝操作(内核中、cache 中)

DPDK

DPDK 是数据包转发处理套件。

  • 允许用户空间的进程通过 DPDK 的库直接访问网卡,无需经过内核(也就是所谓 bypass kernel,或user space stack)。
  • 首先明确一个概念,它不是协议栈,和 TCP/IP 不是对等的概念。不提供二层、三层转发功能、防火墙、ACL 等功能,但通过 DPDK 可以开发出上述功能。
  • 其次,它是一套强大的 user space driver,用户空间库和驱动程序。DPDK 总体来讲是一个二层应用。原本是网卡设备驱动、driver、kernel space、user space 的功能,移到 user space 来做了。当然,DPDK 也提供了很多三层 API,例如转发、LPM 等等。DPDK 的功能相当于 Linux 的设备无关接口层,处于 socket 之下,driver 之上。

主要有四个技术点:

  • 大内存页提高内存使用效率。
  • user space 实现绝大部分功能。
  • cpu affinity 实现将控制面线程以及各个数据面线程绑定到不同的 CPU 来避免反复调度、进出内核切换带来的性能消耗。
  • 实现从 driver -> kernal -> user space 过程中的 Zero copy。它直接从网卡驱动抓取数据,把一系列的工作放到用户态,使得 CPU 将更多的资源放在数据处理上,大大加快数据包处理速度。

主要部件:

  • rte_eal + libc 内存统一组织管理者
  • librte_ring 无锁队列
  • librte_mempool 提供内存池功能
  • librte_mbuf 提供缓冲区功能
  • librte_malloc 对外提供分配释放内存的API
  • librte_timer 主要用于各种服务间的同步

主要函数

  • rte_eal_init()
  • init_mbuf_pools()
  • init_ports(ports->id[i])
  • rte_eth_rx_brust(port_num, 0, buf, PACKET_READ_SIZE)

实验的 workflow 也比较清晰:

rte_eal_init()init_port()init_mbuf_pools() 进行 DPDK 、端口、内存池、队列初始化。利用rte_eth_rx_brust() 轮询各端口接收数据包。自定义函数process_packets()来对数据包进行一个初步处理。

接下面两张图是实验 topo:


基于多核平台的高速网络流量实时捕获方法

本文应用场景

网络数据包的实时采集和分析。

旧有解决方案

  • 基于专用定制化硬件,性能较好,成本较高,模块固定,扩展性差。
  • 基于软件,成本低。

传统的报文处理

  • Linux 网络协议栈的报文处理是典型的软件系统。

简述工作原理:

1
2
3
4
interrupt system call
driver ----------> kernel (protocol stack) <----------- user space(application)
<---------- ----------->
copy context switch copy(or sleep)

性能瓶颈分析:

  • 流量串行访问带来的性能瓶颈。涉及到现代 NIC 的接收端扩展(receiver-side scaling,RSS),使用这种技术,分组的捕获过程可以并行化,然而上层协议栈和用户程序对此没有很好的利用

图:RSS bottleneck

  • driver ~ kernel ~ user space 的的过程中,至少包含 2 次数据拷贝。一次复制消耗 500~2000 个 CPU 周期。
  • 内核态用户态的上下文切换,在每个包上面执行的系统调用产生的上下文切换消耗近 1000 个 CPU 周期。
  • 缺少内存本地化,在内存 copy 时,由于逐字拷贝导致 cache 一直被替换,cache 命中率低下。cache miss 导致额外 13.8% 的 CPU 周期。

可以看出,协议栈处理数据包时的拷贝操作是性能瓶颈。旧有方案不能很好地克服这些困难。

思考对传统模式的改进方向

  • 预分配、重用内存资源。(大页表、内存池)
  • CPU 亲和(CPU affinity)是一种技术,允许进程或线程在制定的处理器核心上运行。在本地核心中,cache 更容易命中,减少 cache miss。
  • 内存映射。应用程序的内存区域可以映射到内核态的内存区域,应用程序可以在没有中间副本的情况下进行读写,用这种方式使得应用直接访问网卡的 DMA 内存区域,这种技术叫零拷贝。也可以理解为 zero copy

这三点是同上一篇论文一样的,下面两点是这篇论文额外所涉及:

  • 数据包采用并行直接通道传递(特定 RSS 队列、特定 CPU 核心、特定用户程序)(这个特性在某一篇教程中有运用到,设置了多个虚拟网卡。)
  • 数据包批处理。以某种策略将数据包划分为组,主要是为了减少系统调用和上下文切换的次数,减少平摊处理和复制每个数据包的消耗。

这些中没有明确拿轮询出来提。轮询主要是避免 system call 引起的 context switch 的技术。

NAPI(new API) 是 Linux 2.6.0 内核之后采用的一种提高数据包处理性能的新技术,其核心就是使用中断和轮询组合收包

其假设场景是,一旦网卡开始接收到数据包,数据包就会以高频率到达,换言之,就是针对一直有数据包到达的网络环境做了优化,:网卡在接收到第 1 个数据包时将触发硬件中断,中断处理函数会将该网卡加入到设备轮询表中,同时,为了防止后续到达的数据包触发频繁的硬件中断,需要用一条指令设置该中断使之不再接收中断请求;随后,操作系统会触发一个软中断,软中断的处理函数将对轮询表上的设备进行轮询,检查是否有数据包到达并处理;直到本次处理的 cpu 时间片用尽或者数据包的处理过程结束,网卡才重新设置中断屏蔽位开中断接收中断请求.

不过,上述技术还是有缺陷的,频繁的软中断在更高要求的网络环境下也无力了。所谓软中断就是还是有进出内核的操作,不是完全 user space 不是完全 zero copy。

DPDK 数据平面开发套件

队列管理rte_ring 无锁队列,环形,大小固定,先进先出,支持无锁,单/多生产者/消费者的排队场景,存储对象的指针。各个 P C 有指针来访问控制。相较于普通的用长度不限的双链表实现的队列,有两个好处:

  • 无锁机制
  • 减少了由于突发操作和大量数据传输导致的 cache miss

环境抽象层EAL是 DPDK 的一个核心。建立物理内存的映射,是在 DPDK 库之上构建应用时使用的内存的基本单元。每个 CPU 核心对 rte 内存池保有一个本地 cache,这也是为什么要 cpu affinity 和采用批处理的原因。

缓存管理rte_mbuf 用来访问某一个 mempool。

关于核心组件,打算之后要深入看源码,先贴上关于这一部分的一个缩略图。

参考链接:here

网络流捕获系统设计

系统总体设计:可维护、可靠、灵活、可重用

  • 数据包接收、处理模块

收包 workflow

采用轮询替代中断和系统调用来收包,所以收包模式是:程序主动调用rte_eth_rx_burst()接口去接受一定数量的数据包,需要对其进行封装,接收到一个包作为一个事件,触发一系列挂载在上面的回调函数对数据包进行处理。

多线程:一个local_main()不断在每个核心上运行,循环地接受包,在收到包的时候调用rte_eth_rx_burst()处理每个包,根据每个包的包头再调用不同的函数进行处理(parser)

而后的数据包处理模块,每一种报文解析的应用就是一种数据包处理模块,例如解析 http 协议的 http 模块、处理 DNS 的 DNS 模块等,各种不同的模块需要有统一设计和接口,内部解析逻辑各有区别

  • 内存管理模块

设计两个全局大页内存池,分别是 TCP 流报文池和普通报文池。报文存储在内存池,在队列中存储报文的地址。

  • 改进 hash 算法

RSS 机制现有一个问题就是会将同一个 TCP 连接的数据包映射到不同的网卡队列。本文改进了一种 hash 算法,将同一 TCP 连接的数据包映射到同一个网卡 RSS 队列。

  • 实验框架

实验分析

新系统无论在 cpu 使用率和系统吞吐率还是在丢包率上相比传统数据包捕获系统都有很大优势。

第二篇论文中提到了 DPDK 的系统在试验中相较于 Linux 的内核有 10 倍以上的吞吐量提升。

本次收获

更加了解了 DPDK 的创新点和工作原理,对于如何用 DPDK 做出基本的网络流量捕获有一个大概的了解。

深刻理解一定的操作系统知识对于理解 DPDK 的创新点非常必要且重要,列出以供参考:

1
2
3
4
5
6
7
8
9
I/O 驱动
中断
系统调用
内核空间、用户空间
cache
进程、线程
虚拟内存、页表
上下文切换
单/多生产者消费者、读者写者等经典信号量同步问题

文献:

  • [1] 赵 宁, 谢淑翠, 基于 DPDK 的高效数据包捕获技术分析与应用 [J].计算机工程与科学, 2016, 38(11): 2209-2215.
  • [2] 令瑞林 李峻峰 李 丹, 基于多核平台的高速网络流量实时捕获方法 [J].计算机研究与发展, 2017, 54(6): 1300-1313.