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 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(ðdev_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(ð_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