xref: /dpdk/app/graph/ethdev.c (revision 7917b0d38e92e8b9ec5a870415b791420e10f11a)
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 static int
208 ethdev_show(const char *name)
209 {
210 	uint16_t mtu = 0, port_id = 0;
211 	struct rte_eth_dev_info info;
212 	struct rte_eth_stats stats;
213 	struct rte_ether_addr addr;
214 	struct rte_eth_link link;
215 	uint32_t length;
216 	int rc;
217 
218 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
219 	if (rc < 0)
220 		return rc;
221 
222 	rte_eth_dev_info_get(port_id, &info);
223 	rte_eth_stats_get(port_id, &stats);
224 	rte_eth_macaddr_get(port_id, &addr);
225 	rte_eth_link_get(port_id, &link);
226 	rte_eth_dev_get_mtu(port_id, &mtu);
227 
228 	length = strlen(conn->msg_out);
229 	conn->msg_out += length;
230 	snprintf(conn->msg_out, conn->msg_out_len_max,
231 		 "%s: flags=<%s> mtu %u\n"
232 		 "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n"
233 		 "\tport# %u  speed %s\n"
234 		 "\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
235 		 "\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
236 		 "\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
237 		 "\tTX errors %" PRIu64"\n\n",
238 		 name,
239 		 link.link_status ? "UP" : "DOWN",
240 		 mtu,
241 		 RTE_ETHER_ADDR_BYTES(&addr),
242 		 info.nb_rx_queues,
243 		 info.nb_tx_queues,
244 		 port_id,
245 		 rte_eth_link_speed_to_str(link.link_speed),
246 		 stats.ipackets,
247 		 stats.ibytes,
248 		 stats.ierrors,
249 		 stats.imissed,
250 		 stats.rx_nombuf,
251 		 stats.opackets,
252 		 stats.obytes,
253 		 stats.oerrors);
254 
255 	length = strlen(conn->msg_out);
256 	conn->msg_out_len_max -= length;
257 	return 0;
258 }
259 
260 static int
261 ethdev_ip4_addr_add(const char *name, struct ipv4_addr_config *config)
262 {
263 	struct ethdev *eth_hdl;
264 	uint16_t portid = 0;
265 	int rc;
266 
267 	rc = rte_eth_dev_get_port_by_name(name, &portid);
268 	if (rc < 0)
269 		return rc;
270 
271 	eth_hdl = ethdev_port_by_id(portid);
272 
273 	if (eth_hdl) {
274 		eth_hdl->ip4_addr.ip = config->ip;
275 		eth_hdl->ip4_addr.mask = config->mask;
276 		return 0;
277 	}
278 
279 	rc = -EINVAL;
280 	return rc;
281 }
282 
283 static int
284 ethdev_ip6_addr_add(const char *name, struct ipv6_addr_config *config)
285 {
286 	struct ethdev *eth_hdl;
287 	uint16_t portid = 0;
288 	int rc, i;
289 
290 	rc = rte_eth_dev_get_port_by_name(name, &portid);
291 	if (rc < 0)
292 		return rc;
293 
294 	eth_hdl = ethdev_port_by_id(portid);
295 
296 	if (eth_hdl) {
297 		for (i = 0; i < ETHDEV_IPV6_ADDR_LEN; i++) {
298 			eth_hdl->ip6_addr.ip[i] = config->ip[i];
299 			eth_hdl->ip6_addr.mask[i] = config->mask[i];
300 		}
301 		return 0;
302 	}
303 	rc = -EINVAL;
304 	return rc;
305 }
306 
307 static int
308 ethdev_prom_mode_config(const char *name, bool enable)
309 {
310 	struct ethdev *eth_hdl;
311 	uint16_t portid = 0;
312 	int rc;
313 
314 	rc = rte_eth_dev_get_port_by_name(name, &portid);
315 	if (rc < 0)
316 		return rc;
317 
318 	eth_hdl = ethdev_port_by_id(portid);
319 
320 	if (eth_hdl) {
321 		if (enable)
322 			rc = rte_eth_promiscuous_enable(portid);
323 		else
324 			rc = rte_eth_promiscuous_disable(portid);
325 		if (rc < 0)
326 			return rc;
327 
328 		eth_hdl->config.promiscuous = enable;
329 		return 0;
330 	}
331 
332 	rc = -EINVAL;
333 	return rc;
334 }
335 
336 static int
337 ethdev_mtu_config(const char *name, uint32_t mtu)
338 {
339 	struct ethdev *eth_hdl;
340 	uint16_t portid = 0;
341 	int rc;
342 
343 	rc = rte_eth_dev_get_port_by_name(name, &portid);
344 	if (rc < 0)
345 		return rc;
346 
347 	eth_hdl = ethdev_port_by_id(portid);
348 
349 	if (eth_hdl) {
350 		rc = rte_eth_dev_set_mtu(portid, mtu);
351 		if (rc < 0)
352 			return rc;
353 
354 		eth_hdl->config.mtu = mtu;
355 		return 0;
356 	}
357 
358 	rc = -EINVAL;
359 	return rc;
360 }
361 
362 static int
363 ethdev_process(const char *name, struct ethdev_config *params)
364 {
365 	struct rte_eth_dev_info port_info;
366 	struct rte_eth_conf port_conf;
367 	struct ethdev_rss_config *rss;
368 	struct rte_mempool *mempool;
369 	struct ethdev *ethdev_port;
370 	struct rte_ether_addr smac;
371 	uint16_t port_id = 0;
372 	int numa_node, rc;
373 	uint32_t i;
374 
375 	/* Check input params */
376 	if (!name || !name[0] || !params || !params->rx.n_queues || !params->rx.queue_size ||
377 	    !params->tx.n_queues || !params->tx.queue_size)
378 		return -EINVAL;
379 
380 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
381 	if (rc)
382 		return -EINVAL;
383 
384 	if (!ethdev_port_by_id(port_id)) {
385 		ethdev_port = malloc(sizeof(struct ethdev));
386 		if (!ethdev_port)
387 			return -EINVAL;
388 	} else {
389 		return 0;
390 	}
391 
392 	rc = rte_eth_dev_info_get(port_id, &port_info);
393 	if (rc) {
394 		rc = -EINVAL;
395 		goto exit;
396 	}
397 
398 	mempool = rte_mempool_lookup(params->rx.mempool_name);
399 	if (!mempool) {
400 		rc =  -EINVAL;
401 		goto exit;
402 	}
403 
404 	params->rx.mp = mempool;
405 
406 	rss = params->rx.rss;
407 	if (rss) {
408 		if (!port_info.reta_size || port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512) {
409 			rc = -EINVAL;
410 			goto exit;
411 		}
412 
413 		if (!rss->n_queues || rss->n_queues >= ETHDEV_RXQ_RSS_MAX) {
414 			rc = -EINVAL;
415 			goto exit;
416 		}
417 
418 		for (i = 0; i < rss->n_queues; i++)
419 			if (rss->queue_id[i] >= port_info.max_rx_queues) {
420 				rc = -EINVAL;
421 				goto exit;
422 			}
423 	}
424 
425 	/* Port */
426 	memcpy(&port_conf, &port_conf_default, sizeof(struct rte_eth_conf));
427 	if (rss) {
428 		uint64_t rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP;
429 
430 		port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
431 		port_conf.rx_adv_conf.rss_conf.rss_hf = rss_hf & port_info.flow_type_rss_offloads;
432 	}
433 
434 	numa_node = rte_eth_dev_socket_id(port_id);
435 	if (numa_node == SOCKET_ID_ANY)
436 		numa_node = 0;
437 
438 	if (params->mtu)
439 		port_conf.rxmode.mtu = params->mtu;
440 
441 	rc = rte_eth_dev_configure(port_id, params->rx.n_queues, params->tx.n_queues,
442 				       &port_conf);
443 	if (rc < 0) {
444 		rc = -EINVAL;
445 		goto exit;
446 	}
447 
448 	rc = rte_eth_macaddr_get(port_id, &smac);
449 	if (rc < 0) {
450 		rc = -EINVAL;
451 		goto exit;
452 	}
453 
454 	printf("Port_id = %d srcmac = %x:%x:%x:%x:%x:%x\n", port_id,
455 		smac.addr_bytes[0], smac.addr_bytes[1],
456 		smac.addr_bytes[2], smac.addr_bytes[3],
457 		smac.addr_bytes[4], smac.addr_bytes[5]);
458 
459 	/* Port RX */
460 	for (i = 0; i < params->rx.n_queues; i++) {
461 		rc = rte_eth_rx_queue_setup(port_id, i, params->rx.queue_size, numa_node, NULL,
462 			mempool);
463 		if (rc < 0) {
464 			rc = -EINVAL;
465 			goto exit;
466 		}
467 	}
468 
469 	/* Port TX */
470 	for (i = 0; i < params->tx.n_queues; i++) {
471 		rc = rte_eth_tx_queue_setup(port_id, i, params->tx.queue_size, numa_node, NULL);
472 		if (rc < 0) {
473 			rc = -EINVAL;
474 			goto exit;
475 		}
476 	}
477 
478 	memcpy(&ethdev_port->config, params, sizeof(struct ethdev_config));
479 	memcpy(ethdev_port->config.dev_name, name, strlen(name));
480 	ethdev_port->config.port_id = port_id;
481 	enabled_port_mask |= RTE_BIT32(port_id);
482 
483 	TAILQ_INSERT_TAIL(&eth_node, ethdev_port, next);
484 	return 0;
485 exit:
486 	free(ethdev_port);
487 	return rc;
488 
489 }
490 
491 static int
492 ethdev_stats_show(const char *name)
493 {
494 	uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx;
495 	static uint64_t prev_pkts_rx[RTE_MAX_ETHPORTS];
496 	static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS];
497 	static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS];
498 	static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS];
499 	static uint64_t prev_cycles[RTE_MAX_ETHPORTS];
500 	uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx;
501 	uint64_t diff_ns, diff_cycles, curr_cycles;
502 	struct rte_eth_stats stats;
503 	static const char *nic_stats_border = "########################";
504 	uint16_t port_id, len;
505 	int rc;
506 
507 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
508 	if (rc < 0)
509 		return rc;
510 
511 	rc = rte_eth_stats_get(port_id, &stats);
512 	if (rc != 0) {
513 		fprintf(stderr,
514 			"%s: Error: failed to get stats (port %u): %d",
515 			__func__, port_id, rc);
516 		return rc;
517 	}
518 
519 	len = strlen(conn->msg_out);
520 	conn->msg_out += len;
521 	snprintf(conn->msg_out, conn->msg_out_len_max,
522 		 "\n  %s NIC statistics for port %-2d %s\n"
523 		 "  RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes:  ""%-"PRIu64"\n"
524 		 "  RX-errors: %-"PRIu64"\n"
525 		 "  RX-nombuf:  %-10"PRIu64"\n"
526 		 "  TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes:  ""%-"PRIu64"\n",
527 		 nic_stats_border, port_id, nic_stats_border, stats.ipackets, stats.imissed,
528 		 stats.ibytes, stats.ierrors, stats.rx_nombuf, stats.opackets, stats.oerrors,
529 		 stats.obytes);
530 
531 	len = strlen(conn->msg_out) - len;
532 	conn->msg_out_len_max -= len;
533 
534 	diff_ns = 0;
535 	diff_cycles = 0;
536 
537 	curr_cycles = rte_rdtsc();
538 	if (prev_cycles[port_id] != 0)
539 		diff_cycles = curr_cycles - prev_cycles[port_id];
540 
541 	prev_cycles[port_id] = curr_cycles;
542 	diff_ns = diff_cycles > 0 ?
543 		diff_cycles * (1 / (double)rte_get_tsc_hz()) * NS_PER_SEC : 0;
544 
545 	diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ?
546 		(stats.ipackets - prev_pkts_rx[port_id]) : 0;
547 	diff_pkts_tx = (stats.opackets > prev_pkts_tx[port_id]) ?
548 		(stats.opackets - prev_pkts_tx[port_id]) : 0;
549 	prev_pkts_rx[port_id] = stats.ipackets;
550 	prev_pkts_tx[port_id] = stats.opackets;
551 	mpps_rx = diff_ns > 0 ?
552 		(double)diff_pkts_rx / diff_ns * NS_PER_SEC : 0;
553 	mpps_tx = diff_ns > 0 ?
554 		(double)diff_pkts_tx / diff_ns * NS_PER_SEC : 0;
555 
556 	diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ?
557 		(stats.ibytes - prev_bytes_rx[port_id]) : 0;
558 	diff_bytes_tx = (stats.obytes > prev_bytes_tx[port_id]) ?
559 		(stats.obytes - prev_bytes_tx[port_id]) : 0;
560 	prev_bytes_rx[port_id] = stats.ibytes;
561 	prev_bytes_tx[port_id] = stats.obytes;
562 	mbps_rx = diff_ns > 0 ?
563 		(double)diff_bytes_rx / diff_ns * NS_PER_SEC : 0;
564 	mbps_tx = diff_ns > 0 ?
565 		(double)diff_bytes_tx / diff_ns * NS_PER_SEC : 0;
566 
567 	len = strlen(conn->msg_out);
568 	snprintf(conn->msg_out + len, conn->msg_out_len_max,
569 		 "\n  Throughput (since last show)\n"
570 		 "  Rx-pps: %12"PRIu64"          Rx-bps: %12"PRIu64"\n  Tx-pps: %12"
571 		 PRIu64"          Tx-bps: %12"PRIu64"\n"
572 		 "  %s############################%s\n",
573 		 mpps_rx, mbps_rx * 8, mpps_tx, mbps_tx * 8, nic_stats_border, nic_stats_border);
574 	return 0;
575 }
576 
577 void
578 cmd_ethdev_dev_mtu_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
579 			  void *data __rte_unused)
580 {
581 	struct cmd_ethdev_dev_mtu_result *res = parsed_result;
582 	int rc = -EINVAL;
583 
584 	rc = ethdev_mtu_config(res->dev, res->size);
585 	if (rc < 0)
586 		printf(MSG_CMD_FAIL, res->ethdev);
587 }
588 
589 void
590 cmd_ethdev_dev_promiscuous_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
591 				  void *data __rte_unused)
592 {
593 	struct cmd_ethdev_dev_promiscuous_result *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->ethdev);
603 }
604 
605 void
606 cmd_ethdev_dev_ip4_addr_add_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
607 				   void *data __rte_unused)
608 {
609 	struct cmd_ethdev_dev_ip4_addr_add_result *res = parsed_result;
610 	struct ipv4_addr_config config;
611 	int rc = -EINVAL;
612 
613 	config.ip = rte_be_to_cpu_32(res->ip.addr.ipv4.s_addr);
614 	config.mask = rte_be_to_cpu_32(res->mask.addr.ipv4.s_addr);
615 
616 	rc = ethdev_ip4_addr_add(res->dev, &config);
617 	if (rc < 0)
618 		printf(MSG_CMD_FAIL, res->ethdev);
619 }
620 
621 void
622 cmd_ethdev_dev_ip6_addr_add_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
623 				   void *data __rte_unused)
624 {
625 	struct cmd_ethdev_dev_ip6_addr_add_result *res = parsed_result;
626 	struct ipv6_addr_config config;
627 	int rc = -EINVAL, i;
628 
629 	for (i = 0; i < ETHDEV_IPV6_ADDR_LEN; i++)
630 		config.ip[i] = res->ip.addr.ipv6.s6_addr[i];
631 
632 	for (i = 0; i < ETHDEV_IPV6_ADDR_LEN; i++)
633 		config.mask[i] = res->mask.addr.ipv6.s6_addr[i];
634 
635 	rc = ethdev_ip6_addr_add(res->dev, &config);
636 	if (rc < 0)
637 		printf(MSG_CMD_FAIL, res->ethdev);
638 }
639 
640 void
641 cmd_ethdev_dev_show_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
642 			   void *data __rte_unused)
643 {
644 	struct cmd_ethdev_dev_show_result *res = parsed_result;
645 	int rc = -EINVAL;
646 
647 	rc = ethdev_show(res->dev);
648 	if (rc < 0)
649 		printf(MSG_ARG_INVALID, res->dev);
650 }
651 
652 void
653 cmd_ethdev_dev_stats_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
654 			    void *data __rte_unused)
655 {
656 	struct cmd_ethdev_dev_stats_result *res = parsed_result;
657 	int rc = -EINVAL;
658 
659 	rc = ethdev_stats_show(res->dev);
660 	if (rc < 0)
661 		printf(MSG_ARG_INVALID, res->dev);
662 }
663 
664 void
665 cmd_ethdev_parsed(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
666 {
667 	struct cmd_ethdev_result *res = parsed_result;
668 	struct ethdev_config config;
669 	int rc;
670 
671 	memset(&config, 0, sizeof(struct ethdev_config));
672 	config.rx.n_queues = res->nb_rxq;
673 	config.rx.queue_size = ETHDEV_RX_DESC_DEFAULT;
674 	memcpy(config.rx.mempool_name, res->mempool, strlen(res->mempool));
675 
676 	config.tx.n_queues = res->nb_txq;
677 	config.tx.queue_size = ETHDEV_TX_DESC_DEFAULT;
678 
679 	config.mtu = port_conf_default.rxmode.mtu;
680 
681 	rc = ethdev_process(res->dev, &config);
682 	if (rc < 0)
683 		printf(MSG_CMD_FAIL, res->ethdev);
684 }
685 
686 void
687 cmd_help_ethdev_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
688 		       __rte_unused void *data)
689 {
690 	size_t len;
691 
692 	len = strlen(conn->msg_out);
693 	conn->msg_out += len;
694 	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%s\n",
695 		 "----------------------------- ethdev command help -----------------------------",
696 		 cmd_ethdev_help, cmd_ethdev_ip4_addr_help, cmd_ethdev_ip6_addr_help,
697 		 cmd_ethdev_forward_help, cmd_ethdev_prom_mode_help, cmd_ethdev_mtu_help,
698 		 cmd_ethdev_stats_help, cmd_ethdev_show_help);
699 
700 	len = strlen(conn->msg_out);
701 	conn->msg_out_len_max -= len;
702 }
703 
704 static int
705 ethdev_forward_config(char *tx_dev, char *rx_dev)
706 {
707 	uint16_t portid_rx = 0;
708 	uint16_t portid_tx = 0;
709 	struct ethdev *port;
710 	int rc = -EINVAL;
711 
712 	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
713 	if (rc < 0)
714 		return rc;
715 
716 	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
717 	if (rc < 0)
718 		return rc;
719 
720 	port = ethdev_port_by_id(portid_rx);
721 	if (port) {
722 		port->tx_port_id = portid_tx;
723 		rc = 0;
724 	} else {
725 		rc = -EINVAL;
726 	}
727 
728 	return rc;
729 }
730 
731 void
732 cmd_ethdev_forward_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
733 			  void *data __rte_unused)
734 {
735 	struct cmd_ethdev_forward_result *res = parsed_result;
736 	int rc = -EINVAL;
737 
738 	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
739 	if (rc < 0)
740 		printf(MSG_CMD_FAIL, res->ethdev);
741 }
742