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, ð_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, ð_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, ð_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(ð_node)) { 148 port = TAILQ_FIRST(ð_node); 149 TAILQ_REMOVE(ð_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(ðdev_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(ð_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