03.DPU网络开发SDK——DPDK(二)

作者: 大空新一 
Hello world
 
上一次的文章中主要介绍了DPDK是什么,主要用在什么地方。作为一个SDK,DPDK提供了大量的function接口用于网络转发面程序的编写。接下来的几篇文章,我们会基于DPDK程序的实例,以剖析关键function接口的方式逐步分析DPDK的实现机制,以此来熟悉DPDK的整个样貌。
 
由于DPDK的版本发生过巨大的变化,涉及到编译方式等的改变,之后的分析统一基于20.11.0这个版本进行。

WX20220408-154052@2x

我们以DPDK版本的“hello world”为例开始我们的分析过程,其代码内容如上(省略头文件)。
进入主函数之后,首先需要调用的是rte_eal_init,该函数的作用是用来初始化DPDK的运行时环境(runtime environment, rte),在DPDK中称为环境抽象层(environment abstract layer, eal)。该初始化过程中会提取命令行参数列表中与DPDK相关的参数进行解析,初始化各类全局数据结构,初始化内存等。该过程涉及到的初始化内容很多,是接下来的几篇DPDK分析文章中会重点分析的内容。
DPDK的eal环境初始化完毕之后,会在各处理核(lcore)上启动各线程,DPDK用RTE_LCORE_FOREACH_WORKER这个宏定义来遍历所有的worker处理核,并在该处理核上启动线程的入口函数。
 
本例中的入口函数是lcore_hello,DPDK通过rte_eal_remote_launch将线程入口函数与处理核进行绑定,绑定之后,在DPDK进程结束前,该线程会独占该处理核且不会有其他线程调度到该处理核上运行。
与worker处理核相对应的是main处理核,在执行DPDK进程时,进程被调度到哪个处理核上执行,该处理核就是main处理核,即main处理核承担了初始化DPDK的任务。在本例中,main函数在各worker处理核上启动线程之后,同样执行了lcore_hello,并且调用rte_eal_mp_wait_lcore等待所有线程执行完毕之后再退出。
lcore_hello的工作仅为获取当前处理核的ID并打印到控制台,在DPDK中处理核的ID从0开始连续编号,最大支持的处理核数量在编译DPDK的lib库时由配置文件指定为宏定义。运行过程中DPDK进程实际占用的处理核与CPU的Processor的对应列表则是由启动DPDK时的参数指定的,rte_eal_init会对此进行解析并初始化相关处理结构。
 
rte_eal_init
 
rte_eal_init的整个初始化过程非常长,此处的分析过程中会尽可能将重点过程保留下来,对某些细节内容则先忽略。
  1. 获取两个全局配置
DPDK中有两个全局配置的变量,类型分别为struct rte_config和struct internal_config。数据结构的定义分别在lib/librte_eal/common目录下的eal_private.h和eal_internal_cfg.h两个文件中,变量定义在eal_common_config.c文件中,并提供了ret_eal_get_configuration()和eal_get_internal_configuration()两个接口用于获取这两个配置的变量。
 
在rte_eal_init中,首先获取这两个全局变量,用于记录经参数解析后的配置及初始化的其他数据结构等。
  1. 检查主机是否满足运行要求
该项检查主要是检查CPU的特性,执行入口为rte_cpu_is_supported()。
该function中,会根据编译时定义的宏RTE_COMPILE_TIME_CPUFLAGS当中指定cpuflag列表,去依次检查当前主机的CPU是否支持这些flag特性,出现不支持的特性时则会以错误返回。该function的实现是分CPU架构的。
 
  1. 确保初始化过程只运行了一次
通过static类型的变量run_once和来标识是否init是否已经执行过了,在一个DPDK进程中rte_eal_init只能执行一次。
  1. 初始化internal_config
将全局配置变量internal_config中相关成员的值设置为默认值。
  1. 设置日志级别
调用eal_log_level_parse()负责日志级别的解析,通过解析命令行参数”–log-leve”确定以什么级别打印日志,并将日志等级存入internal_config中。
由于日志越早打印越有助于在出现问题时及时定位,所以DPDK在初始化阶段的早期就解析了日志级别,而其他的命令行参数则在随后才做解析。
 
在下期我们将继续进行rte_eal_init的过程分析。
往期回顾
02.DPU网络开发SDK——DPDK(一)
01.DPU简介

02.DPU网络开发SDK——DPDK(一)

作者:大空新一

随着软件定义网络SDN的不断发展,网络数据转发面的需求越来越多样化,这体现在更快的数据包处理速率,更高的网络吞吐带宽,更灵活的自定义网络协议。

