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