主流包处理硬件平台
硬件加速器:
对于本身规模化的固化功能具有高性能低成本的特点。
网络处理器:
提供了包处理逻辑软件可编程能力,在获得灵活性的同时兼具了高性能的硬件包处理。
网络处理器是专门为处理数据包而设计的可编程通用处理器,采用多核并行处理结构,常被用于通信领域各种任务,比如包处理、协议分析、路由查找、声音/数据的汇聚、防火墙、QoS等。其通用性表现在执行逻辑由运行时加载的软件决定,用户使用专用指令集即微码进行开发。
NPU具有高性能和高可编程性,但不同厂商不同架构的NPU微码规范不尽相同,开发人员成长和社区构建困难,微码向高级语言转换效果不理想。成本和特定领域特性限制了NPU市场规模。
多核处理器:
多核处理器在更为复杂多变的高层包处理上拥有优势,DPDK用软件的方式在通用多核处理器上演绎着数据包处理新篇章,其为软件定义的包处理提供了快速迭代的平台。
现代CPU性能的扩展主要是通过多核的方式进行演进的。这样通过处理器可以在一定程度上并行地处理网络负载。由于多核处理器在逻辑复杂的协议及应用层面上的处理优势,以及越来越强劲的数据面支持能力,它在多种业务领域得到广泛的应用。
CPU核以及众多加速单元和网络接口,组成了一个片上系统。当前多核处理器正在走向SoC化,针对网络的SoC往往集成内存控制器、网络控制器,甚至是一些硬件加速处理引擎。在这些SoC上,对于可固化的处理例如,流分类、QoS交由加速单元完成,而对于灵活的业务逻辑则由众多的通用处理器完成,有效融合了软硬件各自优势。
初识DPDK
IA多核处理器不适合数据包处理吗?
传统网络设备驱动包处理:
数据包到达网卡设备。——>网卡设备依据配置进行DMA操作。——>网卡发送中断,唤醒处理器。——> 驱动软件填充读写缓冲区数据结构。——>数据报文到达内核协议栈,进行高层处理。——>如果最终应用在用户态,数据从内核搬移到用户态。 / 如果最终应用在内核态,在内核继续进行。
原先每个报文就会触发一个中断,随着网络接口带宽从千兆向万兆迈进,大量数据到来触发频繁的中断,系统无法承受中断带来的开销。因此,有人在Linux内核引入NAPI机制用于高吞吐场景——系统被中断唤醒后,尽量使用轮询的方式一次处理多个数据包,直到网络再次空闲转入中断等待。
在TCP/IP模型中,网络包进入计算机大多需要经过协议处理,在Linux系统中TCP/IP由Linux内核处理。在不需要协议处理的场景下,也需要把包从内核缓冲区复制到用户缓冲区,系统调用以及数据包复制的开销会直接影响用户态应用从设备直接获取包的能力。而对于多样的网络功能节点来说,TCP/IP协议栈不是数据转发节点所必需的。如何让面向控制面原生设计的操作系统如Linux,在包处理上减少不必要的开销是一大热点。Netmap,一个高性能网络I/O框架,采用共享数据包池的方式,减少内核到用户空间的包复制。
NAPI和Netmap两方面的努力已经明显改善了传统Linux系统上包处理能力,DPDK如何去做得更好,怎样的软件设计能充分释放IA的包处理能力呢?
DPDK最佳实践
DPDK很好地回答了IA多核处理器应对高性能数据包处理的问题。其大致的技术可以归纳如下:轮询、用户态驱动、亲和性与独占、降低访存开销、软件调优、利用IA新硬件技术、充分挖掘网卡的潜能。
DPDK框架简介
内核态模块
KNI ( Kernel NIC interface 内核网卡接口)是DPDK允许用户态和内核态交换报文的渠道,KNI 模拟虚拟的网口,提供 DPDK 应用程序和 Linux 内核直接通信链接, 即 KNI 接口允许报文从用户态接收后转发到 Linux 内核协议栈中。
IGB_UIO内核模块。DPDK 利用 Linux 提供的UIO机制,通过read()感知中断、mmap()实现和网卡设备的通信,在 Linux 内核中安装 igb_uio.ko 模块(代替网卡驱动模块),重设中断回调函数入口参数,当网卡与 igb_uio.ko 绑定后,igb_uio接管网卡,并为用户态PMD 提供服务接口。
用户态模块
Core Libraries 核心部件库
核心部件库是 DPDK 面向用户态协议栈程序开发的模块,如:VPP 就是基于 DPDK的核心库接口实现的用户态协议栈应用。
EAL (Environment Abstraction Layer 环境抽象层), 对 DPDK 的运行环境进行初始化,包括:HugePage 内存分配、内存/缓冲区/队列分配、原子性无锁操作、NUMA 亲和性、CPU 绑定等,并通过 UIO 或 VFIO 技术将 PCI/PCIe 设备地址映射到用户态,方便用户态的 DPDK 应用程序调用。同时为应用程序提供通用接口,隐藏与底层库、设备交换的相关细节。
MALLOC (堆内存管理组件),为DPDK应用程序提供从 HugePage 内、分配内存的接口,当需要为skb_buf (Socket Buffer 数据包缓冲区)分配大量的小块内存时,可调用此接口。由于堆内存是从 HugePage 内存分配的,所以可以减少 TLB 缺页。堆、是由开发人员主动分配和释放的存储空间,如果开发人员不释放,则程序结束时由 OS 回收,分配方式类似于链表;与堆不同,栈是由操作系统自动分配和释放的存储空间,用于存储函数的参数值、局部变量等。
MBUF (网络报文缓存块管理组件), 为 DPDK 应用程序提供创建和释放、数据报文信息缓存块的接口。 提供两种类型的 MBUF,一种存储一般信息、一种存储时间的报文数据;这些 MBUF 存储在一个内存池中。
MEMPOOL (内存池管理组件),为 DPDK 应用程序和其他组件提供分配内存池的接口,内存池是一个由固定大小的多个内存块组成的内存容器,可用于存储不同的对象实体,如: 数据报文缓存块等。内存池是由一个字符串进行唯一标识,它由一个Ring 缓冲区和一组本地缓存队列组成,每个CPU core 优先从自身的缓存队列中分配内存块,当本地缓存队列减少到一定程度时,开始从内存环缓冲区中申请内存块进行补充。
RING (环缓冲区管理组件), 为DPDK应用程序和其他组件提供一个无锁的多生产者、多消费者的FIFO缓冲区队列。DPDK 基于 Linux 内核的无锁环形缓冲 kfifo 实现一套自己的无锁机制、 RING 环缓存区管理组件,支持单生产者/单消费者、多生产者/多消费者入列出列的操作,在数据传输时、降低性能的同时还能保住数据的同步。
TIMER (定时器组件),提供一些异步周期执行的接口,可以指定某个函数在规定时间内的异步执行,就像LIBC 中的 timer 定时器。但是这里的定时器需要 DPDK 应用程序在主循环中周期调用 rte_timer_manage 来使能定时器,使用起来不是那么方便。
Extensions 扩展内容
KNI,主要通过 Linux 内核中的 kni.ko 模块将数据报文从用户态传递给内核态的协议栈处理,以便常规的用户进程可以使用Linux 内核协议栈、处理传统的 Socket 接口报文。
POWER, 让 DPDK 应用程序可以根据收报速率、动态调整CPU频率、或让CPU 进入不同的休眠状态。
IVSHMEM, 模块提供虚拟机与虚拟机间、或虚拟机与主机之间的零拷贝共享内存机制,当 DPDK 应用程序运行时、IVSHMEM 模块会调用 Core Libraries 的 API ,把几个HugePage 内存映射为一个 IVSHMEM 设备池,并通过参数传递给 QEMU ,通过此方法实现虚拟机间的零拷贝共享内存。
PMD-Natives&Virtual 用户态轮询模式的网卡驱动程序
以太网轮询模式驱动架构,把以太网驱动从内核移动到应用层,采用同步轮询机制而不是内核态的异步中断机制来提高报文的接收和发送效率。
Classify 报文转发分类算法库
支持精确匹配 (Exact Match)、最长匹配 (LPM)和 通配符匹配 (ACL)数据报文,并提供常用的包处理的查表操作。
Qos 调度和流控库
提供网络服务质量相关的组件,如:限速 (Meter) 和调度 (Scheduler),调度库支持随机早检测、流量整形、严格优先级、和加权随机循环优先级调度等。