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(uint8_t *ip, uint8_t *mask) 128 { 129 int portid = -EINVAL; 130 struct ethdev *port; 131 int j; 132 133 TAILQ_FOREACH(port, ð_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(ð_node)) { 159 port = TAILQ_FIRST(ð_node); 160 TAILQ_REMOVE(ð_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(ðdev_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(ð_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