xref: /dpdk/app/graph/ethdev.c (revision fe02b98cd3925d455731f0201030c587a387eef0)
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(struct rte_ipv6_addr *ip, struct rte_ipv6_addr *mask)
128 {
129 	struct ethdev *port;
130 
131 	TAILQ_FOREACH(port, &eth_node, next) {
132 		uint8_t depth = rte_ipv6_mask_depth(&port->ip6_addr.mask);
133 		if (mask != NULL)
134 			depth = RTE_MAX(depth, rte_ipv6_mask_depth(mask));
135 		if (rte_ipv6_addr_eq_prefix(&port->ip6_addr.ip, ip, depth))
136 			return port->config.port_id;
137 	}
138 
139 	return -EINVAL;
140 }
141 
142 void
143 ethdev_list_clean(void)
144 {
145 	struct ethdev *port;
146 
147 	while (!TAILQ_EMPTY(&eth_node)) {
148 		port = TAILQ_FIRST(&eth_node);
149 		TAILQ_REMOVE(&eth_node, port, next);
150 	}
151 }
152 
153 void
154 ethdev_stop(void)
155 {
156 	uint16_t portid;
157 	int rc;
158 
159 	RTE_ETH_FOREACH_DEV(portid) {
160 		if ((enabled_port_mask & (1 << portid)) == 0)
161 			continue;
162 		printf("Closing port %d...", portid);
163 		rc = rte_eth_dev_stop(portid);
164 		if (rc != 0)
165 			printf("Failed to stop port %u: %s\n",
166 					portid, rte_strerror(-rc));
167 		rte_eth_dev_close(portid);
168 		printf(" Done\n");
169 	}
170 
171 	ethdev_list_clean();
172 	route_ip4_list_clean();
173 	route_ip6_list_clean();
174 	neigh4_list_clean();
175 	neigh6_list_clean();
176 	printf("Bye...\n");
177 }
178 
179 void
180 ethdev_start(void)
181 {
182 	uint16_t portid;
183 	int rc;
184 
185 	RTE_ETH_FOREACH_DEV(portid)
186 	{
187 		if ((enabled_port_mask & (1 << portid)) == 0)
188 			continue;
189 
190 		rc = rte_eth_dev_start(portid);
191 		if (rc < 0)
192 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n", rc, portid);
193 	}
194 }
195 
196 static int
197 ethdev_show(const char *name)
198 {
199 	uint16_t mtu = 0, port_id = 0;
200 	struct rte_eth_dev_info info;
201 	struct rte_eth_stats stats;
202 	struct rte_ether_addr addr;
203 	struct rte_eth_link link;
204 	uint32_t length;
205 	int rc;
206 
207 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
208 	if (rc < 0)
209 		return rc;
210 
211 	rc = rte_eth_dev_info_get(port_id, &info);
212 	if (rc < 0)
213 		return rc;
214 
215 	rc = rte_eth_link_get(port_id, &link);
216 	if (rc < 0)
217 		return rc;
218 
219 	rc = rte_eth_stats_get(port_id, &stats);
220 	if (rc < 0)
221 		return rc;
222 
223 	rc = rte_eth_macaddr_get(port_id, &addr);
224 	if (rc < 0)
225 		return rc;
226 
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;
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 		eth_hdl->ip6_addr.ip = config->ip;
299 		eth_hdl->ip6_addr.mask = config->mask;
300 		return 0;
301 	}
302 	rc = -EINVAL;
303 	return rc;
304 }
305 
306 static int
307 ethdev_prom_mode_config(const char *name, bool enable)
308 {
309 	struct ethdev *eth_hdl;
310 	uint16_t portid = 0;
311 	int rc;
312 
313 	rc = rte_eth_dev_get_port_by_name(name, &portid);
314 	if (rc < 0)
315 		return rc;
316 
317 	eth_hdl = ethdev_port_by_id(portid);
318 
319 	if (eth_hdl) {
320 		if (enable)
321 			rc = rte_eth_promiscuous_enable(portid);
322 		else
323 			rc = rte_eth_promiscuous_disable(portid);
324 		if (rc < 0)
325 			return rc;
326 
327 		eth_hdl->config.promiscuous = enable;
328 		return 0;
329 	}
330 
331 	rc = -EINVAL;
332 	return rc;
333 }
334 
335 static int
336 ethdev_mtu_config(const char *name, uint32_t mtu)
337 {
338 	struct ethdev *eth_hdl;
339 	uint16_t portid = 0;
340 	int rc;
341 
342 	rc = rte_eth_dev_get_port_by_name(name, &portid);
343 	if (rc < 0)
344 		return rc;
345 
346 	eth_hdl = ethdev_port_by_id(portid);
347 
348 	if (eth_hdl) {
349 		rc = rte_eth_dev_set_mtu(portid, mtu);
350 		if (rc < 0)
351 			return rc;
352 
353 		eth_hdl->config.mtu = mtu;
354 		return 0;
355 	}
356 
357 	rc = -EINVAL;
358 	return rc;
359 }
360 
361 static int
362 ethdev_process(const char *name, struct ethdev_config *params)
363 {
364 	struct rte_eth_dev_info port_info;
365 	struct rte_eth_conf port_conf;
366 	struct ethdev_rss_config *rss;
367 	struct rte_mempool *mempool;
368 	struct ethdev *ethdev_port;
369 	struct rte_ether_addr smac;
370 	uint16_t port_id = 0;
371 	int numa_node, rc;
372 	uint32_t i;
373 
374 	/* Check input params */
375 	if (!name || !name[0] || !params || !params->rx.n_queues || !params->rx.queue_size ||
376 	    !params->tx.n_queues || !params->tx.queue_size)
377 		return -EINVAL;
378 
379 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
380 	if (rc)
381 		return -EINVAL;
382 
383 	if (!ethdev_port_by_id(port_id)) {
384 		ethdev_port = malloc(sizeof(struct ethdev));
385 		if (!ethdev_port)
386 			return -EINVAL;
387 	} else {
388 		return 0;
389 	}
390 
391 	rc = rte_eth_dev_info_get(port_id, &port_info);
392 	if (rc) {
393 		rc = -EINVAL;
394 		goto exit;
395 	}
396 
397 	mempool = rte_mempool_lookup(params->rx.mempool_name);
398 	if (!mempool) {
399 		rc =  -EINVAL;
400 		goto exit;
401 	}
402 
403 	params->rx.mp = mempool;
404 
405 	rss = params->rx.rss;
406 	if (rss) {
407 		if (!port_info.reta_size || port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512) {
408 			rc = -EINVAL;
409 			goto exit;
410 		}
411 
412 		if (!rss->n_queues || rss->n_queues >= ETHDEV_RXQ_RSS_MAX) {
413 			rc = -EINVAL;
414 			goto exit;
415 		}
416 
417 		for (i = 0; i < rss->n_queues; i++)
418 			if (rss->queue_id[i] >= port_info.max_rx_queues) {
419 				rc = -EINVAL;
420 				goto exit;
421 			}
422 	}
423 
424 	/* Port */
425 	memcpy(&port_conf, &port_conf_default, sizeof(struct rte_eth_conf));
426 	if (rss) {
427 		uint64_t rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP;
428 
429 		port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
430 		port_conf.rx_adv_conf.rss_conf.rss_hf = rss_hf & port_info.flow_type_rss_offloads;
431 	}
432 
433 	numa_node = rte_eth_dev_socket_id(port_id);
434 	if (numa_node == SOCKET_ID_ANY)
435 		numa_node = 0;
436 
437 	if (params->mtu)
438 		port_conf.rxmode.mtu = params->mtu;
439 
440 	rc = rte_eth_dev_configure(port_id, params->rx.n_queues, params->tx.n_queues,
441 				       &port_conf);
442 	if (rc < 0) {
443 		rc = -EINVAL;
444 		goto exit;
445 	}
446 
447 	rc = rte_eth_macaddr_get(port_id, &smac);
448 	if (rc < 0) {
449 		rc = -EINVAL;
450 		goto exit;
451 	}
452 
453 	printf("Port_id = %d srcmac = %x:%x:%x:%x:%x:%x\n", port_id,
454 		smac.addr_bytes[0], smac.addr_bytes[1],
455 		smac.addr_bytes[2], smac.addr_bytes[3],
456 		smac.addr_bytes[4], smac.addr_bytes[5]);
457 
458 	/* Port RX */
459 	for (i = 0; i < params->rx.n_queues; i++) {
460 		rc = rte_eth_rx_queue_setup(port_id, i, params->rx.queue_size, numa_node, NULL,
461 			mempool);
462 		if (rc < 0) {
463 			rc = -EINVAL;
464 			goto exit;
465 		}
466 	}
467 
468 	/* Port TX */
469 	for (i = 0; i < params->tx.n_queues; i++) {
470 		rc = rte_eth_tx_queue_setup(port_id, i, params->tx.queue_size, numa_node, NULL);
471 		if (rc < 0) {
472 			rc = -EINVAL;
473 			goto exit;
474 		}
475 	}
476 
477 	memcpy(&ethdev_port->config, params, sizeof(struct ethdev_config));
478 	memcpy(ethdev_port->config.dev_name, name, strlen(name));
479 	ethdev_port->config.port_id = port_id;
480 	enabled_port_mask |= RTE_BIT32(port_id);
481 
482 	TAILQ_INSERT_TAIL(&eth_node, ethdev_port, next);
483 	return 0;
484 exit:
485 	free(ethdev_port);
486 	return rc;
487 
488 }
489 
490 static int
491 ethdev_stats_show(const char *name)
492 {
493 	uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx;
494 	static uint64_t prev_pkts_rx[RTE_MAX_ETHPORTS];
495 	static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS];
496 	static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS];
497 	static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS];
498 	static uint64_t prev_cycles[RTE_MAX_ETHPORTS];
499 	uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx;
500 	uint64_t diff_ns, diff_cycles, curr_cycles;
501 	struct rte_eth_stats stats;
502 	static const char *nic_stats_border = "########################";
503 	uint16_t port_id, len;
504 	int rc;
505 
506 	rc = rte_eth_dev_get_port_by_name(name, &port_id);
507 	if (rc < 0)
508 		return rc;
509 
510 	rc = rte_eth_stats_get(port_id, &stats);
511 	if (rc != 0) {
512 		fprintf(stderr,
513 			"%s: Error: failed to get stats (port %u): %d",
514 			__func__, port_id, rc);
515 		return rc;
516 	}
517 
518 	len = strlen(conn->msg_out);
519 	conn->msg_out += len;
520 	snprintf(conn->msg_out, conn->msg_out_len_max,
521 		 "\n  %s NIC statistics for port %-2d %s\n"
522 		 "  RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes:  ""%-"PRIu64"\n"
523 		 "  RX-errors: %-"PRIu64"\n"
524 		 "  RX-nombuf:  %-10"PRIu64"\n"
525 		 "  TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes:  ""%-"PRIu64"\n",
526 		 nic_stats_border, port_id, nic_stats_border, stats.ipackets, stats.imissed,
527 		 stats.ibytes, stats.ierrors, stats.rx_nombuf, stats.opackets, stats.oerrors,
528 		 stats.obytes);
529 
530 	len = strlen(conn->msg_out) - len;
531 	conn->msg_out_len_max -= len;
532 
533 	diff_ns = 0;
534 	diff_cycles = 0;
535 
536 	curr_cycles = rte_rdtsc();
537 	if (prev_cycles[port_id] != 0)
538 		diff_cycles = curr_cycles - prev_cycles[port_id];
539 
540 	prev_cycles[port_id] = curr_cycles;
541 	diff_ns = diff_cycles > 0 ?
542 		diff_cycles * (1 / (double)rte_get_tsc_hz()) * NS_PER_SEC : 0;
543 
544 	diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ?
545 		(stats.ipackets - prev_pkts_rx[port_id]) : 0;
546 	diff_pkts_tx = (stats.opackets > prev_pkts_tx[port_id]) ?
547 		(stats.opackets - prev_pkts_tx[port_id]) : 0;
548 	prev_pkts_rx[port_id] = stats.ipackets;
549 	prev_pkts_tx[port_id] = stats.opackets;
550 	mpps_rx = diff_ns > 0 ?
551 		(double)diff_pkts_rx / diff_ns * NS_PER_SEC : 0;
552 	mpps_tx = diff_ns > 0 ?
553 		(double)diff_pkts_tx / diff_ns * NS_PER_SEC : 0;
554 
555 	diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ?
556 		(stats.ibytes - prev_bytes_rx[port_id]) : 0;
557 	diff_bytes_tx = (stats.obytes > prev_bytes_tx[port_id]) ?
558 		(stats.obytes - prev_bytes_tx[port_id]) : 0;
559 	prev_bytes_rx[port_id] = stats.ibytes;
560 	prev_bytes_tx[port_id] = stats.obytes;
561 	mbps_rx = diff_ns > 0 ?
562 		(double)diff_bytes_rx / diff_ns * NS_PER_SEC : 0;
563 	mbps_tx = diff_ns > 0 ?
564 		(double)diff_bytes_tx / diff_ns * NS_PER_SEC : 0;
565 
566 	len = strlen(conn->msg_out);
567 	snprintf(conn->msg_out + len, conn->msg_out_len_max,
568 		 "\n  Throughput (since last show)\n"
569 		 "  Rx-pps: %12"PRIu64"          Rx-bps: %12"PRIu64"\n  Tx-pps: %12"
570 		 PRIu64"          Tx-bps: %12"PRIu64"\n"
571 		 "  %s############################%s\n",
572 		 mpps_rx, mbps_rx * 8, mpps_tx, mbps_tx * 8, nic_stats_border, nic_stats_border);
573 	return 0;
574 }
575 
576 void
577 cmd_ethdev_dev_mtu_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
578 			  void *data __rte_unused)
579 {
580 	struct cmd_ethdev_dev_mtu_result *res = parsed_result;
581 	int rc = -EINVAL;
582 
583 	rc = ethdev_mtu_config(res->dev, res->size);
584 	if (rc < 0)
585 		printf(MSG_CMD_FAIL, res->ethdev);
586 }
587 
588 void
589 cmd_ethdev_dev_promiscuous_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
590 				  void *data __rte_unused)
591 {
592 	struct cmd_ethdev_dev_promiscuous_result *res = parsed_result;
593 	bool enable = false;
594 	int rc = -EINVAL;
595 
596 	if (!strcmp(res->enable, "on"))
597 		enable = true;
598 
599 	rc = ethdev_prom_mode_config(res->dev, enable);
600 	if (rc < 0)
601 		printf(MSG_CMD_FAIL, res->ethdev);
602 }
603 
604 void
605 cmd_ethdev_dev_ip4_addr_add_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
606 				   void *data __rte_unused)
607 {
608 	struct cmd_ethdev_dev_ip4_addr_add_result *res = parsed_result;
609 	struct ipv4_addr_config config;
610 	int rc = -EINVAL;
611 
612 	config.ip = rte_be_to_cpu_32(res->ip.addr.ipv4.s_addr);
613 	config.mask = rte_be_to_cpu_32(res->mask.addr.ipv4.s_addr);
614 
615 	rc = ethdev_ip4_addr_add(res->dev, &config);
616 	if (rc < 0)
617 		printf(MSG_CMD_FAIL, res->ethdev);
618 }
619 
620 void
621 cmd_ethdev_dev_ip6_addr_add_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
622 				   void *data __rte_unused)
623 {
624 	struct cmd_ethdev_dev_ip6_addr_add_result *res = parsed_result;
625 	struct ipv6_addr_config config = {
626 		.ip = res->ip.addr.ipv6,
627 		.mask = res->mask.addr.ipv6,
628 	};
629 	int rc;
630 
631 	rc = ethdev_ip6_addr_add(res->dev, &config);
632 	if (rc < 0)
633 		printf(MSG_CMD_FAIL, res->ethdev);
634 }
635 
636 void
637 cmd_ethdev_dev_show_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
638 			   void *data __rte_unused)
639 {
640 	struct cmd_ethdev_dev_show_result *res = parsed_result;
641 	int rc = -EINVAL;
642 
643 	rc = ethdev_show(res->dev);
644 	if (rc < 0)
645 		printf(MSG_ARG_INVALID, res->dev);
646 }
647 
648 void
649 cmd_ethdev_dev_stats_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
650 			    void *data __rte_unused)
651 {
652 	struct cmd_ethdev_dev_stats_result *res = parsed_result;
653 	int rc = -EINVAL;
654 
655 	rc = ethdev_stats_show(res->dev);
656 	if (rc < 0)
657 		printf(MSG_ARG_INVALID, res->dev);
658 }
659 
660 void
661 cmd_ethdev_parsed(void *parsed_result, __rte_unused struct cmdline *cl, void *data __rte_unused)
662 {
663 	struct cmd_ethdev_result *res = parsed_result;
664 	struct ethdev_config config;
665 	int rc;
666 
667 	memset(&config, 0, sizeof(struct ethdev_config));
668 	config.rx.n_queues = res->nb_rxq;
669 	config.rx.queue_size = ETHDEV_RX_DESC_DEFAULT;
670 	memcpy(config.rx.mempool_name, res->mempool, strlen(res->mempool));
671 
672 	config.tx.n_queues = res->nb_txq;
673 	config.tx.queue_size = ETHDEV_TX_DESC_DEFAULT;
674 
675 	config.mtu = port_conf_default.rxmode.mtu;
676 
677 	rc = ethdev_process(res->dev, &config);
678 	if (rc < 0)
679 		printf(MSG_CMD_FAIL, res->ethdev);
680 }
681 
682 void
683 cmd_help_ethdev_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl,
684 		       __rte_unused void *data)
685 {
686 	size_t len;
687 
688 	len = strlen(conn->msg_out);
689 	conn->msg_out += len;
690 	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",
691 		 "----------------------------- ethdev command help -----------------------------",
692 		 cmd_ethdev_help, cmd_ethdev_ip4_addr_help, cmd_ethdev_ip6_addr_help,
693 		 cmd_ethdev_forward_help, cmd_ethdev_prom_mode_help, cmd_ethdev_mtu_help,
694 		 cmd_ethdev_stats_help, cmd_ethdev_show_help);
695 
696 	len = strlen(conn->msg_out);
697 	conn->msg_out_len_max -= len;
698 }
699 
700 static int
701 ethdev_forward_config(char *tx_dev, char *rx_dev)
702 {
703 	uint16_t portid_rx = 0;
704 	uint16_t portid_tx = 0;
705 	struct ethdev *port;
706 	int rc = -EINVAL;
707 
708 	rc = rte_eth_dev_get_port_by_name(tx_dev, &portid_tx);
709 	if (rc < 0)
710 		return rc;
711 
712 	rc = rte_eth_dev_get_port_by_name(rx_dev, &portid_rx);
713 	if (rc < 0)
714 		return rc;
715 
716 	port = ethdev_port_by_id(portid_rx);
717 	if (port) {
718 		port->tx_port_id = portid_tx;
719 		rc = 0;
720 	} else {
721 		rc = -EINVAL;
722 	}
723 
724 	return rc;
725 }
726 
727 void
728 cmd_ethdev_forward_parsed(void *parsed_result, __rte_unused struct cmdline *cl,
729 			  void *data __rte_unused)
730 {
731 	struct cmd_ethdev_forward_result *res = parsed_result;
732 	int rc = -EINVAL;
733 
734 	rc = ethdev_forward_config(res->tx_dev, res->rx_dev);
735 	if (rc < 0)
736 		printf(MSG_CMD_FAIL, res->ethdev);
737 }
738