Branch data Line data Source code
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_graph_feature_arc_worker.h>
16 : : #include <rte_log.h>
17 : :
18 : : #include "graph_priv.h"
19 : : #include "module_api.h"
20 : :
21 : : #define RTE_LOGTYPE_APP_GRAPH RTE_LOGTYPE_USER1
22 : :
23 : : static const char
24 : : cmd_graph_help[] = "graph <usecases> coremask <bitmask> bsz <size> tmo <ns> "
25 : : "model <rtc | mcd | default> pcap_enable <0 | 1> num_pcap_pkts <num>"
26 : : "pcap_file <output_capture_file>";
27 : :
28 : : static const char * const supported_usecases[] = {"l3fwd", "l2fwd"};
29 : : struct graph_config graph_config;
30 : : bool graph_started;
31 : :
32 : : /* Check the link rc of all ports in up to 9s, and print them finally */
33 : : static void
34 : 0 : check_all_ports_link_status(uint32_t port_mask)
35 : : {
36 : : #define CHECK_INTERVAL 100 /* 100ms */
37 : : #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
38 : : char link_rc_text[RTE_ETH_LINK_MAX_STR_LEN];
39 : : uint8_t count, all_ports_up, print_flag = 0;
40 : : struct rte_eth_link link;
41 : : uint16_t portid;
42 : : int rc;
43 : :
44 : : printf("\nChecking link status...");
45 : 0 : fflush(stdout);
46 : 0 : for (count = 0; count <= MAX_CHECK_TIME; count++) {
47 : 0 : if (force_quit)
48 : 0 : return;
49 : :
50 : : all_ports_up = 1;
51 : 0 : RTE_ETH_FOREACH_DEV(portid)
52 : : {
53 : 0 : if (force_quit)
54 : : return;
55 : :
56 : 0 : if ((port_mask & (1 << portid)) == 0)
57 : 0 : continue;
58 : :
59 : : memset(&link, 0, sizeof(link));
60 : 0 : rc = rte_eth_link_get_nowait(portid, &link);
61 : 0 : if (rc < 0) {
62 : : all_ports_up = 0;
63 : 0 : if (print_flag == 1)
64 : 0 : printf("Port %u link get failed: %s\n",
65 : : portid, rte_strerror(-rc));
66 : 0 : continue;
67 : : }
68 : :
69 : : /* Print link rc if flag set */
70 : 0 : if (print_flag == 1) {
71 : 0 : rte_eth_link_to_str(link_rc_text, sizeof(link_rc_text),
72 : : &link);
73 : : printf("Port %d %s\n", portid, link_rc_text);
74 : 0 : continue;
75 : : }
76 : :
77 : : /* Clear all_ports_up flag if any link down */
78 : 0 : if (link.link_status == RTE_ETH_LINK_DOWN) {
79 : : all_ports_up = 0;
80 : : break;
81 : : }
82 : : }
83 : :
84 : : /* After finally printing all link rc, get out */
85 : 0 : if (print_flag == 1)
86 : : break;
87 : :
88 : 0 : if (all_ports_up == 0) {
89 : : printf(".");
90 : 0 : fflush(stdout);
91 : : rte_delay_ms(CHECK_INTERVAL);
92 : : }
93 : :
94 : : /* Set the print_flag if all ports up or timeout */
95 : 0 : if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
96 : : print_flag = 1;
97 : : printf("Done\n");
98 : : }
99 : : }
100 : : }
101 : :
102 : : static bool
103 : 0 : parser_usecases_read(char *usecases)
104 : : {
105 : : bool valid = false;
106 : : uint32_t i, j = 0;
107 : 0 : char *token, *saveptr = NULL;
108 : :
109 : 0 : token = strtok_r(usecases, ",", &saveptr);
110 : 0 : while (token != NULL) {
111 : 0 : for (i = 0; i < RTE_DIM(supported_usecases); i++) {
112 : 0 : if (strcmp(supported_usecases[i], token) == 0) {
113 : 0 : graph_config.usecases[j].enabled = true;
114 : 0 : rte_strscpy(graph_config.usecases[j].name, token, 31);
115 : : valid = true;
116 : 0 : j++;
117 : 0 : break;
118 : : }
119 : : }
120 : 0 : token = strtok_r(NULL, ",", &saveptr);
121 : : }
122 : :
123 : 0 : return valid;
124 : : }
125 : :
126 : : static uint64_t
127 : : graph_worker_count_get(void)
128 : : {
129 : : uint64_t nb_worker = 0;
130 : : uint64_t coremask;
131 : :
132 : 0 : coremask = graph_config.params.coremask;
133 : 0 : while (coremask) {
134 : 0 : if (coremask & 0x1)
135 : 0 : nb_worker++;
136 : :
137 : 0 : coremask = (coremask >> 1);
138 : : }
139 : :
140 : : return nb_worker;
141 : : }
142 : :
143 : : static struct rte_node_ethdev_config *
144 : 0 : graph_rxtx_node_config_get(uint32_t *num_conf, uint32_t *num_graphs)
145 : : {
146 : : uint32_t n_tx_queue, nb_conf = 0, lcore_id;
147 : : uint16_t queueid, portid, nb_graphs = 0;
148 : : uint8_t nb_rx_queue, queue;
149 : : struct lcore_conf *qconf;
150 : :
151 : 0 : n_tx_queue = graph_worker_count_get();
152 : : if (n_tx_queue > RTE_MAX_ETHPORTS)
153 : : n_tx_queue = RTE_MAX_ETHPORTS;
154 : :
155 : 0 : RTE_ETH_FOREACH_DEV(portid) {
156 : : /* Skip ports that are not enabled */
157 : 0 : if ((enabled_port_mask & (1 << portid)) == 0) {
158 : : printf("\nSkipping disabled port %d\n", portid);
159 : 0 : continue;
160 : : }
161 : :
162 : 0 : nb_rx_queue = ethdev_rx_num_rx_queues_get(portid);
163 : :
164 : : /* Setup ethdev node config */
165 : 0 : ethdev_conf[nb_conf].port_id = portid;
166 : 0 : ethdev_conf[nb_conf].num_rx_queues = nb_rx_queue;
167 : 0 : ethdev_conf[nb_conf].num_tx_queues = n_tx_queue;
168 : 0 : ethdev_conf[nb_conf].mp = ethdev_mempool_list_by_portid(portid);
169 : 0 : ethdev_conf[nb_conf].mp_count = 1; /* Check with pools */
170 : :
171 : 0 : nb_conf++;
172 : : }
173 : :
174 : 0 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
175 : 0 : if (rte_lcore_is_enabled(lcore_id) == 0)
176 : 0 : continue;
177 : :
178 : : qconf = &lcore_conf[lcore_id];
179 : : printf("\nInitializing rx queues on lcore %u ... ", lcore_id);
180 : 0 : fflush(stdout);
181 : :
182 : : /* Init RX queues */
183 : 0 : for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
184 : 0 : portid = qconf->rx_queue_list[queue].port_id;
185 : 0 : queueid = qconf->rx_queue_list[queue].queue_id;
186 : :
187 : : /* Add this queue node to its graph */
188 : 0 : snprintf(qconf->rx_queue_list[queue].node_name, RTE_NODE_NAMESIZE,
189 : : "ethdev_rx-%u-%u", portid, queueid);
190 : : }
191 : 0 : if (qconf->n_rx_queue)
192 : 0 : nb_graphs++;
193 : : }
194 : :
195 : : printf("\n");
196 : :
197 : 0 : ethdev_start();
198 : 0 : check_all_ports_link_status(enabled_port_mask);
199 : :
200 : 0 : *num_conf = nb_conf;
201 : 0 : *num_graphs = nb_graphs;
202 : 0 : return ethdev_conf;
203 : : }
204 : :
205 : : static void
206 : 0 : graph_stats_print_to_file(void)
207 : : {
208 : : struct rte_graph_cluster_stats_param s_param;
209 : : struct rte_graph_cluster_stats *stats;
210 : 0 : const char *pattern = "worker_*";
211 : : FILE *fp = NULL;
212 : : size_t sz, len;
213 : :
214 : : /* Prepare stats object */
215 : 0 : fp = fopen("/tmp/graph_stats.txt", "w+");
216 : 0 : if (fp == NULL)
217 : 0 : rte_exit(EXIT_FAILURE, "Error in opening stats file\n");
218 : :
219 : : memset(&s_param, 0, sizeof(s_param));
220 : 0 : s_param.f = fp;
221 : 0 : s_param.socket_id = SOCKET_ID_ANY;
222 : 0 : s_param.graph_patterns = &pattern;
223 : 0 : s_param.nb_graph_patterns = 1;
224 : :
225 : 0 : stats = rte_graph_cluster_stats_create(&s_param);
226 : 0 : if (stats == NULL)
227 : 0 : rte_exit(EXIT_FAILURE, "Unable to create stats object\n");
228 : :
229 : : /* Clear screen and move to top left */
230 : 0 : rte_graph_cluster_stats_get(stats, 0);
231 : : rte_delay_ms(1E3);
232 : :
233 : 0 : fseek(fp, 0L, SEEK_END);
234 : 0 : sz = ftell(fp);
235 : 0 : fseek(fp, 0L, SEEK_SET);
236 : :
237 : 0 : len = strlen(conn->msg_out);
238 : 0 : conn->msg_out += len;
239 : :
240 : : sz = fread(conn->msg_out, sizeof(char), sz, fp);
241 : 0 : len = strlen(conn->msg_out);
242 : 0 : conn->msg_out_len_max -= len;
243 : 0 : rte_graph_cluster_stats_destroy(stats);
244 : :
245 : 0 : fclose(fp);
246 : 0 : }
247 : :
248 : : void
249 : 0 : cmd_graph_stats_show_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
250 : : __rte_unused void *data)
251 : : {
252 : 0 : graph_stats_print_to_file();
253 : 0 : }
254 : :
255 : : bool
256 : 0 : graph_status_get(void)
257 : : {
258 : 0 : return graph_started;
259 : : }
260 : :
261 : : void
262 : 0 : cmd_graph_start_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
263 : : __rte_unused void *data)
264 : : {
265 : : struct rte_node_ethdev_config *conf;
266 : 0 : uint32_t nb_graphs = 0, nb_conf, i;
267 : : int rc = -EINVAL;
268 : :
269 : 0 : if (app_graph_feature_arc_enabled())
270 : 0 : rte_graph_feature_arc_init(0);
271 : :
272 : 0 : conf = graph_rxtx_node_config_get(&nb_conf, &nb_graphs);
273 : 0 : for (i = 0; i < MAX_GRAPH_USECASES; i++) {
274 : 0 : if (!strcmp(graph_config.usecases[i].name, "l3fwd")) {
275 : 0 : if (graph_config.usecases[i].enabled) {
276 : 0 : rc = usecase_l3fwd_configure(conf, nb_conf, nb_graphs);
277 : 0 : break;
278 : : }
279 : : }
280 : 0 : if (!strcmp(graph_config.usecases[i].name, "l2fwd")) {
281 : 0 : if (graph_config.usecases[i].enabled) {
282 : 0 : rc = usecase_l2fwd_configure(conf, nb_conf, nb_graphs);
283 : 0 : break;
284 : : }
285 : : }
286 : : }
287 : :
288 : 0 : if (!rc)
289 : 0 : graph_started = true;
290 : 0 : }
291 : :
292 : : static int
293 : 0 : graph_config_add(char *usecases, struct graph_config *config)
294 : : {
295 : : uint64_t lcore_id, core_num;
296 : : uint64_t eal_coremask = 0;
297 : :
298 : 0 : if (!parser_usecases_read(usecases))
299 : : return -EINVAL;
300 : :
301 : 0 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
302 : 0 : if (rte_lcore_is_enabled(lcore_id))
303 : 0 : eal_coremask |= RTE_BIT64(lcore_id);
304 : : }
305 : :
306 : 0 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
307 : 0 : core_num = 1 << lcore_id;
308 : 0 : if (config->params.coremask & core_num) {
309 : 0 : if (eal_coremask & core_num)
310 : 0 : continue;
311 : : else
312 : : return -EINVAL;
313 : : }
314 : : }
315 : :
316 : 0 : graph_config.params.bsz = config->params.bsz;
317 : 0 : graph_config.params.tmo = config->params.tmo;
318 : 0 : graph_config.params.coremask = config->params.coremask;
319 : 0 : graph_config.model = config->model;
320 : 0 : graph_config.pcap_ena = config->pcap_ena;
321 : 0 : graph_config.num_pcap_pkts = config->num_pcap_pkts;
322 : 0 : graph_config.pcap_file = strdup(config->pcap_file);
323 : :
324 : 0 : return 0;
325 : : }
326 : :
327 : : void
328 : 0 : graph_pcap_config_get(uint8_t *pcap_ena, uint64_t *num_pkts, char **file)
329 : : {
330 : :
331 : 0 : *pcap_ena = graph_config.pcap_ena;
332 : 0 : *num_pkts = graph_config.num_pcap_pkts;
333 : 0 : *file = graph_config.pcap_file;
334 : 0 : }
335 : :
336 : : int
337 : 0 : graph_walk_start(void *conf)
338 : : {
339 : : struct lcore_conf *qconf;
340 : : struct rte_graph *graph;
341 : : uint32_t lcore_id;
342 : :
343 : : RTE_SET_USED(conf);
344 : :
345 : : lcore_id = rte_lcore_id();
346 : : qconf = &lcore_conf[lcore_id];
347 : 0 : graph = qconf->graph;
348 : :
349 : 0 : if (!graph) {
350 : 0 : RTE_LOG(INFO, APP_GRAPH, "Lcore %u has nothing to do\n", lcore_id);
351 : 0 : return 0;
352 : : }
353 : :
354 : 0 : RTE_LOG(INFO, APP_GRAPH, "Entering main loop on lcore %u, graph %s(%p)\n", lcore_id,
355 : : qconf->name, graph);
356 : :
357 : 0 : while (likely(!force_quit))
358 : 0 : rte_graph_walk(graph);
359 : :
360 : : return 0;
361 : : }
362 : :
363 : : void
364 : 0 : graph_stats_print(void)
365 : : {
366 : 0 : const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
367 : 0 : const char clr[] = {27, '[', '2', 'J', '\0'};
368 : : struct rte_graph_cluster_stats_param s_param;
369 : : struct rte_graph_cluster_stats *stats;
370 : 0 : const char *pattern = "worker_*";
371 : :
372 : : /* Prepare stats object */
373 : : memset(&s_param, 0, sizeof(s_param));
374 : 0 : s_param.f = stdout;
375 : 0 : s_param.socket_id = SOCKET_ID_ANY;
376 : 0 : s_param.graph_patterns = &pattern;
377 : 0 : s_param.nb_graph_patterns = 1;
378 : :
379 : 0 : stats = rte_graph_cluster_stats_create(&s_param);
380 : 0 : if (stats == NULL)
381 : 0 : rte_exit(EXIT_FAILURE, "Unable to create stats object\n");
382 : :
383 : 0 : while (!force_quit) {
384 : : /* Clear screen and move to top left */
385 : : printf("%s%s", clr, topLeft);
386 : 0 : rte_graph_cluster_stats_get(stats, 0);
387 : : rte_delay_ms(1E3);
388 : 0 : if (app_graph_exit())
389 : 0 : force_quit = true;
390 : : }
391 : :
392 : 0 : rte_graph_cluster_stats_destroy(stats);
393 : 0 : }
394 : :
395 : : uint64_t
396 : 0 : graph_coremask_get(void)
397 : : {
398 : 0 : return graph_config.params.coremask;
399 : : }
400 : :
401 : : void
402 : 0 : cmd_graph_parsed(void *parsed_result, __rte_unused struct cmdline *cl, __rte_unused void *data)
403 : : {
404 : : struct cmd_graph_result *res = parsed_result;
405 : : struct graph_config config;
406 : : char *model_name;
407 : : uint8_t model;
408 : : int rc;
409 : :
410 : 0 : model_name = res->model_name;
411 : 0 : if (strcmp(model_name, "default") == 0) {
412 : : model = GRAPH_MODEL_RTC;
413 : 0 : } else if (strcmp(model_name, "rtc") == 0) {
414 : : model = GRAPH_MODEL_RTC;
415 : 0 : } else if (strcmp(model_name, "mcd") == 0) {
416 : : model = GRAPH_MODEL_MCD;
417 : : } else {
418 : : printf(MSG_ARG_NOT_FOUND, "model arguments");
419 : 0 : return;
420 : : }
421 : :
422 : 0 : config.params.bsz = res->size;
423 : 0 : config.params.tmo = res->ns;
424 : 0 : config.params.coremask = res->mask;
425 : 0 : config.model = model;
426 : 0 : config.pcap_ena = res->pcap_ena;
427 : 0 : config.num_pcap_pkts = res->num_pcap_pkts;
428 : 0 : config.pcap_file = res->pcap_file;
429 : 0 : rc = graph_config_add(res->usecase, &config);
430 : 0 : if (rc < 0) {
431 : 0 : cli_exit();
432 : 0 : printf(MSG_CMD_FAIL, res->graph);
433 : 0 : rte_exit(EXIT_FAILURE, "coremask is Invalid\n");
434 : : }
435 : : }
436 : :
437 : : void
438 : 0 : cmd_help_graph_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
439 : : __rte_unused void *data)
440 : : {
441 : : size_t len;
442 : :
443 : 0 : len = strlen(conn->msg_out);
444 : 0 : conn->msg_out += len;
445 : 0 : snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n%s\n%s\n%s\n",
446 : : "----------------------------- graph command help -----------------------------",
447 : : cmd_graph_help, "graph start", "graph stats show");
448 : :
449 : 0 : len = strlen(conn->msg_out);
450 : 0 : conn->msg_out_len_max -= len;
451 : 0 : }
|