xref: /dpdk/app/graph/ethdev.c (revision 0f1dc8cb671203d52488fd66936f2fe6dcca03cc)
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_bitops.h>
14 #include <rte_ethdev.h>
15 #include <rte_mempool.h>
16 
17 #include "ethdev_priv.h"
18 #include "module_api.h"
19 
20 static const char
21 cmd_ethdev_mtu_help[] = "ethdev <ethdev_name> mtu <mtu_sz>";
22 
23 static const char
24 cmd_ethdev_prom_mode_help[] = "ethdev <ethdev_name> promiscuous <on/off>";
25 
26 static const char
27 cmd_ethdev_help[] = "ethdev <ethdev_name> rxq <n_queues> txq <n_queues> <mempool_name>";
28 
29 static const char
30 cmd_ethdev_stats_help[] = "ethdev <ethdev_name> stats";
31 
32 static const char
33 cmd_ethdev_show_help[] = "ethdev <ethdev_name> show";
34 
35 static const char
36 cmd_ethdev_ip4_addr_help[] = "ethdev <ethdev_name> ip4 addr add <ip> netmask <mask>";
37 
38 static const char
39 cmd_ethdev_ip6_addr_help[] = "ethdev <ethdev_name> ip6 addr add <ip> netmask <mask>";
40 
41 static const char
42 cmd_ethdev_forward_help[] = "ethdev forward <tx_dev_name> <rx_dev_name>";
43 
44 static struct rte_eth_conf port_conf_default = {
45 	.link_speeds = 0,
46 	.rxmode = {
47 		.mq_mode = RTE_ETH_MQ_RX_NONE,
48 		.mtu = 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo frame MTU */
49 	},
50 	.rx_adv_conf = {
51 		.rss_conf = {
52 			.rss_key = NULL,
53 			.rss_key_len = 40,
54 			.rss_hf = 0,
55 		},
56 	},
57 	.txmode = {
58 		.mq_mode = RTE_ETH_MQ_TX_NONE,
59 	},
60 	.lpbk_mode = 0,
61 };
62 
63 uint32_t enabled_port_mask;
64 static struct ethdev_head eth_node = TAILQ_HEAD_INITIALIZER(eth_node);
65 
66 
67 static struct ethdev*
68 ethdev_port_by_id(uint16_t port_id)
69 {
70 	struct ethdev *port;
71 
72 	TAILQ_FOREACH(port, &eth_node, next) {
73 		if (port->config.port_id == port_id)
74 			return port;
75 	}
76 	return NULL;
77 }
78 
79 int16_t
80 ethdev_txport_by_rxport_get(uint16_t portid_rx)
81 {
82 	int portid = -EINVAL;
83 	struct ethdev *port;
84 
85 	port = ethdev_port_by_id(portid_rx);
86 	if (port)
87 		portid = port->tx_port_id;
88 
89 	return portid;
90 }
91 
92 void *
93 ethdev_mempool_list_by_portid(uint16_t portid)
94 {
95 	struct ethdev *port;
96 
97 	if (portid >= RTE_MAX_ETHPORTS)
98 		return NULL;
99 
100 	port = ethdev_port_by_id(portid);
101 	if (port)
102 		return &(port->config.rx.mp);
103 	else
104 		return NULL;
105 }
106 
107 int16_t
108 ethdev_portid_by_ip4(uint32_t ip, uint32_t mask)
109 {
110 	int portid = -EINVAL;
111 	struct ethdev *port;
112 
113 	TAILQ_FOREACH(port, &eth_node, next) {
114 		if (mask == 0) {
115 			if ((port->ip4_addr.ip & port->ip4_addr.mask) == (ip & port->ip4_addr.mask))
116 				return port->config.port_id;
117 		} else {
118 			if ((port->ip4_addr.ip & port->ip4_addr.mask) == (ip & mask))
119 				return port->config.port_id;
120 		}
121 	}
122 
123 	return portid;
124 }
125 
126 int16_t
127 ethdev_portid_by_ip6(uint8_t *ip, uint8_t *mask)
128 {
129 	int portid = -EINVAL;
130 	struct ethdev *port;
131 	int j;
132 
133 	TAILQ_FOREACH(port, &eth_node, next) {
134 		for (j = 0; j < ETHDEV_IPV6_ADDR_LEN; j++) {
135 			if (mask == NULL) {
136 				if ((port->ip6_addr.ip[j] & port->ip6_addr.mask[j]) !=
137 				    (ip[j] & port->ip6_addr.mask[j]))
138 					break;
139 
140 			} else {
141 				if ((port->ip6_addr.ip[j] & port->ip6_addr.mask[j]) !=
142 				    (ip[j] & mask[j]))
143 					break;
144 			}
145 		}
146 		if (j == ETHDEV_IPV6_ADDR_LEN)
147 			return port->config.port_id;
148 	}
149 
150 	return portid;
151 }
152 
153 void
154 ethdev_list_clean(void)
155 {
156 	struct ethdev *port;
157 
158 	while (!TAILQ_EMPTY(&eth_node)) {
159 		port = TAILQ_FIRST(&eth_node);
160 		TAILQ_REMOVE(&eth_node, port, next);
161 	}
162 }
163 
164 void
165 ethdev_stop(void)
166 {
167 	uint16_t portid;
168 	int rc;
169 
170 	RTE_ETH_FOREACH_DEV(portid) {
171 		if ((enabled_port_mask & (1 << portid)) == 0)
172 			continue;
173 		printf("Closing port %d...", portid);
174 		rc = rte_eth_dev_stop(portid);
175 		if (rc != 0)
176 			printf("Failed to stop port %u: %s\n",
177 					portid, rte_strerror(-rc));
178 		rte_eth_dev_close(portid);
179 		printf(" Done\n");
180 	}
181 
182 	ethdev_list_clean();
183 	route_ip4_list_clean();
184 	route_ip6_list_clean();
185 	neigh4_list_clean();
186 	neigh6_list_clean();
187 	printf("Bye...\n");
188 }
189 
190 void
191 ethdev_start(void)
192 {
193 	uint16_t portid;
194 	int rc;
195 
196 	RTE_ETH_FOREACH_DEV(portid)
197 	{
198 		if ((enabled_port_mask & (1 << portid)) == 0)
199 			continue;
200 
201 		rc = rte_eth_dev_start(portid);
202 		if (rc < 0)
203 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n", rc, portid);
204 	}
205 }
206 
207 
208 static int
209 ethdev_show(const char *name)
210 {
211 	uint16_t mtu = 0, port_id = 0;
212 	struct rte_eth_dev_info info;
213 	struct rte_eth_stats stats;
214 	struct rte_ether_addr addr;
215 	struct rte_eth_link link;
216 	uint32_t length;
217 	int rc;
218 
219 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
220 	if (rc < 0)
221 		return rc;
222 
223 	rte_eth_dev_info_get(port_id, &info);
224 	rte_eth_stats_get(port_id, &stats);
225 	rte_eth_macaddr_get(port_id, &addr);
226 	rte_eth_link_get(port_id, &link);
227 	rte_eth_dev_get_mtu(port_id, &mtu);
228 
229 	length = strlen(conn->msg_out);
230 	conn->msg_out += length;
231 	snprintf(conn->msg_out, conn->msg_out_len_max,
232 		 "%s: flags=<%s> mtu %u\n"
233 		 "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n"
234 		 "\tport# %u  speed %s\n"
235 		 "\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
236 		 "\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
237 		 "\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
238 		 "\tTX errors %" PRIu64"\n\n",
239 		 name,
240 		 link.link_status ? "UP" : "DOWN",
241 		 mtu,
242 		 RTE_ETHER_ADDR_BYTES(&addr),
243 		 info.nb_rx_queues,
244 		 info.nb_tx_queues,
245 		 port_id,
246 		 rte_eth_link_speed_to_str(link.link_speed),
247 		 stats.ipackets,
248 		 stats.ibytes,
249 		 stats.ierrors,
250 		 stats.imissed,
251 		 stats.rx_nombuf,
252 		 stats.opackets,
253 		 stats.obytes,
254 		 stats.oerrors);
255 
256 	length = strlen(conn->msg_out);
257 	conn->msg_out_len_max -= length;
258 	return 0;
259 }
260 
261 static int
262 ethdev_ip4_addr_add(const char *name, struct ipv4_addr_config *config)
263 {
264 	struct ethdev *eth_hdl;
265 	uint16_t portid = 0;
266 	int rc;
267 
268 	rc = rte_eth_dev_get_port_by_name(name, &portid);
269 	if (rc < 0)
270 		return rc;
271 
272 	eth_hdl = ethdev_port_by_id(portid);
273 
274 	if (eth_hdl) {
275 		eth_hdl->ip4_addr.ip = config->ip;
276 		eth_hdl->ip4_addr.mask = config->mask;
277 		return 0;
278 	}
279 
280 	rc = -EINVAL;
281 	return rc;
282 }
283 
284 static int
285 ethdev_ip6_addr_add(const char *name, struct ipv6_addr_config *config)
286 {
287 	struct ethdev *eth_hdl;
288 	uint16_t portid = 0;
289 	int rc, i;
290 
291 	rc = rte_eth_dev_get_port_by_name(name, &portid);
292 	if (rc < 0)
293 		return rc;
294 
295 	eth_hdl = ethdev_port_by_id(portid);
296 
297 	if (eth_hdl) {
298 		for (i = 0; i < ETHDEV_IPV6_ADDR_LEN; i++) {
299 			eth_hdl->ip6_addr.ip[i] = config->ip[i];
300 			eth_hdl->ip6_addr.mask[i] = config->mask[i];
301 		}
302 		return 0;
303 	}
304 	rc = -EINVAL;
305 	return rc;
306 }
307 
308 static int
309 ethdev_prom_mode_config(const char *name, bool enable)
310 {
311 	struct ethdev *eth_hdl;
312 	uint16_t portid = 0;
313 	int rc;
314 
315 	rc = rte_eth_dev_get_port_by_name(name, &portid);
316 	if (rc < 0)
317 		return rc;
318 
319 	eth_hdl = ethdev_port_by_id(portid);
320 
321 	if (eth_hdl) {
322 		if (enable)
323 			rc = rte_eth_promiscuous_enable(portid);
324 		else
325 			rc = rte_eth_promiscuous_disable(portid);
326 		if (rc < 0)
327 			return rc;
328 
329 		eth_hdl->config.promiscuous = enable;
330 		return 0;
331 	}
332 
333 	rc = -EINVAL;
334 	return rc;
335 }
336 
337 static int
338 ethdev_mtu_config(const char *name, uint32_t mtu)
339 {
340 	struct ethdev *eth_hdl;
341 	uint16_t portid = 0;
342 	int rc;
343 
344 	rc = rte_eth_dev_get_port_by_name(name, &portid);
345 	if (rc < 0)
346 		return rc;
347 
348 	eth_hdl = ethdev_port_by_id(portid);
349 
350 	if (eth_hdl) {
351 		rc = rte_eth_dev_set_mtu(portid, mtu);
352 		if (rc < 0)
353 			return rc;
354 
355 		eth_hdl->config.mtu = mtu;
356 		return 0;
357 	}
358 
359 	rc = -EINVAL;
360 	return rc;
361 }
362 
363 
364 static int
365 ethdev_process(const char *name, struct ethdev_config *params)
366 {
367 	struct rte_eth_dev_info port_info;
368 	struct rte_eth_conf port_conf;
369 	struct ethdev_rss_config *rss;
370 	struct rte_mempool *mempool;
371 	struct ethdev *ethdev_port;
372 	struct rte_ether_addr smac;
373 	uint16_t port_id = 0;
374 	int numa_node, rc;
375 	uint32_t i;
376 
377 	/* Check input params */
378 	if (!name || !name[0] || !params || !params->rx.n_queues || !params->rx.queue_size ||
379 	    !params->tx.n_queues || !params->tx.queue_size)
380 		return -EINVAL;
381 
382 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
383 	if (rc)
384 		return -EINVAL;
385 
386 	if (!ethdev_port_by_id(port_id)) {
387 		ethdev_port = malloc(sizeof(struct ethdev));
388 		if (!ethdev_port)
389 			return -EINVAL;
390 	} else {
391 		return 0;
392 	}
393 
394 	rc = rte_eth_dev_info_get(port_id, &port_info);
395 	if (rc) {
396 		rc = -EINVAL;
397 		goto exit;
398 	}
399 
400 	mempool = rte_mempool_lookup(params->rx.mempool_name);
401 	if (!mempool) {
402 		rc =  -EINVAL;
403 		goto exit;
404 	}
405 
406 	params->rx.mp = mempool;
407 
408 	rss = params->rx.rss;
409 	if (rss) {
410 		if (!port_info.reta_size || port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512) {
411 			rc = -EINVAL;
412 			goto exit;
413 		}
414 
415 		if (!rss->n_queues || rss->n_queues >= ETHDEV_RXQ_RSS_MAX) {
416 			rc = -EINVAL;
417 			goto exit;
418 		}
419 
420 		for (i = 0; i < rss->n_queues; i++)
421 			if (rss->queue_id[i] >= port_info.max_rx_queues) {
422 				rc = -EINVAL;
423 				goto exit;
424 			}
425 	}
426 
427 	/* Port */
428 	memcpy(&port_conf, &port_conf_default, sizeof(struct rte_eth_conf));
429 	if (rss) {
430 		uint64_t rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP;
431 
432 		port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
433 		port_conf.rx_adv_conf.rss_conf.rss_hf = rss_hf & port_info.flow_type_rss_offloads;
434 	}
435 
436 	numa_node = rte_eth_dev_socket_id(port_id);
437 	if (numa_node == SOCKET_ID_ANY)
438 		numa_node = 0;
439 
440 	if (params->mtu)
441 		port_conf.rxmode.mtu = params->mtu;
442 
443 	rc = rte_eth_dev_configure(port_id, params->rx.n_queues, params->tx.n_queues,
444 				       &port_conf);
445 	if (rc < 0) {
446 		rc = -EINVAL;
447 		goto exit;
448 	}
449 
450 	rc = rte_eth_macaddr_get(port_id, &smac);
451 	if (rc < 0) {
452 		rc = -EINVAL;
453 		goto exit;
454 	}
455 
456 	printf("Port_id = %d srcmac = %x:%x:%x:%x:%x:%x\n", port_id,
457 		smac.addr_bytes[0], smac.addr_bytes[1],
458 		smac.addr_bytes[2], smac.addr_bytes[3],
459 		smac.addr_bytes[4], smac.addr_bytes[5]);
460 
461 	/* Port RX */
462 	for (i = 0; i < params->rx.n_queues; i++) {
463 		rc = rte_eth_rx_queue_setup(port_id, i, params->rx.queue_size, numa_node, NULL,
464 			mempool);
465 		if (rc < 0) {
466 			rc = -EINVAL;
467 			goto exit;
468 		}
469 	}
470 
471 	/* Port TX */
472 	for (i = 0; i < params->tx.n_queues; i++) {
473 		rc = rte_eth_tx_queue_setup(port_id, i, params->tx.queue_size, numa_node, NULL);
474 		if (rc < 0) {
475 			rc = -EINVAL;
476 			goto exit;
477 		}
478 	}
479 
480 	memcpy(&ethdev_port->config, params, sizeof(struct ethdev_config));
481 	memcpy(ethdev_port->config.dev_name, name, strlen(name));
482 	ethdev_port->config.port_id = port_id;
483 	enabled_port_mask |= RTE_BIT32(port_id);
484 
485 	TAILQ_INSERT_TAIL(&eth_node, ethdev_port, next);
486 	return 0;
487 exit:
488 	free(ethdev_port);
489 	return rc;
490 
491 }
492 
493 static int
494 ethdev_stats_show(const char *name)
495 {
496 	uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx;
497 	static uint64_t prev_pkts_rx[RTE_MAX_ETHPORTS];
498 	static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS];
499 	static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS];
500 	static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS];
501 	static uint64_t prev_cycles[RTE_MAX_ETHPORTS];
502 	uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx;
503 	uint64_t diff_ns, diff_cycles, curr_cycles;
504 	struct rte_eth_stats stats;
505 	static const char *nic_stats_border = "########################";
506 	uint16_t port_id, len;
507 	int rc;
508 
509 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
510 	if (rc < 0)
511 		return rc;
512 
513 	rc = rte_eth_stats_get(port_id, &stats);
514 	if (rc != 0) {
515 		fprintf(stderr,
516 			"%s: Error: failed to get stats (port %u): %d",
517 			__func__, port_id, rc);
518 		return rc;
519 	}
520 
521 	len = strlen(conn->msg_out);
522 	conn->msg_out += len;
523 	snprintf(conn->msg_out, conn->msg_out_len_max,
524 		 "\n  %s NIC statistics for port %-2d %s\n"
525 		 "  RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes:  ""%-"PRIu64"\n"
526 		 "  RX-errors: %-"PRIu64"\n"
527 		 "  RX-nombuf:  %-10"PRIu64"\n"
528 		 "  TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes:  ""%-"PRIu64"\n",
529 		 nic_stats_border, port_id, nic_stats_border, stats.ipackets, stats.imissed,
530 		 stats.ibytes, stats.ierrors, stats.rx_nombuf, stats.opackets, stats.oerrors,
531 		 stats.obytes);
532 
533 	len = strlen(conn->msg_out) - len;
534 	conn->msg_out_len_max -= len;
535 
536 	diff_ns = 0;
537 	diff_cycles = 0;
538 
539 	curr_cycles = rte_rdtsc();
540 	if (prev_cycles[port_id] != 0)
541 		diff_cycles = curr_cycles - prev_cycles[port_id];
542 
543 	prev_cycles[port_id] = curr_cycles;
544 	diff_ns = diff_cycles > 0 ?
545 		diff_cycles * (1 / (double)rte_get_tsc_hz()) * NS_PER_SEC : 0;
546 
547 	diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ?
548 		(stats.ipackets - prev_pkts_rx[port_id]) : 0;
549 	diff_pkts_tx = (stats.opackets > prev_pkts_tx[port_id]) ?
550 		(stats.opackets - prev_pkts_tx[port_id]) : 0;
551 	prev_pkts_rx[port_id] = stats.ipackets;
552 	prev_pkts_tx[port_id] = stats.opackets;
553 	mpps_rx = diff_ns > 0 ?
554 		(double)diff_pkts_rx / diff_ns * NS_PER_SEC : 0;
555 	mpps_tx = diff_ns > 0 ?
556 		(double)diff_pkts_tx / diff_ns * NS_PER_SEC : 0;
557 
558 	diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ?
559 		(stats.ibytes - prev_bytes_rx[port_id]) : 0;
560 	diff_bytes_tx = (stats.obytes > prev_bytes_tx[port_id]) ?
561 		(stats.obytes - prev_bytes_tx[port_id]) : 0;
562 	prev_bytes_rx[port_id] = stats.ibytes;
563 	prev_bytes_tx[port_id] = stats.obytes;
564 	mbps_rx = diff_ns > 0 ?
565 		(double)diff_bytes_rx / diff_ns * NS_PER_SEC : 0;
566 	mbps_tx = diff_ns > 0 ?
567 		(double)diff_bytes_tx / diff_ns * NS_PER_SEC : 0;
568 
569 	len = strlen(conn->msg_out);
570 	snprintf(conn->msg_out + len, conn->msg_out_len_max,
571 		 "\n  Throughput (since last show)\n"
572 		 "  Rx-pps: %12"PRIu64"          Rx-bps: %12"PRIu64"\n  Tx-pps: %12"
573 		 PRIu64"          Tx-bps: %12"PRIu64"\n"
574 		 "  %s############################%s\n",
575 		 mpps_rx, mbps_rx * 8, mpps_tx, mbps_tx * 8, nic_stats_border, nic_stats_border);
576 	return 0;
577 }
578 
579 static void
580 cli_ethdev_mtu(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
581 {
582 	struct ethdev_mtu_cmd_tokens *res = parsed_result;
583 	int rc = -EINVAL;
584 
585 	rc = ethdev_mtu_config(res->dev, res->size);
586 	if (rc < 0)
587 		printf(MSG_CMD_FAIL, res->cmd);
588 }
589 
590 static void
591 cli_ethdev_prom_mode(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
592 {
593 	struct ethdev_prom_mode_cmd_tokens *res = parsed_result;
594 	bool enable = false;
595 	int rc = -EINVAL;
596 
597 	if (!strcmp(res->enable, "on"))
598 		enable = true;
599 
600 	rc = ethdev_prom_mode_config(res->dev, enable);
601 	if (rc < 0)
602 		printf(MSG_CMD_FAIL, res->cmd);
603 }
604 
605 static void
606 cli_ip4_addr(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
607 {
608 	struct ethdev_ip4_cmd_tokens *res = parsed_result;
609 	struct ipv4_addr_config config;
610 	int rc = -EINVAL;
611 
612 	if (parser_ip4_read(&config.ip, res->ip)) {
613 		printf(MSG_ARG_INVALID, "ip");
614 		return;
615 	}
616 
617 	if (parser_ip4_read(&config.mask, res->mask)) {
618 		printf(MSG_ARG_INVALID, "netmask");
619 		return;
620 	}
621 
622 	rc = ethdev_ip4_addr_add(res->dev, &config);
623 	if (rc < 0)
624 		printf(MSG_CMD_FAIL, res->cmd);
625 }
626 
627 static void
628 cli_ip6_addr(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
629 {
630 	struct ethdev_ip6_cmd_tokens *res = parsed_result;
631 	struct ipv6_addr_config config;
632 	int rc = -EINVAL;
633 
634 	if (parser_ip6_read(config.ip, res->ip)) {
635 		printf(MSG_ARG_INVALID, "ip");
636 		return;
637 	}
638 
639 	if (parser_ip6_read(config.mask, res->mask)) {
640 		printf(MSG_ARG_INVALID, "netmask");
641 		return;
642 	}
643 
644 	rc = ethdev_ip6_addr_add(res->dev, &config);
645 	if (rc < 0)
646 		printf(MSG_CMD_FAIL, res->cmd);
647 }
648 
649 static void
650 cli_ethdev_show(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
651 {
652 	struct ethdev_show_cmd_tokens *res = parsed_result;
653 	int rc = -EINVAL;
654 
655 	rc = ethdev_show(res->dev);
656 	if (rc < 0)
657 		printf(MSG_ARG_INVALID, res->dev);
658 }
659 
660 static void
661 cli_ethdev_stats(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
662 {
663 	struct ethdev_stats_cmd_tokens *res = parsed_result;
664 	int rc = -EINVAL;
665 
666 	rc = ethdev_stats_show(res->dev);
667 	if (rc < 0)
668 		printf(MSG_ARG_INVALID, res->dev);
669 }
670 
671 static void
672 cli_ethdev(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
673 {
674 	struct ethdev_cmd_tokens *res = parsed_result;
675 	struct ethdev_config config;
676 	int rc;
677 
678 	memset(&config, 0, sizeof(struct ethdev_config));
679 	config.rx.n_queues = res->nb_rxq;
680 	config.rx.queue_size = ETHDEV_RX_DESC_DEFAULT;
681 	memcpy(config.rx.mempool_name, res->mempool, strlen(res->mempool));
682 
683 	config.tx.n_queues = res->nb_txq;
684 	config.tx.queue_size = ETHDEV_TX_DESC_DEFAULT;
685 
686 	config.mtu = port_conf_default.rxmode.mtu;
687 
688 	rc = ethdev_process(res->dev, &config);
689 	if (rc < 0)
690 		printf(MSG_CMD_FAIL, res->cmd);
691 }
692 
693 static void
694 cli_ethdev_help(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
695 		__rte_unused void *data)
696 {
697 	size_t len;
698 
699 	len = strlen(conn->msg_out);
700 	conn->msg_out += len;
701 	snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
702 		 "----------------------------- ethdev command help -----------------------------",
703 		 cmd_ethdev_help, cmd_ethdev_ip4_addr_help, cmd_ethdev_ip6_addr_help,
704 		 cmd_ethdev_prom_mode_help, cmd_ethdev_mtu_help, cmd_ethdev_stats_help,
705 		 cmd_ethdev_show_help);
706 
707 	len = strlen(conn->msg_out);
708 	conn->msg_out_len_max -= len;
709 }
710 
711 cmdline_parse_token_string_t ethdev_stats_cmd =
712 	TOKEN_STRING_INITIALIZER(struct ethdev_stats_cmd_tokens, cmd, "ethdev");
713 cmdline_parse_token_string_t ethdev_stats_dev =
714 	TOKEN_STRING_INITIALIZER(struct ethdev_stats_cmd_tokens, dev, NULL);
715 cmdline_parse_token_string_t ethdev_stats_stats =
716 	TOKEN_STRING_INITIALIZER(struct ethdev_stats_cmd_tokens, stats, "stats");
717 
718 cmdline_parse_inst_t ethdev_stats_cmd_ctx = {
719 	.f = cli_ethdev_stats,
720 	.data = NULL,
721 	.help_str = "",
722 	.tokens = {
723 		(void *)&ethdev_stats_cmd,
724 		(void *)&ethdev_stats_dev,
725 		(void *)&ethdev_stats_stats,
726 		NULL,
727 	},
728 };
729 
730 cmdline_parse_token_string_t ethdev_show_cmd =
731 	TOKEN_STRING_INITIALIZER(struct ethdev_show_cmd_tokens, cmd, "ethdev");
732 cmdline_parse_token_string_t ethdev_show_dev =
733 	TOKEN_STRING_INITIALIZER(struct ethdev_show_cmd_tokens, dev, NULL);
734 cmdline_parse_token_string_t ethdev_show_show =
735 	TOKEN_STRING_INITIALIZER(struct ethdev_show_cmd_tokens, show, "show");
736 
737 cmdline_parse_inst_t ethdev_show_cmd_ctx = {
738 	.f = cli_ethdev_show,
739 	.data = NULL,
740 	.help_str = cmd_ethdev_show_help,
741 	.tokens = {
742 		(void *)&ethdev_show_cmd,
743 		(void *)&ethdev_show_dev,
744 		(void *)&ethdev_show_show,
745 		NULL,
746 	},
747 };
748 
749 cmdline_parse_token_string_t ethdev_mtu_cmd =
750 	TOKEN_STRING_INITIALIZER(struct ethdev_mtu_cmd_tokens, cmd, "ethdev");
751 cmdline_parse_token_string_t ethdev_mtu_dev =
752 	TOKEN_STRING_INITIALIZER(struct ethdev_mtu_cmd_tokens, dev, NULL);
753 cmdline_parse_token_string_t ethdev_mtu_mtu =
754 	TOKEN_STRING_INITIALIZER(struct ethdev_mtu_cmd_tokens, mtu, "mtu");
755 cmdline_parse_token_num_t ethdev_mtu_size =
756 	TOKEN_NUM_INITIALIZER(struct ethdev_mtu_cmd_tokens, size, RTE_UINT16);
757 
758 cmdline_parse_inst_t ethdev_mtu_cmd_ctx = {
759 	.f = cli_ethdev_mtu,
760 	.data = NULL,
761 	.help_str = cmd_ethdev_mtu_help,
762 	.tokens = {
763 		(void *)&ethdev_mtu_cmd,
764 		(void *)&ethdev_mtu_dev,
765 		(void *)&ethdev_mtu_mtu,
766 		(void *)&ethdev_mtu_size,
767 		NULL,
768 	},
769 };
770 
771 cmdline_parse_token_string_t ethdev_prom_mode_cmd =
772 	TOKEN_STRING_INITIALIZER(struct ethdev_prom_mode_cmd_tokens, cmd, "ethdev");
773 cmdline_parse_token_string_t ethdev_prom_mode_dev =
774 	TOKEN_STRING_INITIALIZER(struct ethdev_prom_mode_cmd_tokens, dev, NULL);
775 cmdline_parse_token_string_t ethdev_prom_mode_prom =
776 	TOKEN_STRING_INITIALIZER(struct ethdev_prom_mode_cmd_tokens, prom, "promiscuous");
777 cmdline_parse_token_string_t ethdev_prom_mode_enable =
778 	TOKEN_STRING_INITIALIZER(struct ethdev_prom_mode_cmd_tokens, enable, "on#off");
779 
780 cmdline_parse_inst_t ethdev_prom_mode_cmd_ctx = {
781 	.f = cli_ethdev_prom_mode,
782 	.data = NULL,
783 	.help_str = cmd_ethdev_prom_mode_help,
784 	.tokens = {
785 		(void *)&ethdev_prom_mode_cmd,
786 		(void *)&ethdev_prom_mode_dev,
787 		(void *)&ethdev_prom_mode_prom,
788 		(void *)&ethdev_prom_mode_enable,
789 		NULL,
790 	},
791 };
792 
793 cmdline_parse_token_string_t ethdev_ip4_cmd =
794 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, cmd, "ethdev");
795 cmdline_parse_token_string_t ethdev_ip4_dev =
796 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, dev, NULL);
797 cmdline_parse_token_string_t ethdev_ip4_ip4 =
798 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, ip4, "ip4");
799 cmdline_parse_token_string_t ethdev_ip4_addr =
800 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, addr, "addr");
801 cmdline_parse_token_string_t ethdev_ip4_add =
802 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, add, "add");
803 cmdline_parse_token_string_t ethdev_ip4_ip =
804 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, ip, NULL);
805 cmdline_parse_token_string_t ethdev_ip4_netmask =
806 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, netmask, "netmask");
807 cmdline_parse_token_string_t ethdev_ip4_mask =
808 	TOKEN_STRING_INITIALIZER(struct ethdev_ip4_cmd_tokens, mask, NULL);
809 
810 cmdline_parse_inst_t ethdev_ip4_cmd_ctx = {
811 	.f = cli_ip4_addr,
812 	.data = NULL,
813 	.help_str = cmd_ethdev_ip4_addr_help,
814 	.tokens = {
815 		(void *)&ethdev_ip4_cmd,
816 		(void *)&ethdev_ip4_dev,
817 		(void *)&ethdev_ip4_ip4,
818 		(void *)&ethdev_ip4_addr,
819 		(void *)&ethdev_ip4_add,
820 		(void *)&ethdev_ip4_ip,
821 		(void *)&ethdev_ip4_netmask,
822 		(void *)&ethdev_ip4_mask,
823 		NULL,
824 	},
825 };
826 
827 cmdline_parse_token_string_t ethdev_ip6_cmd =
828 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, cmd, "ethdev");
829 cmdline_parse_token_string_t ethdev_ip6_dev =
830 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, dev, NULL);
831 cmdline_parse_token_string_t ethdev_ip6_ip6 =
832 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, ip6, "ip6");
833 cmdline_parse_token_string_t ethdev_ip6_addr =
834 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, addr, "addr");
835 cmdline_parse_token_string_t ethdev_ip6_add =
836 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, add, "add");
837 cmdline_parse_token_string_t ethdev_ip6_ip =
838 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, ip, NULL);
839 cmdline_parse_token_string_t ethdev_ip6_netmask =
840 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, netmask, "netmask");
841 cmdline_parse_token_string_t ethdev_ip6_mask =
842 	TOKEN_STRING_INITIALIZER(struct ethdev_ip6_cmd_tokens, mask, NULL);
843 
844 cmdline_parse_inst_t ethdev_ip6_cmd_ctx = {
845 	.f = cli_ip6_addr,
846 	.data = NULL,
847 	.help_str = cmd_ethdev_ip6_addr_help,
848 	.tokens = {
849 		(void *)&ethdev_ip6_cmd,
850 		(void *)&ethdev_ip6_dev,
851 		(void *)&ethdev_ip6_ip6,
852 		(void *)&ethdev_ip6_addr,
853 		(void *)&ethdev_ip6_add,
854 		(void *)&ethdev_ip6_ip,
855 		(void *)&ethdev_ip6_netmask,
856 		(void *)&ethdev_ip6_mask,
857 		NULL,
858 	},
859 };
860 
861 cmdline_parse_token_string_t ethdev_cmd =
862 	TOKEN_STRING_INITIALIZER(struct ethdev_cmd_tokens, cmd, "ethdev");
863 cmdline_parse_token_string_t ethdev_dev =
864 	TOKEN_STRING_INITIALIZER(struct ethdev_cmd_tokens, dev, NULL);
865 cmdline_parse_token_string_t ethdev_rxq =
866 	TOKEN_STRING_INITIALIZER(struct ethdev_cmd_tokens, rxq, "rxq");
867 cmdline_parse_token_num_t ethdev_nb_rxq =
868 	TOKEN_NUM_INITIALIZER(struct ethdev_cmd_tokens, nb_rxq, RTE_UINT16);
869 cmdline_parse_token_string_t ethdev_txq =
870 	TOKEN_STRING_INITIALIZER(struct ethdev_cmd_tokens, txq, "txq");
871 cmdline_parse_token_num_t ethdev_nb_txq =
872 	TOKEN_NUM_INITIALIZER(struct ethdev_cmd_tokens, nb_txq, RTE_UINT16);
873 cmdline_parse_token_string_t ethdev_mempool =
874 	TOKEN_STRING_INITIALIZER(struct ethdev_cmd_tokens, mempool, NULL);
875 
876 cmdline_parse_inst_t ethdev_cmd_ctx = {
877 	.f = cli_ethdev,
878 	.data = NULL,
879 	.help_str = cmd_ethdev_help,
880 	.tokens = {
881 		(void *)&ethdev_cmd,
882 		(void *)&ethdev_dev,
883 		(void *)&ethdev_rxq,
884 		(void *)&ethdev_nb_rxq,
885 		(void *)&ethdev_txq,
886 		(void *)&ethdev_nb_txq,
887 		(void *)&ethdev_mempool,
888 		NULL,
889 	},
890 };
891 
892 cmdline_parse_token_string_t ethdev_help_cmd =
893 	TOKEN_STRING_INITIALIZER(struct ethdev_help_cmd_tokens, help, "help");
894 cmdline_parse_token_string_t ethdev_help_ethdev =
895 	TOKEN_STRING_INITIALIZER(struct ethdev_help_cmd_tokens, ethdev, "ethdev");
896 
897 cmdline_parse_inst_t ethdev_help_cmd_ctx = {
898 	.f = cli_ethdev_help,
899 	.data = NULL,
900 	.help_str = "",
901 	.tokens = {
902 		(void *)&ethdev_help_cmd,
903 		(void *)&ethdev_help_ethdev,
904 		NULL,
905 	},
906 };
907 
908 static int
909 ethdev_forward_config(char *tx_dev, char *rx_dev)
910 {
911 	uint16_t portid_rx = 0;
912 	uint16_t portid_tx = 0;
913 	struct ethdev *port;
914 	int rc = -EINVAL;
915 
916 	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
917 	if (rc < 0)
918 		return rc;
919 
920 	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
921 	if (rc < 0)
922 		return rc;
923 
924 	port = ethdev_port_by_id(portid_rx);
925 	if (port) {
926 		port->tx_port_id = portid_tx;
927 		rc = 0;
928 	} else {
929 		rc = -EINVAL;
930 	}
931 
932 	return rc;
933 }
934 
935 static void
936 cli_ethdev_forward(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
937 {
938 	struct ethdev_fwd_cmd_tokens *res = parsed_result;
939 	int rc = -EINVAL;
940 
941 	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
942 	if (rc < 0)
943 		printf(MSG_CMD_FAIL, res->cmd);
944 }
945 
946 cmdline_parse_token_string_t ethdev_fwd_cfg =
947 	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, cmd, "ethdev");
948 cmdline_parse_token_string_t ethdev_fwd_cmd =
949 	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, fwd, "forward");
950 cmdline_parse_token_string_t ethdev_tx_device =
951 	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, tx_dev, NULL);
952 cmdline_parse_token_string_t ethdev_rx_device =
953 	TOKEN_STRING_INITIALIZER(struct ethdev_fwd_cmd_tokens, rx_dev, NULL);
954 
955 cmdline_parse_inst_t ethdev_forward_cmd_ctx = {
956 	.f = cli_ethdev_forward,
957 	.data = NULL,
958 	.help_str = cmd_ethdev_forward_help,
959 	.tokens = {
960 	       (void *)&ethdev_fwd_cfg,
961 	       (void *)&ethdev_fwd_cmd,
962 	       (void *)&ethdev_tx_device,
963 	       (void *)&ethdev_rx_device,
964 	       NULL,
965 	},
966 };
967