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