传统的硬件设备无法满足网络协议的自定义,而基于Linux内核网络协议栈的网络数据转发则存在处理流程繁琐,效率低下等问题。在此背景下,Intel公司提供了一款高性能网络数据平面开发套件DPDK(data plane development kit),它提供了一个简单方便的,完整的,快速的数据包处理解决方案。

目前,DPDK被广泛应用在网络转发组件的开发当中,如负载均衡网关,NAT网关,虚拟机交换机OVS也同样包含了对DPDK的支持。由于DPDK能够向网络转发面组件提供快速高效的对原生数据包进行处理的能力,其在DPU的研发上也扮演着重要的角色。

DPDK主要包含以下几大特性,借助这些特性网络转发面组件得以实现快速高效的数据包处理:

 

  • 用户态数据包处理
传统情况下,当网卡收到数据包时,需要经过内核网络协议栈的处理,协议栈将头部一层层进行剥离之后,才能将最终数据交付给用户态进程;过程中会存在内核空间向用户空间进行内存拷贝的情况,这会消耗大量的计算资源。
Linux内核源码中提供了uio驱动模块,网卡硬件设备在绑定该模块之后,会将设备暴露在用户空间;DPDK通过读取该uio文件,能够直接收取原始的二层数据包并直接写入用户态进程的内存空间当中;用户态进程可直接对数据包的各层数据进行分析并根据需要进行修改、转发或选择丢弃;发送数据包时,则通过写入该uio文件进行发送。
在收取-处理-发送的过程中,数据包绕开了内核网络协议栈的处理逻辑,且处理过程中未发生过内存的拷贝,这就节省了大量的开销;且用户态进程拿到的数据包是原始的二层数据包,开发者可根据需要自主决定对该数据包的处理方式,更便于自定义网络协议的实现。
无DPDK与有DPDK的对比
DPDK工作原理
 
  • PMD轮询模式收包
传统Linux系统中,当网卡收到数据包时,会借助DMA技术将数据包发送到预先分配好的内存缓冲区里面,之后产生中断通知内核有数据包过来。Linux内核会对中断进行响应,将接收到的数据帧交给内核中的网络协议栈进行处理,最后数据被复制到了用户空间或者直接在内核协议栈中处理完毕。
通过中断通知内核有数据包到来的方法在低带宽低吞吐等环境下能够满足需求,但在云平台这样要求高带宽高吞吐的情况下,中断方式会引发中断风暴,内核需不间断的处理中断请求,不利于内核对数据包和其他内核运算的处理。
DPDK提供了PMD(Poll mode driving)轮询模式实现对数据包的收取,不需要网卡通过中断通知内核收取到数据包,而是由用户态进程不间断去查询网卡是否收取到数据包,有则处理之,无则进行下一轮查询。在高吞吐情况下,一次轮询可批量处理多个数据包,减少了中断引发的系统开销。
  • 大页内存
Linux内核中默认页面的大小是4KB,在64位系统中页表被划分为5级,用户态进程在寻址时需要经过4次页表查找才能将虚拟地址转换为物理地址。页表查找过程是高性能处理进程的一项瓶颈,而使用大页内存可有效减少页表查询的次数,减轻TLB的查询压力和查询miss的概率。在64位系统中支持2MB和1GB两种类型的大页内存,分别需要4级和3级页表的支持,DPDK一般使用1G大页内存,仅需2次页表查询即可实现虚拟地址到物理地址的转换。
  • CPU独占及亲和性
运行基于DPDK的网络转发面处理组件的主机会提前将部分CPU的Processor隔离出来专门提供给DPDK使用,DPDK进程在初始化阶段会根据配置初始化线程数量,并将线程和Processor进行绑定。绑定之后Processor不会再处理绑定线程以外的其他线程,被绑定线程也不会调度到其他Processor上进行处理,此举有效减少了因线程调度产生的上下文切换的开销,并减少了Cache Miss发生的概率。
  • 有助于转发处理逻辑的数据结构
DPDK提供了一些有助于编写网络转发平面处理逻辑的数据结构,如Timer,Mbuf,Ring等。Timer实现了计时器的功能;Mbuf提供了基本的内存缓存片段,用于缓存数据包,并支持片段向前后进行扩展;Ring实现了FIFO队列,且该队列是无锁的。
  • QoS和ACL
DPDK提供了相应的数据结构,基于此数据结构及关联的API,可以在用户态进程中实现限速和访问控制这两项网络转发平面必须的功能。
  • 适配多种类型的实体或虚拟网络设备
DPDK是由Intel开发并维护的,最初仅支持对Intel系列网卡的支持,后DPDK陆续支持了对Mellanox,Virtio等设备的支持,使得DPDK的使用范围进一步扩大。
 
以上是DPDK的在加速网络数据面处理上减少的开销和提供的便利,底层实现上仍然是基于Linux内核提供的功能,在接下来的几期文章中将对DPDK深入分析,以理清其内部实现机制。 
往期推荐
01.DPU简介

