文章目录
- 1. DPDK概述
- 1.1 DPDK 内存管理
- Mbuf单帧结构:
- 1.2 DPDK内核驱动 igb_uio驱动
- 1.3 DPDK源码下载方式
- 1.4 pktgen源码下载方式
- 1.5 DPDK相关名词解释
1. DPDK概述
Intel DPDK
全称Intel Data Plane Development Kit
,是Intel提供的数据平面开发工具集,为Intel architecture(IA)处理器架构下用户空间高效的数据包处理提供库函数和驱动的支持,它不同于Linux系统以通用性设计为目的,而是专注于网络应用中数据包的高性能处理。DPDK应用程序是运行在用户空间上利用自身提供的数据平面库来收发数据包,绕过了Linux内核协议栈对数据包处理过程。Linux内核将DPDK应用程序看作是一个普通的用户态进程
,包括它的编译、连接和加载方式和普通程序没有什么两样。DPDK程序启动后只能有一个主线程,然后创建一些子线程并绑定到指定CPU核心上运行
DPDK 有三大法宝:
①ByPass Kernel : UIO/VFIO
②微架构优化: Cache/DDIO/SIMD
③内存管理: HugePage/mbuf/mempool
1.1 DPDK 内存管理
①hugetlbfs:
②Mbuf:为了高效访问数据,DPDK将内存封装在Mbuf(struct rte_mbuf)结构体内。
Mbuf主要用来封装网络帧缓存,也可用来封装通用控制信息缓存(缓存类型需使
用CTRL_MBUF_FLAG来指定)。
网络帧元数据的一部分内容由DPDK的网卡驱动写入。这些内容包括VLAN标签、RSS哈希值、网络帧入口端口号以及巨型帧所占的Mbuf个数等。
对于巨型帧,网络帧元数据仅出现在第一个帧的Mbuf结构中,其他的帧该信息为空。
Mbuf单帧结构:
Mbuf巨型帧结构(有多个segment):
③Mempool:在DPDK中,数据包的内存操作对象被抽象化为Mbuf结构,而有限的rte_mbuf结构对象则存储在内存池Mempool中。内存池使用环形缓存区来保存空闲对象。
rte_mempool
内部管理是基于rte_ring(无锁队列,巧妙运用了CAS)实现的
当一个网络帧被网卡接收时,DPDK的网卡驱动将其存储在一个高效的环形缓存区中,同时在Mbuf的环形缓存区中创建一个Mbuf对象。
为了减少多核访问造成的冲突,引入了local_cache对象缓冲区。该local_cache非硬件上的cache
,而是为了减少多核访问ring造成的临界区访问,coreX app会优先访问该local_cache上的对象。
④malloc: 通常,这些类型的分配不应该在数据面处理中进行,因为他们比基于池的分配慢,并且在分配和释放路径中使用了锁操作。 但是,他们可以在配置代码中使用。
struct malloc_heap - 用于在每个插槽上跟踪可用内存空间:数据结构malloc_heap用于管理每个插槽上的可用内存空间。 在内部,每个NUMA节点有一个堆结构,这允许我们根据此线程运行的NUMA节点为线程分配内存。 虽然这并不能保证在NUMA节点上使用内存,但是它并不比内存总是在固定或随机节点上的方案更糟。
struct malloc_elem - 库内部分配和释放空间跟踪的基本要素:数据结构malloc_elem用作各种内存块的通用头结构。 它以三种不同的方式使用,如上图所示:
a).作为一个释放/申请内存的头部 – 正常使用
b).作为内存块内部填充头
c).作为内存结尾标记
1.2 DPDK内核驱动 igb_uio驱动
igb_uio驱动主要做的就是注册一个pci设备。但是igbuio_pci_driver对应的保存pci设备信息的id_table指针为空,这样在内核插入igb_uio驱动时,会找不到匹配的设备,就不会调用igb_uio驱动中的探测probe
函数,只会在/sys
目录下创建igb_uio
相应的目录。
变量igbuio_intr_mode_preferred表示中断的模式,它由igb_uio驱动模块的参数intr_mode决定,有MSIX中断和Legacy中断两种模式,默认的是MSIX中断模式(我们修改成了默认是MSI模式)
那么何时调用igb_uio驱动中的probe函数?在下面的测试说明中有提到,进行加密设备绑定(bind)时会进行probe。
进行设备bind时igb_uio驱动做了什么?
记录设备的资源:igb_uio驱动也会遍历PCI设备的BAR空间,但是它不会直接使用功能BAR空间的物理地址,而是调用ioremap函数将物理地址映射为虚拟地址,驱动在内核态读写操作映射出来的虚拟地址
注册一个uio设备:在Linux上的驱动设备一般都是运行在内核态的,提供接口函数给用户态函数调用即可。而新引入的UIO技术,则是将驱动的大部分事情移到了用户态。前面讲到probe函数会记录设备的资源,具体而言就是PCI设备BAR空间的物理地址、大小等信息记录下来传给用户态。除了记录BAR空间资源信息,uio框架还会在内核态实现中断处理相关的初始化工作。
内核uio驱动框架
①背景: 通常一些非标准设备的驱动被实现为字符驱动。这些驱动使用了很多内核内部函数和宏。而这些内部函数和宏是变化的。这样驱动的编写者必须编写一个完全的内核驱动,而且一直维护这些代码。而且这些驱动进不了主内核源码。于是就出现了用户空间I/O框架(Userspace I/O framework)
②原理:UIO(Userspace I/O)是运行在用户空间的I/O技术。Linux系统中一般的驱动设备都是运行在内核空间,而在用户空间用应用程序调用即可,而UIO则是将驱动的很少一部分运行在内核空间,而在用户空间实现驱动的绝大多数功能。
a).开发运行在内核的UIO模块,因为硬中断只能在内核处理
b).通过/dev/uioX读取中断
c).通过mmap和外设共享内存
1.3 DPDK源码下载方式
①DPDK官网: http://core.dpdk.org/download/
②DPDK git仓库(该仓库只能clone): git://dpdk.org/dpdk-stable
③某github主仓库(该仓库可以导入成私有仓库,便于git管理):https://github.com/chaudron/dpdk-stable
1.4 pktgen源码下载方式
DPDK pktgen官网: git://dpdk.org/apps/pktgen-dpdk
1)下载后,查看pktgen-dpdk的git tag,切换到与dpdk版本对应的tag
$ git tag
我测试用的dpdk版本是18.11, 经编译对比测试,dpdk18.11选用pktgen-3.7.2最为合适
$ git checkout pktgen-3.7.2
2)切换到tag pktgen-3.7.2后, 直接输入make即可
3)编译好后,生成的app/x86_64-native-linuxapp-gcc/pktgen
就是我们要的发包工具
注:pktgen编译可能需要的前提步骤如下:
$ pip3 install --user meson
$ pip3 install --user ninja
Ubuntu16.04安装lua5.3
$ sudo apt install liblua5.3-dev
$ sudo apt remove liblua5.3-dev #若要删除的话
1.5 DPDK相关名词解释
DPDK: Data Plane Development Kit: 数据平面开发工具包
EAL: Environment Abstraction Layer: 环境抽象层/环境适配层
NIC: Network Interface Cards: 网卡
PMD: Poll Mode Driver: (基于用户态的)轮询模式驱动
UIO: Userspace I/O: 运行在用户空间的I/O技术
RTE: RunTime Environment: 运行环境?
SDK: Software Development Kit: 软件开发工具包
另外关于SEC snoop ICV含义:
ICV: Integrity Check Value: 完整性检查值, 用于内部进行hash计算,并比较计算结果是否与预期值相同(正确: job output ring status返回0, 错误:返回其它值:0x2000004a)