DPDK pdump个人学习笔记

DPDK 20.08 PDUMP工具学习

pdump是DPDK自带的调试工具,可以将抓到的包存储为pcap文件。
本人接触DPDK时间相对较短,本博客仅为本人学习记录与笔记,肯定是错误连篇,而且由于本人比较笨,所以写的比较像流水账,便于本人理解。这些写在前面,希望不要误导别人(或者被大佬喷)。

pdump主函数如下:

int
main(int argc, char **argv)
{
	int diag; 
	int ret;
	int i;

	char n_flag[] = "-n4";
	char mp_flag[] = "--proc-type=secondary";
	char *argp[argc + 2];

	/* catch ctrl-c so we can print on exit */
	signal(SIGINT, signal_handler);

	argp[0] = argv[0];
	argp[1] = n_flag;
	argp[2] = mp_flag;

	for (i = 1; i < argc; i++)
		argp[i + 2] = argv[i];

	argc += 2;

	diag = rte_eal_init(argc, argp);  //初始化eal
	if (diag < 0)
		rte_panic("Cannot init EAL\n");

	if (rte_eth_dev_count_avail() == 0)  
		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");

	argc -= diag;
	argv += (diag - 2);

	/* parse app arguments */
	if (argc > 1) {
		ret = launch_args_parse(argc, argv, argp[0]);
		if (ret < 0)
			rte_exit(EXIT_FAILURE, "Invalid argument\n");
	}

	/* create mempool, ring and vdevs info */
	create_mp_ring_vdev();
	enable_pdump();         
	enable_primary_monitor();
	dump_packets();

	disable_primary_monitor();
	cleanup_pdump_resources();
	/* dump debug stats */
	print_pdump_stats();

	ret = rte_eal_cleanup();
	if (ret)
		printf("Error from rte_eal_cleanup(), %d\n", ret);

	return 0;
}

其主要分为如下几个部分:
1)初始化环境:处理EAL所需要的初始化参数外,还增加了两个参数:

char n_flag[] = "-n4";
char mp_flag[] = "--proc-type=secondary";
char *argp[argc + 2];

/* catch ctrl-c so we can print on exit */
signal(SIGINT, signal_handler);

argp[0] = argv[0];
argp[1] = n_flag;
argp[2] = mp_flag;

for (i = 1; i < argc; i++)
	argp[i + 2] = argv[i];

argc += 2;

diag = rte_eal_init(argc, argp);  //初始化eal
if (diag < 0)
	rte_panic("Cannot init EAL\n");

一个是-n4,另一个是--proc-type。根据DPDK文档,-n4用于指定使用的内存通道数,后者指定当前进程的类型,分为<primary|secondary|auto>,因为pdump是附属于testpmd等主进程的调试程序,所以这里就是secondary
新的参数作为argp传入rte_eal_init()执行初始化。

2)参数解析:

if (rte_eth_dev_count_avail() == 0)  //查看是否有可用的设备
		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");

argc -= diag;
argv += (diag - 2);

/* parse app arguments */
if (argc > 1) {
	ret = launch_args_parse(argc, argv, argp[0]);
	if (ret < 0)
		rte_exit(EXIT_FAILURE, "Invalid argument\n");
}

初始化后返回的diag指明使用过了哪些参数,将其从argc和argv中减去,剩下的参数就是程序的参数了。
pdump的参数提示

./build/app/dpdk-pdump --
						[--multi]
						--pdump '(port=<port id> | device_id=<pci id or vdev name>),
								 (queue=<queue_id>),
								 (rx-dev=<iface or pcap file> |
								 tx-dev=<iface or pcap file>),
								 [ring-size=<ring size>],
								 [mbuf-size=<mbuf data size>],
								 [total-num-mbufs=<number of mbufs>]'

<以下部分来自于DPDK Tools User Guides文档>
其中的--multi是可选选项,如果不设置,则所有处理都是单核。
--pdump以及后面的参数是强制的,可以传递多个--pdump参数给程序,设置在不同的端口和队列上进行捕获。

必须配置的内容包括端口,队列和dev。其中dev中的rx-dev和tx-dev分别代表ingress和egress的配置,可以二选一,也可以全选,可以配置为一个pcap文件,也可以配置成iface。

之后的都是可选参数,其中ring_size用来设置缓冲区,此处的缓冲区用于在主进程和pdump之间传递数据包,默认数值为16384;mbuf-size用于生成mempool,最好设置成主进程中用于接收数据包的mempool大小,默认数值为2176。

官方用法示例:

$ sudo ./build/app/dpdk-pdump -l 3 -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap'
$ sudo ./build/app/dpdk-pdump -l 3,4,5 -- --multi --pdump 'port=0,queue=*,rx-dev=/tmp/rx-1.pcap' 

3)初始化部件并开始抓取:

create_mp_ring_vdev();
enable_pdump();
enable_primary_monitor();
dump_packets();

disable_primary_monitor();
cleanup_pdump_resources();
/* dump debug stats */
print_pdump_stats();

ret = rte_eal_cleanup();
if (ret)
	printf("Error from rte_eal_cleanup(), %d\n", ret);

首先依据前面的设置初始化mempool,rte_ring和vdev,之后就是开始正式流程了。在前面的signal(SIGINT, signal_handler)语句中,将signal_handlerSIGINT绑定,回调函数中会修改quit_signal为1,结束捕获与存储过程,并执行结束时的各类清理操作,程序结束。

函数代码分解:
1)launch_args_parse:
这个函数的作用就是解析参数,主要分成两个部分,一部分是解析--multi参数,如果有这个参数,就把multiple_core_capture的值设置为1,也就是前面说的使用多个现程;另一部分就是解析--pdump参数,把后面的字符串传入到parse_pdump函数中去进行进一步解析。parse_pdump中会调用rte_kvargs_parse函数,将键值对存在kvlist中。

2)create_mp_ring_vdev:
使用之前解析所得参数对mempool等组件进行初始化。其主体是一个循环,对应所有的--pdump参数。
下面简单介绍些每次循环的大致流程。首先是使用rte_pktmbuf_pool_create_by_ops函数创建mempool,之后根据程序运行时选择的rx和tx情况(经过解析后分为RTE_PDUMP_FLAG_RXTXRTE_PDUMP_FLAG_RX.RTE_PDUMP_FLAG_TX.),按照不同的流程生成rte_ring和vdev。如果是rxtx,要调用rte_ring_create分别为接收和发送创建rte_ring,而vdev初始化流程分为两个部分,第一个是使用rte_eal_hotplug_add创建vdev,并通过rte_eth_dev_get_port_by_name获取vdev对应的port id;第二个是进行配置,这里需要查看之间选择的rx-devtx-dev参数,如果后面的参数是一样的,就公用一个vdev,反之就再为tx创建并配置一个vdev,配置过程使用的函数包括rte_eth_dev_configurerte_eth_tx_queue_setuprte_eth_dev_startrte_eth_macaddr_getrte_eth_promiscuous_enable,具体流程这里不再赘述,如果后面有需要可以去看源代码。

3)开始抓取:
这一部分主要是enable_pdumpenable_primary_monitordump_packets
(待续)

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页