01.DPU简介

作者:大空新一

DPU是Data Processing Unit的简称,它是近几年发展起来的专用处理器,是CPU、GPU之后,数据中心场景中的第三颗重要的算力芯片,为诸如云平台等需要高带宽、低延迟、数据密集的计算场景提供计算能力。

 

为什么需要DPU

 

传统的云计算主机上,CPU除了负担客户购买的计算能力之外,还需要负担云平台中必要的支撑组件的运行,典型例子如云平台VPC网络数据转发平面的常见组件OVS。

 

一般场景下,OVS运行在云计算主机上,基于VXLAN技术实现云平台VPC网络。在转发网络数据包的过程中,需要处理大量的计算工作,如流表匹配,数据包的封装与解封,checksum计算等,这些工作必然要消耗云主机大量的CPU资源。那么是否可以有一个额外的处理单元,替CPU分担这些支撑组件的运行工作呢?

 

DPU就是这个额外的处理单元。DPU在物理上体现为一个插在主机上的PCIe设备,通过PCI总线与主机进行交互。

 

DPU存在一个ARM架构的片上系统(SoC),SoC上可运行基础的Linux,如此类似OVS这样的云平台中的支撑组件则不必运行在主机中,而是运行在DPU的SoC上。

这样主机上的CPU则可专注于处理客户的计算任务,使得CPU能够发挥其最大的计算能力为客户提供服务。

 

 

DPU的发展历程

 

Fungible最先于2016年提出DPU的概念,也是第一家专注于设计DPU的创业公司。

 

Mellanox在2019年率先推出了基于BlueField的DPU,后Nvidia于2020年收购Mellanox,同年提出BlueField 2.0 DPU,自此,DPU开始活跃起来,并吸引了大量国内外知名创业公司的加入。

 

国外公司的典型代表有Marvell、Pensando、Broadcom、Intel,国内的公司集中在创业团队,他们凭借自身的技术积累入局DPU,如中科驭数、星云智联等。

 

2021年Nvidia推出了基于BlueField 3.0的DPU。

 

 

DPU的工作内容

 

DPU的角色类似于CPU的“小秘书”,主机将一些需要重复计算或者计算量大的“杂活”“累活”卸载给DPU进行处理。

 

DPU卸载的内容常见的有:数据中心网络服务,比如前文提到的OVS虚拟交换、虚拟路由;数据中心存储服务,比如RDMA、NVMe(一种远程存储技术);数据中心的安全服务,比如防火墙、加解密等等。

 

DPU有自己的处理单元和硬件设备,前面提到的加密和虚拟交换等通常使用软件实现,并在CPU里运行。而DPU可以使用硬件实现并运行这些支撑组件,这样比在CPU运行要快好几个数量级,这也就是我们常常会听到的“硬件加速”。

 

此外,由于将支撑组件运行在了DPU中,而客户的应用则在CPU里运行,这样就把二者隔离开了,会带来很多安全和性能上的好处。

 

 

DPU在网络上的应用

 

DPU的前身是Smart NIC,Smart NIC是没有SoC的,运行不能脱离主机CPU,且其对网络的卸载主要是在数据面上,控制面仍然是主机CPU上的工作。

 

Smart NIC在网络方面的可卸载的工作内容是由硬件设定好的,内容不可变,而DPU中引入了可编程硬件,使用方可根据自身需要自行决定硬件行为,而无需再受限于固定化程式化的硬件处理流程。

 

在诸如云计算等数据中心不断提高对带宽要求的背景下,DPU相比于Smart NIC的灵活性使得其在网络上的应用更加的宽泛。

 

典型的应用场景包括:

 

  • 像OVS一样对数据包进行解析、匹配和处理
  • 基于RoCE的RDMA数据传输加速
     
  • 通过GPU-Direct加速器绕过CPU,将来自存储和其他GPU的数据通过网络直接传给GPU
  • TCP通信加速,包括RSS、LRO、checksum等操作
     
  • 网络虚拟化的VXLAN和Geneve Overlay卸载和VTEP卸载
     
  • 面向多媒体流、CDN和新的4K/8K IP视频的“Packet Pacing” 流量整型加速
     
  • 电信Cloud RAN的精准时钟加速器,例如5T for 5G (精准时钟调度5G无线报文传输技术)功能
     
  • 在线IPSEC和TLS加密加速,但不影响其它正在运行的加速操作
     
  • 支持SR-IOV、VirtIO 和PV(Para-Virtualization)等虚拟化
     
  • 安全隔离:如信任根、安全启动、安全固件升级以及基于身份验证的容器和应用的生命周期管理等