1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2021 6WIND S.A. 3 * Copyright 2021 Mellanox Technologies, Ltd 4 */ 5 6 #include <stdint.h> 7 #include <string.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #ifndef RTE_EXEC_ENV_WINDOWS 11 #include <sys/socket.h> 12 #include <sys/un.h> 13 #endif 14 15 #include <rte_prefetch.h> 16 #include <rte_common.h> 17 #include <rte_branch_prediction.h> 18 #include <rte_ether.h> 19 #include <rte_alarm.h> 20 #include <rte_pmd_mlx5.h> 21 #include <rte_ethdev.h> 22 23 #include "mlx5_testpmd.h" 24 #include "testpmd.h" 25 26 static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS]; 27 #define SHAPER_DISABLE_DELAY_US 100000 /* 100ms */ 28 29 /** 30 * Disable the host shaper and re-arm available descriptor threshold event. 31 * 32 * @param[in] args 33 * uint32_t integer combining port_id and rxq_id. 34 */ 35 static void 36 mlx5_test_host_shaper_disable(void *args) 37 { 38 uint32_t port_rxq_id = (uint32_t)(uintptr_t)args; 39 uint16_t port_id = port_rxq_id & 0xffff; 40 uint16_t qid = (port_rxq_id >> 16) & 0xffff; 41 struct rte_eth_rxq_info qinfo; 42 43 printf("%s disable shaper\n", __func__); 44 if (rte_eth_rx_queue_info_get(port_id, qid, &qinfo)) { 45 printf("rx_queue_info_get returns error\n"); 46 return; 47 } 48 /* Rearm the available descriptor threshold event. */ 49 if (rte_eth_rx_avail_thresh_set(port_id, qid, qinfo.avail_thresh)) { 50 printf("config avail_thresh returns error\n"); 51 return; 52 } 53 /* Only disable the shaper when avail_thresh_triggered is set. */ 54 if (host_shaper_avail_thresh_triggered[port_id] && 55 rte_pmd_mlx5_host_shaper_config(port_id, 0, 0)) 56 printf("%s disable shaper returns error\n", __func__); 57 } 58 59 void 60 mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id) 61 { 62 struct rte_eth_dev_info dev_info; 63 uint32_t port_rxq_id = port_id | (rxq_id << 16); 64 65 /* Ensure it's MLX5 port. */ 66 if (rte_eth_dev_info_get(port_id, &dev_info) != 0 || 67 (strncmp(dev_info.driver_name, "mlx5", 4) != 0)) 68 return; 69 rte_eal_alarm_set(SHAPER_DISABLE_DELAY_US, 70 mlx5_test_host_shaper_disable, 71 (void *)(uintptr_t)port_rxq_id); 72 printf("%s port_id:%u rxq_id:%u\n", __func__, port_id, rxq_id); 73 } 74 75 /** 76 * Configure host shaper's avail_thresh_triggered and current rate. 77 * 78 * @param[in] avail_thresh_triggered 79 * Disable/enable avail_thresh_triggered. 80 * @param[in] rate 81 * Configure current host shaper rate. 82 * @return 83 * On success, returns 0. 84 * On failure, returns < 0. 85 */ 86 static int 87 mlx5_test_set_port_host_shaper(uint16_t port_id, uint16_t avail_thresh_triggered, uint8_t rate) 88 { 89 struct rte_eth_link link; 90 bool port_id_valid = false; 91 uint16_t pid; 92 int ret; 93 94 RTE_ETH_FOREACH_DEV(pid) 95 if (port_id == pid) { 96 port_id_valid = true; 97 break; 98 } 99 if (!port_id_valid) 100 return -EINVAL; 101 ret = rte_eth_link_get_nowait(port_id, &link); 102 if (ret < 0) 103 return ret; 104 host_shaper_avail_thresh_triggered[port_id] = avail_thresh_triggered ? 1 : 0; 105 if (!avail_thresh_triggered) { 106 ret = rte_pmd_mlx5_host_shaper_config(port_id, 0, 107 RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 108 } else { 109 ret = rte_pmd_mlx5_host_shaper_config(port_id, 1, 110 RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 111 } 112 if (ret) 113 return ret; 114 ret = rte_pmd_mlx5_host_shaper_config(port_id, rate, 0); 115 if (ret) 116 return ret; 117 return 0; 118 } 119 120 #ifndef RTE_EXEC_ENV_WINDOWS 121 static const char* 122 mlx5_test_get_socket_path(char *extend) 123 { 124 if (strstr(extend, "socket=") == extend) { 125 const char *socket_path = strchr(extend, '=') + 1; 126 127 TESTPMD_LOG(DEBUG, "MLX5 socket path is %s\n", socket_path); 128 return socket_path; 129 } 130 131 TESTPMD_LOG(ERR, "Failed to extract a valid socket path from %s\n", 132 extend); 133 return NULL; 134 } 135 136 static int 137 mlx5_test_extend_devargs(char *identifier, char *extend) 138 { 139 struct sockaddr_un un = { 140 .sun_family = AF_UNIX, 141 }; 142 int cmd_fd; 143 int pd_handle; 144 struct iovec iov = { 145 .iov_base = &pd_handle, 146 .iov_len = sizeof(int), 147 }; 148 union { 149 char buf[CMSG_SPACE(sizeof(int))]; 150 struct cmsghdr align; 151 } control; 152 struct msghdr msgh = { 153 .msg_iov = NULL, 154 .msg_iovlen = 0, 155 }; 156 struct cmsghdr *cmsg; 157 const char *path = mlx5_test_get_socket_path(extend + 1); 158 size_t len = 1; 159 int socket_fd; 160 int ret; 161 162 if (path == NULL) { 163 TESTPMD_LOG(ERR, "Invalid devargs extension is specified\n"); 164 return -1; 165 } 166 167 /* Initialize IPC channel. */ 168 socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 169 if (socket_fd < 0) { 170 TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n", 171 strerror(errno)); 172 return -1; 173 } 174 rte_strlcpy(un.sun_path, path, sizeof(un.sun_path)); 175 if (connect(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { 176 TESTPMD_LOG(ERR, "Failed to connect %s: %s\n", un.sun_path, 177 strerror(errno)); 178 close(socket_fd); 179 return -1; 180 } 181 182 /* Send the request message. */ 183 do { 184 ret = sendmsg(socket_fd, &msgh, 0); 185 } while (ret < 0 && errno == EINTR); 186 if (ret < 0) { 187 TESTPMD_LOG(ERR, "Failed to send request to (%s): %s\n", path, 188 strerror(errno)); 189 close(socket_fd); 190 return -1; 191 } 192 193 msgh.msg_iov = &iov; 194 msgh.msg_iovlen = 1; 195 msgh.msg_control = control.buf; 196 msgh.msg_controllen = sizeof(control.buf); 197 do { 198 ret = recvmsg(socket_fd, &msgh, 0); 199 } while (ret < 0); 200 if (ret != sizeof(int) || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) { 201 TESTPMD_LOG(ERR, "truncated msg"); 202 close(socket_fd); 203 return -1; 204 } 205 206 /* Translate the FD. */ 207 cmsg = CMSG_FIRSTHDR(&msgh); 208 if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 209 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 210 TESTPMD_LOG(ERR, "Fail to get FD using SCM_RIGHTS mechanism\n"); 211 close(socket_fd); 212 unlink(un.sun_path); 213 return -1; 214 } 215 memcpy(&cmd_fd, CMSG_DATA(cmsg), sizeof(int)); 216 217 TESTPMD_LOG(DEBUG, "Command FD (%d) and PD handle (%d) " 218 "are successfully imported from remote process\n", 219 cmd_fd, pd_handle); 220 221 /* Cleanup IPC channel. */ 222 close(socket_fd); 223 224 /* Calculate the new length of devargs string. */ 225 len += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); 226 /* Extend the devargs string. */ 227 snprintf(extend, len, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); 228 229 TESTPMD_LOG(DEBUG, "Attach port with extra devargs %s\n", identifier); 230 return 0; 231 } 232 233 static bool 234 is_delimiter_path_spaces(char *extend) 235 { 236 while (*extend != '\0') { 237 if (*extend != ' ') 238 return true; 239 extend++; 240 } 241 return false; 242 } 243 244 /* 245 * Extend devargs list with "cmd_fd" and "pd_handle" coming from external 246 * process. It happens only in this format: 247 * testpmd> mlx5 port attach (identifier) socket=<socket path> 248 * all "(identifier) socket=<socket path>" is in the same string pointed 249 * by the input parameter 'identifier'. 250 * 251 * @param identifier 252 * Identifier of port attach command line. 253 */ 254 static void 255 mlx5_test_attach_port_extend_devargs(char *identifier) 256 { 257 char *extend; 258 259 if (identifier == NULL) { 260 fprintf(stderr, "Invalid parameters are specified\n"); 261 return; 262 } 263 264 extend = strchr(identifier, ' '); 265 if (extend != NULL && is_delimiter_path_spaces(extend) && 266 mlx5_test_extend_devargs(identifier, extend) < 0) { 267 TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n", 268 identifier); 269 return; 270 } 271 272 attach_port(identifier); 273 } 274 #endif 275 276 /* *** SET HOST_SHAPER FOR A PORT *** */ 277 struct cmd_port_host_shaper_result { 278 cmdline_fixed_string_t mlx5; 279 cmdline_fixed_string_t set; 280 cmdline_fixed_string_t port; 281 uint16_t port_num; 282 cmdline_fixed_string_t host_shaper; 283 cmdline_fixed_string_t avail_thresh_triggered; 284 uint16_t fr; 285 cmdline_fixed_string_t rate; 286 uint8_t rate_num; 287 }; 288 289 static void cmd_port_host_shaper_parsed(void *parsed_result, 290 __rte_unused struct cmdline *cl, 291 __rte_unused void *data) 292 { 293 struct cmd_port_host_shaper_result *res = parsed_result; 294 int ret = 0; 295 296 if ((strcmp(res->mlx5, "mlx5") == 0) && 297 (strcmp(res->set, "set") == 0) && 298 (strcmp(res->port, "port") == 0) && 299 (strcmp(res->host_shaper, "host_shaper") == 0) && 300 (strcmp(res->avail_thresh_triggered, "avail_thresh_triggered") == 0) && 301 (strcmp(res->rate, "rate") == 0)) 302 ret = mlx5_test_set_port_host_shaper(res->port_num, res->fr, 303 res->rate_num); 304 if (ret < 0) 305 printf("cmd_port_host_shaper error: (%s)\n", strerror(-ret)); 306 } 307 308 static cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 = 309 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 310 mlx5, "mlx5"); 311 static cmdline_parse_token_string_t cmd_port_host_shaper_set = 312 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 313 set, "set"); 314 static cmdline_parse_token_string_t cmd_port_host_shaper_port = 315 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 316 port, "port"); 317 static cmdline_parse_token_num_t cmd_port_host_shaper_portnum = 318 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 319 port_num, RTE_UINT16); 320 static cmdline_parse_token_string_t cmd_port_host_shaper_host_shaper = 321 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 322 host_shaper, "host_shaper"); 323 static cmdline_parse_token_string_t cmd_port_host_shaper_avail_thresh_triggered = 324 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 325 avail_thresh_triggered, "avail_thresh_triggered"); 326 static cmdline_parse_token_num_t cmd_port_host_shaper_fr = 327 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 328 fr, RTE_UINT16); 329 static cmdline_parse_token_string_t cmd_port_host_shaper_rate = 330 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 331 rate, "rate"); 332 static cmdline_parse_token_num_t cmd_port_host_shaper_rate_num = 333 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 334 rate_num, RTE_UINT8); 335 static cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper = { 336 .f = cmd_port_host_shaper_parsed, 337 .data = (void *)0, 338 .help_str = "mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> " 339 "rate <rate_num>: Set HOST_SHAPER avail_thresh_triggered and rate with port_id", 340 .tokens = { 341 (void *)&cmd_port_host_shaper_mlx5, 342 (void *)&cmd_port_host_shaper_set, 343 (void *)&cmd_port_host_shaper_port, 344 (void *)&cmd_port_host_shaper_portnum, 345 (void *)&cmd_port_host_shaper_host_shaper, 346 (void *)&cmd_port_host_shaper_avail_thresh_triggered, 347 (void *)&cmd_port_host_shaper_fr, 348 (void *)&cmd_port_host_shaper_rate, 349 (void *)&cmd_port_host_shaper_rate_num, 350 NULL, 351 } 352 }; 353 354 #ifndef RTE_EXEC_ENV_WINDOWS 355 /* *** attach a specified port *** */ 356 struct mlx5_cmd_operate_attach_port_result { 357 cmdline_fixed_string_t mlx5; 358 cmdline_fixed_string_t port; 359 cmdline_fixed_string_t keyword; 360 cmdline_multi_string_t identifier; 361 }; 362 363 static void mlx5_cmd_operate_attach_port_parsed(void *parsed_result, 364 __rte_unused struct cmdline *cl, 365 __rte_unused void *data) 366 { 367 struct mlx5_cmd_operate_attach_port_result *res = parsed_result; 368 369 if (!strcmp(res->keyword, "attach")) 370 mlx5_test_attach_port_extend_devargs(res->identifier); 371 else 372 fprintf(stderr, "Unknown parameter\n"); 373 } 374 375 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_mlx5 = 376 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 377 mlx5, "mlx5"); 378 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_port = 379 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 380 port, "port"); 381 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_keyword = 382 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 383 keyword, "attach"); 384 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_identifier = 385 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 386 identifier, TOKEN_STRING_MULTI); 387 388 static cmdline_parse_inst_t mlx5_cmd_operate_attach_port = { 389 .f = mlx5_cmd_operate_attach_port_parsed, 390 .data = NULL, 391 .help_str = "mlx5 port attach <identifier> socket=<path>: " 392 "(identifier: pci address or virtual dev name" 393 ", path (optional): socket path to get cmd FD and PD handle)", 394 .tokens = { 395 (void *)&mlx5_cmd_operate_attach_port_mlx5, 396 (void *)&mlx5_cmd_operate_attach_port_port, 397 (void *)&mlx5_cmd_operate_attach_port_keyword, 398 (void *)&mlx5_cmd_operate_attach_port_identifier, 399 NULL, 400 }, 401 }; 402 #endif 403 404 /* Map HW queue index to rte queue index. */ 405 struct mlx5_cmd_map_ext_rxq { 406 cmdline_fixed_string_t mlx5; 407 cmdline_fixed_string_t port; 408 portid_t port_id; 409 cmdline_fixed_string_t ext_rxq; 410 cmdline_fixed_string_t map; 411 uint16_t sw_queue_id; 412 uint32_t hw_queue_id; 413 }; 414 415 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_mlx5 = 416 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, mlx5, "mlx5"); 417 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_port = 418 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port, "port"); 419 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_port_id = 420 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port_id, RTE_UINT16); 421 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_ext_rxq = 422 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, ext_rxq, 423 "ext_rxq"); 424 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_map = 425 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, map, "map"); 426 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_sw_queue_id = 427 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, sw_queue_id, 428 RTE_UINT16); 429 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_hw_queue_id = 430 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, hw_queue_id, 431 RTE_UINT32); 432 433 static void 434 mlx5_cmd_map_ext_rxq_parsed(void *parsed_result, 435 __rte_unused struct cmdline *cl, 436 __rte_unused void *data) 437 { 438 struct mlx5_cmd_map_ext_rxq *res = parsed_result; 439 int ret; 440 441 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 442 return; 443 ret = rte_pmd_mlx5_external_rx_queue_id_map(res->port_id, 444 res->sw_queue_id, 445 res->hw_queue_id); 446 switch (ret) { 447 case 0: 448 break; 449 case -EINVAL: 450 fprintf(stderr, "invalid ethdev index (%u), out of range\n", 451 res->sw_queue_id); 452 break; 453 case -ENODEV: 454 fprintf(stderr, "invalid port_id %u\n", res->port_id); 455 break; 456 case -ENOTSUP: 457 fprintf(stderr, "function not implemented or supported\n"); 458 break; 459 case -EEXIST: 460 fprintf(stderr, "mapping with index %u already exists\n", 461 res->sw_queue_id); 462 break; 463 default: 464 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 465 } 466 } 467 468 cmdline_parse_inst_t mlx5_cmd_map_ext_rxq = { 469 .f = mlx5_cmd_map_ext_rxq_parsed, 470 .data = NULL, 471 .help_str = "mlx5 port <port_id> ext_rxq map <sw_queue_id> <hw_queue_id>", 472 .tokens = { 473 (void *)&mlx5_cmd_map_ext_rxq_mlx5, 474 (void *)&mlx5_cmd_map_ext_rxq_port, 475 (void *)&mlx5_cmd_map_ext_rxq_port_id, 476 (void *)&mlx5_cmd_map_ext_rxq_ext_rxq, 477 (void *)&mlx5_cmd_map_ext_rxq_map, 478 (void *)&mlx5_cmd_map_ext_rxq_sw_queue_id, 479 (void *)&mlx5_cmd_map_ext_rxq_hw_queue_id, 480 NULL, 481 } 482 }; 483 484 /* Unmap HW queue index to rte queue index. */ 485 struct mlx5_cmd_unmap_ext_rxq { 486 cmdline_fixed_string_t mlx5; 487 cmdline_fixed_string_t port; 488 portid_t port_id; 489 cmdline_fixed_string_t ext_rxq; 490 cmdline_fixed_string_t unmap; 491 uint16_t queue_id; 492 }; 493 494 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_mlx5 = 495 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, mlx5, "mlx5"); 496 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_port = 497 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port, "port"); 498 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_port_id = 499 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port_id, 500 RTE_UINT16); 501 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_ext_rxq = 502 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, ext_rxq, 503 "ext_rxq"); 504 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_unmap = 505 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, unmap, "unmap"); 506 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_queue_id = 507 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, queue_id, 508 RTE_UINT16); 509 510 static void 511 mlx5_cmd_unmap_ext_rxq_parsed(void *parsed_result, 512 __rte_unused struct cmdline *cl, 513 __rte_unused void *data) 514 { 515 struct mlx5_cmd_unmap_ext_rxq *res = parsed_result; 516 int ret; 517 518 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 519 return; 520 ret = rte_pmd_mlx5_external_rx_queue_id_unmap(res->port_id, 521 res->queue_id); 522 switch (ret) { 523 case 0: 524 break; 525 case -EINVAL: 526 fprintf(stderr, "invalid rte_flow index (%u), " 527 "out of range, doesn't exist or still referenced\n", 528 res->queue_id); 529 break; 530 case -ENODEV: 531 fprintf(stderr, "invalid port_id %u\n", res->port_id); 532 break; 533 case -ENOTSUP: 534 fprintf(stderr, "function not implemented or supported\n"); 535 break; 536 default: 537 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 538 } 539 } 540 541 cmdline_parse_inst_t mlx5_cmd_unmap_ext_rxq = { 542 .f = mlx5_cmd_unmap_ext_rxq_parsed, 543 .data = NULL, 544 .help_str = "mlx5 port <port_id> ext_rxq unmap <queue_id>", 545 .tokens = { 546 (void *)&mlx5_cmd_unmap_ext_rxq_mlx5, 547 (void *)&mlx5_cmd_unmap_ext_rxq_port, 548 (void *)&mlx5_cmd_unmap_ext_rxq_port_id, 549 (void *)&mlx5_cmd_unmap_ext_rxq_ext_rxq, 550 (void *)&mlx5_cmd_unmap_ext_rxq_unmap, 551 (void *)&mlx5_cmd_unmap_ext_rxq_queue_id, 552 NULL, 553 } 554 }; 555 556 static struct testpmd_driver_commands mlx5_driver_cmds = { 557 .commands = { 558 { 559 .ctx = &mlx5_test_cmd_port_host_shaper, 560 .help = "mlx5 set port (port_id) host_shaper avail_thresh_triggered (on|off)" 561 "rate (rate_num):\n" 562 " Set HOST_SHAPER avail_thresh_triggered and rate with port_id\n\n", 563 }, 564 #ifndef RTE_EXEC_ENV_WINDOWS 565 { 566 .ctx = &mlx5_cmd_operate_attach_port, 567 .help = "mlx5 port attach (ident) socket=(path)\n" 568 " Attach physical or virtual dev by pci address or virtual device name " 569 "and add \"cmd_fd\" and \"pd_handle\" devargs before attaching\n\n", 570 }, 571 #endif 572 { 573 .ctx = &mlx5_cmd_map_ext_rxq, 574 .help = "mlx5 port (port_id) ext_rxq map (sw_queue_id) (hw_queue_id)\n" 575 " Map HW queue index (32-bit) to ethdev" 576 " queue index (16-bit) for external RxQ\n\n", 577 }, 578 { 579 .ctx = &mlx5_cmd_unmap_ext_rxq, 580 .help = "mlx5 port (port_id) ext_rxq unmap (sw_queue_id)\n" 581 " Unmap external Rx queue ethdev index mapping\n\n", 582 }, 583 { 584 .ctx = NULL, 585 }, 586 } 587 }; 588 TESTPMD_ADD_DRIVER_COMMANDS(mlx5_driver_cmds); 589