一、DPDK介绍
提起DPDK,需要先回顾一下网络的发展。最初的网络的出现是从美国军方的局域网发展起来的,从一开始,网络的应用并没有现在这么复杂,数据传输量也没有现在这么巨大。更不要提现在什么高清、3D等等这些初时的大数据流传送。同样,也不会有什么双11,618之类海量的并发。
为什么说这些呢?随着网络的不断发展,全球网络的应用可以说用井喷来形容,对应用的人来说,只是把生活变得更丰富更美好,应用更简单更容易。可对于底层的计算机技术来说,这需要不断的演进技术,才能够保证上层的这些应用。搞技术的都清楚,早期的一些网站,包括很多大型的网站,其实就是用的最基础的Socket通信中的Select轮询,再辅以多进程即可以实现上面的应用。但这些问题随着应用规模越来越大,已经完全无法满足需求了。
解决这种问题的方式有两种,一种是在应用层使用更好的框架和通信模型(如epoll等);另外一种就是修改网络的底层协议(TCP/IP)。
这两种方式,应用层好完善,大不了迭代一个新版本,但修改协议这个就麻烦大了,涉及到N多的东西,更为关键的是,要硬件的跟进。这几乎是不可能的,而且这需要一个很漫长的时间才能实现。另外更关键的是,随着云技术的兴起,导致了网络数据传输的路径更加延长,也就是说,网络的吞吐量理论上讲进一步减少。同时,异构和多CPU多核的出现,又需要能尽量公平的使用CPU,保证数据的调度,这也是原来的整个技术栈没有考虑到的。
而DPDK就相对较好的解决了这些问题,它掠过了内核中的网络协议栈,而将其迁移到了用户态,消除和减少了中断以及内存数据的拷贝次数,通过网卡和用户进行直接的数据交互。它的优势是明显的,特别是在云的环境下,虚拟技术可以更好的和真实的网卡进行数据通信。
二、框架主要结构
先看一下DPDK的框架结构图:
注:图来源网上,找不到出处,如有侵权,通知删除
结合着这张图再回头和前面编译过程的代码就会更加清晰的理解整个DPDK的框架结构。
三、源码目录结构
在DPDK源码中主要的目录如下:
其中主要目录:
app:是DPDK应用程序的源码,包括测试应用代码
lib:库源码
drivers:DPDK轮询驱动代码
config:平台编译配置
usertools:DPDK提供给用户的一些工具
buildtools:编译配置脚本
devtools:设置管理脚本
mk:Makefile的相关脚本
kernel:内核相关的源码
五、简单例程
看一下自带的一个HelloWrold例程:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/queue.h>
#include <rte_memory.h>
#include <rte_launch.h>
#include <rte_eal.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_debug.h>
static int lcore_hello(__attribute__((unused)) void *arg)
{
unsigned lcore_id;
lcore_id = rte_lcore_id();
printf("hello from core %u\n", lcore_id);
return 0;
}
int main(int argc, char **argv)
{
int ret;
unsigned lcore_id;
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
/* call lcore_hello() on every slave lcore */
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
}
/* call it on master lcore too */
lcore_hello(NULL);
rte_eal_mp_wait_lcore();
/* clean up the EAL * /
rte_eal_cleanup();
return 0;
}
这是一个最简单的程序了,一般所有的新的语言或者框架出来都会有一个“Hello World”,这个就是DPDK的。程序中首先使用rte_eal_init来对主线程和子线程进行创建初始化,通过管道实现它们之间的通信。然后使用RTE_LCORE_FOREACH_SLAVE宏来实现对CPU核的遍历(Master除外),而rte_eal_remote_launch就是实现的具体的函数。rte_eal_mp_wait_lcore可以理解为一种主从线程之间的同步的机制,主线程会等待所有的子线程进入等待状态后,才可以进行消息的通信。
其运行的结果:
:~/dpdk-stable-19.11.14/examples/helloworld/build$ sudo ./helloworld -l 0-7 -n 8
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: No available hugepages reported in hugepages-1048576kB
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL: PCI device 0000:02:06.0 on NUMA socket -1
EAL: probe driver: 8086:100f net_e1000_em
EAL: PCI device 0000:03:00.0 on NUMA socket -1
EAL: probe driver: 15ad:7b0 net_vmxnet3
hello from core 1
hello from core 2
hello from core 3
hello from core 4
hello from core 5
hello from core 6
hello from core 7
hello from core 0
可别少了sudo,要不报一些乱七八糟的问题。同时需要设置:
export RTE_SDK=/home/fpc/dpdk-stable-19.11.14/
五、总结
其实网络技术发展不是一蹴而就的,从最初的DMA,到COW,总之,消除和减少各种冗余动作的技术不断出现,直到DPDK的出现其实是一个延续发展的过程。随着DPDK的广泛应用,硬件厂商特别是云厂商对其的支持不断增加和完善。而原来提到过的上层应用SPDK也是对DPDK的一种扩展。专门就DPDK而言,其实可以理解为应用倒逼的技术的进步。所以说,人多,这也是一个优势。没有应用场景,技术进步就不会那么迫切,或许,这也是理论联系实际的一个典型例子。