目录
一,概述
最近开始学习DPDK,最开始也是在网上看别人写的博客或者总结之类的文章,但是如果一点都没有接触到DPDK的小白,这样学习可能最后也只是一脸懵(比如我),所以根据自身需要制定一个确实可行的学习计划。根据各方的建议,从书《深入浅出DPDK》开始(申明,我不是卖书的,书也是我自个掏钱买的),先对DPDK有个框架上的认识,再深入到DPDK代码。
学习一个知识,最好就是从一个小例子开始。正如学习任何的计算机都从helloworld开始,咱也遵循老祖宗的干法,学习dpdk也从一个小helloworld开始。
DPDK的helloworld是最基础的入门程序,它建立了一个多核(线程)运行的基础环境,每个线程会打印”hello from core ?”。在正式代码之前,先了解一下DPDK代码的命名习惯,DPDK的主要对外函数接口都是以rte_作为前缀,抽象化函数是典型软件设计思路。从代码角度,ret是指runtime environment, eal是指environment adstraction layer(环境抽象层的责任就是提供访问低级别资源的能力,比如:硬件、地址空间等。EAL提供了一个普通的API接口,他们对应用程序和lib库等隐藏了硬件环境的特殊性。EAL同时也负责完成初始化例程,从而决定如何申请各种资源,比如:地址空间、PCI设备、Timers、consoles等)。
二,helloworld代码详解
下面直接看helloworld的代码,然后详细介绍用到的函数功能
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/queue.h>
//以上头开发环境glibc的相关头文件
#include <rte_memory.h>
#include <rte_memzone.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(); //获取逻辑核编号,并输出逻辑核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");
/* 每个从逻辑核调用回调函数lcore_hello输出相关信息。 */
/*给出RTE_LCORE_FOREACH_SLAVE宏定义
#define RTE_LCORE_FOREACH_SLAVE(i) \
for (i = rte_get_next_lcore(-1, 1, 0); \
i<RTE_MAX_LCORE; \
i = rte_get_next_lcore(i, 1, 0))
*/
RTE_LCORE_FOREACH_SLAVE(lcore_id)
{
rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
}
/* 再次调用主逻辑核输出相关信息。 */
lcore_hello(NULL);
/* 等待所有从逻辑核调用返回,相当于主线程阻塞等待。*/
rte_eal_mp_wait_lcore();
return 0;
}
下面详细介绍一下上面用的几个函数
1,rte_eal_init(argc, argv)
该初始化函数用于启动dpdk的基础运行环境。入口参数是启动DPDK的命令行,可以是长长的一串很复杂的设置,在此先不展开。以helloworld这个实例,最需要的参数是”-c <core mask>”,线程掩码(core mask)指定了需要参与运行的线程集合.rte_eal_init本身所完成的工作很复杂,它读取入口参数,解析并保存作为DPDK运行的系统信息,依赖这些信息,构建一个针对包处理设计的运行环境。
2,int rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int slave_id)
DPDK面向多核设计,程序会试图独占运行在逻辑核(lcore)上。RTE_LCORE_FOREACH_SLAVE遍历所有EAL指定可以使用的lcore,然后通过rte_eal_remote_launch在每个lcore上启动被指定的线程。
int rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int slave_id)
Launch a function on another lcore.To be executed on the MASTER lcore only.Sends a message to a slave lcore (identified by the slave_id) thatis in the WAIT state (this is true after the first call torte_eal_init()).
This can be checked by first callingrte_eal_wait_lcore(slave_id).When the remote lcore receives the message, it switches tothe RUNNING state, then calls the function f with argument arg.
Once theexecution is done, the remote lcore switches to a FINISHED state andthe return value of f is stored in a local variable to be read usingrte_eal_wait_lcore().
The MASTER lcore returns as soon as the message is sent and knowsnothing about the completion of f.Note: This function is not designed to offer optimumperformance.
It is just a practical way to launch a function onanother lcore at initialization time.
参数:
f – The function to be called.
arg – The argument for the function.
slave_id – The identifier of the lcore on which the function should be executed.
第一个参数是要被调用的函数
第二个参数是传给从线程的参数
第三个参数是指定的逻辑核,从线程在该核上运行调用的函数
从本例上,简单来说rte_eal_remote_launch函数就是在指定的lcore_id的从线程上执行函数lcore_hello.
3,void rte_eal_mp_wait_lcore(void)
void rte_eal_mp_wait_lcore(void)
Wait until all lcores finish their jobs.
To be executed on the MASTER lcore only. Issue an
rte_eal_wait_lcore() for every lcore. The return values are
ignored.
After a call to rte_eal_mp_wait_lcore(), the caller can assume
that all slave lcores are in a WAIT state.
该函数只能在主线程上执行,等待所有逻辑核上的任务执行完毕
三,makefile编写
介绍完上面的代码后,可以试运行一下,不过运行前得编译该函数,看看makefile的编写
#判断相关环境变量是否设置
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
# 默认的平台目标
RTE_TARGET = x86_64-native-linuxapp-gcc
include $(RTE_SDK)/mk/rte.vars.mk
# binary name
APP = helloworld
# all source are stored in SRCS-y
SRCS-y := main.c
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
include $(RTE_SDK)/mk/rte.extapp.mk
四,编译执行
[root@localhost lesson1]# ll
total 8
-rwxrwxrwx. 1 root root 1515 Mar 16 19:46 main.c
-rwxr-xr-x. 1 root root 406 Mar 16 19:53 makefile
[root@localhost lesson1]# make clean
[root@localhost lesson1]# make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
执行helloworld
[root@localhost build]# ./helloworld
EAL: Detected 56 lcore(s)
EAL: Detected 2 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: No free hugepages reported in hugepages-2048kB
EAL: No free hugepages reported in hugepages-2048kB
EAL: No available hugepages reported in hugepages-2048kB
EAL: Probing VFIO support...
EAL: PCI device 0000:01:00.0 on NUMA socket 0
EAL: probe driver: 8086:10fb net_ixgbe
EAL: PCI device 0000:01:00.1 on NUMA socket 0
EAL: probe driver: 8086:10fb net_ixgbe
EAL: PCI device 0000:05:00.0 on NUMA socket 0
EAL: probe driver: 8086:1521 net_e1000_igb
EAL: PCI device 0000:05:00.1 on NUMA socket 0
EAL: probe driver: 8086:1521 net_e1000_igb
EAL: PCI device 0000:05:00.2 on NUMA socket 0
EAL: probe driver: 8086:1521 net_e1000_igb
EAL: PCI device 0000:05:00.3 on NUMA socket 0
EAL: probe driver: 8086:1521 net_e1000_igb
EAL: PCI device 0000:81:00.0 on NUMA socket 1
EAL: probe driver: 8086:1572 net_i40e
EAL: PCI device 0000:81:00.1 on NUMA socket 1
EAL: probe driver: 8086:1572 net_i40e
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 8
hello from core 9
hello from core 10
hello from core 11
hello from core 12
hello from core 13
hello from core 14
hello from core 15
hello from core 16
hello from core 17
hello from core 18
hello from core 19
hello from core 20
hello from core 21
hello from core 22
hello from core 23
hello from core 24
hello from core 27
hello from core 28
hello from core 26
hello from core 25
hello from core 29
hello from core 30
hello from core 31
hello from core 32
hello from core 33
hello from core 34
hello from core 35
hello from core 36
hello from core 37
hello from core 38
hello from core 40
hello from core 41
hello from core 42
hello from core 43
hello from core 39
hello from core 44
hello from core 45
hello from core 46
hello from core 48
hello from core 49
hello from core 47
hello from core 50
hello from core 51
hello from core 52
hello from core 53
hello from core 54
hello from core 55
hello from core 0
可以看到在该服务器上有56个逻辑核,在每个核上执行lcore_hello函数,打印出hello from core ?。
!!!至此第一个DPDK的helloworld程序介绍完毕!!!