xref: /dpdk/app/graph/graph.c (revision 3c4898ef762eeb2578b9ae3d7f6e3a0e5cbca8c8)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2023 Marvell.
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <cmdline_parse.h>
10 #include <cmdline_parse_num.h>
11 #include <cmdline_parse_string.h>
12 #include <cmdline_socket.h>
13 #include <rte_ethdev.h>
14 #include <rte_graph_worker.h>
15 #include <rte_log.h>
16 
17 #include "graph_priv.h"
18 #include "module_api.h"
19 
20 #define RTE_LOGTYPE_APP_GRAPH RTE_LOGTYPE_USER1
21 
22 static const char
23 cmd_graph_help[] = "graph <usecases> bsz <size> tmo <ns> coremask <bitmask> "
24 		   "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
25 		   "pcap_file <output_capture_file>";
26 
27 static const char * const supported_usecases[] = {"l3fwd"};
28 struct graph_config graph_config;
29 bool graph_started;
30 
31 /* Check the link rc of all ports in up to 9s, and print them finally */
32 static void
33 check_all_ports_link_status(uint32_t port_mask)
34 {
35 #define CHECK_INTERVAL 100 /* 100ms */
36 #define MAX_CHECK_TIME 90  /* 9s (90 * 100ms) in total */
37 	char link_rc_text[RTE_ETH_LINK_MAX_STR_LEN];
38 	uint8_t count, all_ports_up, print_flag = 0;
39 	struct rte_eth_link link;
40 	uint16_t portid;
41 	int rc;
42 
43 	printf("\nChecking link status...");
44 	fflush(stdout);
45 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
46 		if (force_quit)
47 			return;
48 
49 		all_ports_up = 1;
50 		RTE_ETH_FOREACH_DEV(portid)
51 		{
52 			if (force_quit)
53 				return;
54 
55 			if ((port_mask & (1 << portid)) == 0)
56 				continue;
57 
58 			memset(&link, 0, sizeof(link));
59 			rc = rte_eth_link_get_nowait(portid, &link);
60 			if (rc < 0) {
61 				all_ports_up = 0;
62 				if (print_flag == 1)
63 					printf("Port %u link get failed: %s\n",
64 					       portid, rte_strerror(-rc));
65 				continue;
66 			}
67 
68 			/* Print link rc if flag set */
69 			if (print_flag == 1) {
70 				rte_eth_link_to_str(link_rc_text, sizeof(link_rc_text),
71 					&link);
72 				printf("Port %d %s\n", portid, link_rc_text);
73 				continue;
74 			}
75 
76 			/* Clear all_ports_up flag if any link down */
77 			if (link.link_status == RTE_ETH_LINK_DOWN) {
78 				all_ports_up = 0;
79 				break;
80 			}
81 		}
82 
83 		/* After finally printing all link rc, get out */
84 		if (print_flag == 1)
85 			break;
86 
87 		if (all_ports_up == 0) {
88 			printf(".");
89 			fflush(stdout);
90 			rte_delay_ms(CHECK_INTERVAL);
91 		}
92 
93 		/* Set the print_flag if all ports up or timeout */
94 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
95 			print_flag = 1;
96 			printf("Done\n");
97 		}
98 	}
99 }
100 
101 static bool
102 parser_usecases_read(char *usecases)
103 {
104 	bool valid = false;
105 	uint32_t i, j = 0;
106 	char *token;
107 
108 	token = strtok(usecases, ",");
109 	while (token != NULL) {
110 		for (i = 0; i < RTE_DIM(supported_usecases); i++) {
111 			if (strcmp(supported_usecases[i], token) == 0) {
112 				graph_config.usecases[j].enabled = true;
113 				rte_strscpy(graph_config.usecases[j].name, token, 31);
114 				valid = true;
115 				j++;
116 				break;
117 			}
118 		}
119 		token = strtok(NULL, ",");
120 	}
121 
122 	return valid;
123 }
124 
125 static uint64_t
126 graph_worker_count_get(void)
127 {
128 	uint64_t nb_worker = 0;
129 	uint64_t coremask;
130 
131 	coremask = graph_config.params.coremask;
132 	while (coremask) {
133 		if (coremask & 0x1)
134 			nb_worker++;
135 
136 		coremask = (coremask >> 1);
137 	}
138 
139 	return nb_worker;
140 }
141 
142 static struct rte_node_ethdev_config *
143 graph_rxtx_node_config_get(uint32_t *num_conf, uint32_t *num_graphs)
144 {
145 	uint32_t n_tx_queue, nb_conf = 0, lcore_id;
146 	uint16_t queueid, portid, nb_graphs = 0;
147 	uint8_t nb_rx_queue, queue;
148 	struct lcore_conf *qconf;
149 
150 	n_tx_queue = graph_worker_count_get();
151 	if (n_tx_queue > RTE_MAX_ETHPORTS)
152 		n_tx_queue = RTE_MAX_ETHPORTS;
153 
154 	RTE_ETH_FOREACH_DEV(portid) {
155 		/* Skip ports that are not enabled */
156 		if ((enabled_port_mask & (1 << portid)) == 0) {
157 			printf("\nSkipping disabled port %d\n", portid);
158 			continue;
159 		}
160 
161 		nb_rx_queue = ethdev_rx_num_rx_queues_get(portid);
162 
163 		/* Setup ethdev node config */
164 		ethdev_conf[nb_conf].port_id = portid;
165 		ethdev_conf[nb_conf].num_rx_queues = nb_rx_queue;
166 		ethdev_conf[nb_conf].num_tx_queues = n_tx_queue;
167 		ethdev_conf[nb_conf].mp = ethdev_mempool_list_by_portid(portid);
168 		ethdev_conf[nb_conf].mp_count = 1; /* Check with pools */
169 
170 		nb_conf++;
171 	}
172 
173 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
174 		if (rte_lcore_is_enabled(lcore_id) == 0)
175 			continue;
176 
177 		qconf = &lcore_conf[lcore_id];
178 		printf("\nInitializing rx queues on lcore %u ... ", lcore_id);
179 		fflush(stdout);
180 
181 		/* Init RX queues */
182 		for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
183 			portid = qconf->rx_queue_list[queue].port_id;
184 			queueid = qconf->rx_queue_list[queue].queue_id;
185 
186 			/* Add this queue node to its graph */
187 			snprintf(qconf->rx_queue_list[queue].node_name, RTE_NODE_NAMESIZE,
188 				 "ethdev_rx-%u-%u", portid, queueid);
189 		}
190 		if (qconf->n_rx_queue)
191 			nb_graphs++;
192 	}
193 
194 	printf("\n");
195 
196 	ethdev_start();
197 	check_all_ports_link_status(enabled_port_mask);
198 
199 	*num_conf = nb_conf;
200 	*num_graphs = nb_graphs;
201 	return ethdev_conf;
202 }
203 
204 static void
205 graph_stats_print_to_file(void)
206 {
207 	struct rte_graph_cluster_stats_param s_param;
208 	struct rte_graph_cluster_stats *stats;
209 	const char *pattern = "worker_*";
210 	FILE *fp = NULL;
211 	size_t sz, len;
212 
213 	/* Prepare stats object */
214 	fp = fopen("/tmp/graph_stats.txt", "w+");
215 	if (fp == NULL)
216 		rte_exit(EXIT_FAILURE, "Error in opening stats file\n");
217 
218 	memset(&s_param, 0, sizeof(s_param));
219 	s_param.f = fp;
220 	s_param.socket_id = SOCKET_ID_ANY;
221 	s_param.graph_patterns = &pattern;
222 	s_param.nb_graph_patterns = 1;
223 
224 	stats = rte_graph_cluster_stats_create(&s_param);
225 	if (stats == NULL)
226 		rte_exit(EXIT_FAILURE, "Unable to create stats object\n");
227 
228 	/* Clear screen and move to top left */
229 	rte_graph_cluster_stats_get(stats, 0);
230 	rte_delay_ms(1E3);
231 
232 	fseek(fp, 0L, SEEK_END);
233 	sz = ftell(fp);
234 	fseek(fp, 0L, SEEK_SET);
235 
236 	len = strlen(conn->msg_out);
237 	conn->msg_out += len;
238 
239 	sz = fread(conn->msg_out, sizeof(char), sz, fp);
240 	len = strlen(conn->msg_out);
241 	conn->msg_out_len_max -= len;
242 	rte_graph_cluster_stats_destroy(stats);
243 
244 	fclose(fp);
245 }
246 
247 static void
248 cli_graph_stats(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
249 		__rte_unused void *data)
250 {
251 	graph_stats_print_to_file();
252 }
253 
254 bool
255 graph_status_get(void)
256 {
257 	return graph_started;
258 }
259 
260 static void
261 cli_graph_start(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
262 		__rte_unused void *data)
263 {
264 	struct rte_node_ethdev_config *conf;
265 	uint32_t nb_graphs = 0, nb_conf, i;
266 	int rc = -EINVAL;
267 
268 	conf = graph_rxtx_node_config_get(&nb_conf, &nb_graphs);
269 	for (i = 0; i < MAX_GRAPH_USECASES; i++) {
270 		if (!strcmp(graph_config.usecases[i].name, "l3fwd")) {
271 			if (graph_config.usecases[i].enabled) {
272 				rc  = usecase_l3fwd_configure(conf, nb_conf, nb_graphs);
273 				break;
274 			}
275 		}
276 	}
277 
278 	if (!rc)
279 		graph_started = true;
280 }
281 
282 static int
283 graph_config_add(char *usecases, struct graph_config *config)
284 {
285 	uint64_t lcore_id, core_num;
286 	uint64_t eal_coremask = 0;
287 
288 	if (!parser_usecases_read(usecases))
289 		return -EINVAL;
290 
291 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
292 		if (rte_lcore_is_enabled(lcore_id))
293 			eal_coremask |= RTE_BIT64(lcore_id);
294 	}
295 
296 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
297 		core_num = 1 << lcore_id;
298 		if (config->params.coremask & core_num) {
299 			if (eal_coremask & core_num)
300 				continue;
301 			else
302 				return -EINVAL;
303 		}
304 	}
305 
306 	graph_config.params.bsz = config->params.bsz;
307 	graph_config.params.tmo = config->params.tmo;
308 	graph_config.params.coremask = config->params.coremask;
309 	graph_config.model = config->model;
310 	graph_config.pcap_ena = config->pcap_ena;
311 	graph_config.num_pcap_pkts = config->num_pcap_pkts;
312 	graph_config.pcap_file = strdup(config->pcap_file);
313 
314 	return 0;
315 }
316 
317 void
318 graph_pcap_config_get(uint8_t *pcap_ena, uint64_t *num_pkts, char **file)
319 {
320 
321 	*pcap_ena = graph_config.pcap_ena;
322 	*num_pkts = graph_config.num_pcap_pkts;
323 	*file = graph_config.pcap_file;
324 }
325 
326 int
327 graph_walk_start(void *conf)
328 {
329 	struct lcore_conf *qconf;
330 	struct rte_graph *graph;
331 	uint32_t lcore_id;
332 
333 	RTE_SET_USED(conf);
334 
335 	lcore_id = rte_lcore_id();
336 	qconf = &lcore_conf[lcore_id];
337 	graph = qconf->graph;
338 
339 	if (!graph) {
340 		RTE_LOG(INFO, APP_GRAPH, "Lcore %u has nothing to do\n", lcore_id);
341 		return 0;
342 	}
343 
344 	RTE_LOG(INFO, APP_GRAPH, "Entering main loop on lcore %u, graph %s(%p)\n", lcore_id,
345 		qconf->name, graph);
346 
347 	while (likely(!force_quit))
348 		rte_graph_walk(graph);
349 
350 	return 0;
351 }
352 
353 void
354 graph_stats_print(void)
355 {
356 	const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
357 	const char clr[] = {27, '[', '2', 'J', '\0'};
358 	struct rte_graph_cluster_stats_param s_param;
359 	struct rte_graph_cluster_stats *stats;
360 	const char *pattern = "worker_*";
361 
362 	/* Prepare stats object */
363 	memset(&s_param, 0, sizeof(s_param));
364 	s_param.f = stdout;
365 	s_param.socket_id = SOCKET_ID_ANY;
366 	s_param.graph_patterns = &pattern;
367 	s_param.nb_graph_patterns = 1;
368 
369 	stats = rte_graph_cluster_stats_create(&s_param);
370 	if (stats == NULL)
371 		rte_exit(EXIT_FAILURE, "Unable to create stats object\n");
372 
373 	while (!force_quit) {
374 		/* Clear screen and move to top left */
375 		printf("%s%s", clr, topLeft);
376 		rte_graph_cluster_stats_get(stats, 0);
377 		rte_delay_ms(1E3);
378 		if (app_graph_exit())
379 			force_quit = true;
380 	}
381 
382 	rte_graph_cluster_stats_destroy(stats);
383 }
384 
385 uint64_t
386 graph_coremask_get(void)
387 {
388 	return graph_config.params.coremask;
389 }
390 
391 static void
392 cli_graph(void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data)
393 {
394 	struct graph_config_cmd_tokens *res = parsed_result;
395 	struct graph_config config;
396 	char *model_name;
397 	uint8_t model;
398 	int rc;
399 
400 	model_name = res->model_name;
401 	if (strcmp(model_name, "default") == 0) {
402 		model = GRAPH_MODEL_RTC;
403 	} else if (strcmp(model_name, "rtc") == 0) {
404 		model = GRAPH_MODEL_RTC;
405 	} else if (strcmp(model_name, "mcd") == 0) {
406 		model = GRAPH_MODEL_MCD;
407 	} else {
408 		printf(MSG_ARG_NOT_FOUND, "model arguments");
409 		return;
410 	}
411 
412 	config.params.bsz = res->size;
413 	config.params.tmo = res->ns;
414 	config.params.coremask = res->mask;
415 	config.model = model;
416 	config.pcap_ena = res->pcap_ena;
417 	config.num_pcap_pkts = res->num_pcap_pkts;
418 	config.pcap_file = res->pcap_file;
419 	rc = graph_config_add(res->usecase, &config);
420 	if (rc < 0) {
421 		cli_exit();
422 		printf(MSG_CMD_FAIL, res->graph);
423 		rte_exit(EXIT_FAILURE, "coremask is Invalid\n");
424 	}
425 }
426 
427 static void
428 cli_graph_help(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
429 	       __rte_unused void *data)
430 {
431 	size_t len;
432 
433 	len = strlen(conn->msg_out);
434 	conn->msg_out += len;
435 	snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n%s\n%s\n%s\n",
436 		 "----------------------------- graph command help -----------------------------",
437 		 cmd_graph_help, "graph start", "graph stats show");
438 
439 	len = strlen(conn->msg_out);
440 	conn->msg_out_len_max -= len;
441 }
442 
443 cmdline_parse_token_string_t graph_display_graph =
444 	TOKEN_STRING_INITIALIZER(struct graph_stats_cmd_tokens, graph, "graph");
445 cmdline_parse_token_string_t graph_display_stats =
446 	TOKEN_STRING_INITIALIZER(struct graph_stats_cmd_tokens, stats, "stats");
447 cmdline_parse_token_string_t graph_display_show =
448 	TOKEN_STRING_INITIALIZER(struct graph_stats_cmd_tokens, show, "show");
449 
450 cmdline_parse_inst_t graph_stats_cmd_ctx = {
451 	.f = cli_graph_stats,
452 	.data = NULL,
453 	.help_str = "graph stats show",
454 	.tokens = {
455 		(void *)&graph_display_graph,
456 		(void *)&graph_display_stats,
457 		(void *)&graph_display_show,
458 		NULL,
459 	},
460 };
461 
462 cmdline_parse_token_string_t graph_config_start_graph =
463 	TOKEN_STRING_INITIALIZER(struct graph_start_cmd_tokens, graph, "graph");
464 cmdline_parse_token_string_t graph_config_start =
465 	TOKEN_STRING_INITIALIZER(struct graph_start_cmd_tokens, start, "start");
466 
467 cmdline_parse_inst_t graph_start_cmd_ctx = {
468 	.f = cli_graph_start,
469 	.data = NULL,
470 	.help_str = "graph start",
471 	.tokens = {
472 		(void *)&graph_config_start_graph,
473 		(void *)&graph_config_start,
474 		NULL,
475 	},
476 };
477 
478 cmdline_parse_token_string_t graph_config_add_graph =
479 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, graph, "graph");
480 cmdline_parse_token_string_t graph_config_add_usecase =
481 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, usecase, NULL);
482 cmdline_parse_token_string_t graph_config_add_coremask =
483 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, coremask, "coremask");
484 cmdline_parse_token_num_t graph_config_add_mask =
485 	TOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, mask, RTE_UINT64);
486 cmdline_parse_token_string_t graph_config_add_bsz =
487 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, bsz, "bsz");
488 cmdline_parse_token_num_t graph_config_add_size =
489 	TOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, size, RTE_UINT16);
490 cmdline_parse_token_string_t graph_config_add_tmo =
491 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, tmo, "tmo");
492 cmdline_parse_token_num_t graph_config_add_ns =
493 	TOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, ns, RTE_UINT64);
494 cmdline_parse_token_string_t graph_config_add_model =
495 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, model, "model");
496 cmdline_parse_token_string_t graph_config_add_model_name =
497 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, model_name, "rtc#mcd#default");
498 cmdline_parse_token_string_t graph_config_add_capt_ena =
499 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, capt_ena, "pcap_enable");
500 cmdline_parse_token_num_t graph_config_add_pcap_ena =
501 	TOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, pcap_ena, RTE_UINT8);
502 cmdline_parse_token_string_t graph_config_add_capt_pkts_count =
503 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, capt_pkts_count, "num_pcap_pkts");
504 cmdline_parse_token_num_t graph_config_add_num_pcap_pkts =
505 	TOKEN_NUM_INITIALIZER(struct graph_config_cmd_tokens, num_pcap_pkts, RTE_UINT64);
506 cmdline_parse_token_string_t graph_config_add_capt_file =
507 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, capt_file, "pcap_file");
508 cmdline_parse_token_string_t graph_config_add_pcap_file =
509 	TOKEN_STRING_INITIALIZER(struct graph_config_cmd_tokens, pcap_file, NULL);
510 
511 cmdline_parse_inst_t graph_config_cmd_ctx = {
512 	.f = cli_graph,
513 	.data = NULL,
514 	.help_str = cmd_graph_help,
515 	.tokens = {
516 		(void *)&graph_config_add_graph,
517 		(void *)&graph_config_add_usecase,
518 		(void *)&graph_config_add_coremask,
519 		(void *)&graph_config_add_mask,
520 		(void *)&graph_config_add_bsz,
521 		(void *)&graph_config_add_size,
522 		(void *)&graph_config_add_tmo,
523 		(void *)&graph_config_add_ns,
524 		(void *)&graph_config_add_model,
525 		(void *)&graph_config_add_model_name,
526 		(void *)&graph_config_add_capt_ena,
527 		(void *)&graph_config_add_pcap_ena,
528 		(void *)&graph_config_add_capt_pkts_count,
529 		(void *)&graph_config_add_num_pcap_pkts,
530 		(void *)&graph_config_add_capt_file,
531 		(void *)&graph_config_add_pcap_file,
532 		NULL,
533 	},
534 };
535 
536 cmdline_parse_token_string_t graph_help_cmd =
537 	TOKEN_STRING_INITIALIZER(struct graph_help_cmd_tokens, help, "help");
538 cmdline_parse_token_string_t graph_help_graph =
539 	TOKEN_STRING_INITIALIZER(struct graph_help_cmd_tokens, graph, "graph");
540 
541 cmdline_parse_inst_t graph_help_cmd_ctx = {
542 	.f = cli_graph_help,
543 	.data = NULL,
544 	.help_str = "",
545 	.tokens = {
546 		(void *)&graph_help_cmd,
547 		(void *)&graph_help_graph,
548 		NULL,
549 	},
550 };
551