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 #define SHAPER_DISABLE_DELAY_US 100000 /* 100ms */ 27 #define MAX_GENEVE_OPTIONS_RESOURCES 7 28 #define PARSE_DELIMITER " \f\n\r\t\v" 29 #define SPACE_DELIMITER (" ") 30 31 static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS]; 32 33 struct mlx5_port { 34 void *geneve_tlv_parser_handle; 35 }; 36 37 static struct mlx5_port private_port[RTE_MAX_ETHPORTS] = {{0}}; 38 39 struct tlv_list_manager { 40 uint8_t nb_options; 41 struct rte_pmd_mlx5_geneve_tlv tlv_list[MAX_GENEVE_OPTIONS_RESOURCES]; 42 }; 43 44 static struct tlv_list_manager tlv_mng = {.nb_options = 0}; 45 46 static int 47 parse_uint(uint64_t *value, const char *str) 48 { 49 char *next = NULL; 50 uint64_t n; 51 52 errno = 0; 53 /* Parse number string */ 54 if (!strncasecmp(str, "0x", 2)) { 55 str += 2; 56 n = strtol(str, &next, 16); 57 } else { 58 n = strtol(str, &next, 10); 59 } 60 if (errno != 0 || str == next || *next != '\0') 61 return -1; 62 63 *value = n; 64 65 return 0; 66 } 67 68 /** 69 * Disable the host shaper and re-arm available descriptor threshold event. 70 * 71 * @param[in] args 72 * uint32_t integer combining port_id and rxq_id. 73 */ 74 static void 75 mlx5_test_host_shaper_disable(void *args) 76 { 77 uint32_t port_rxq_id = (uint32_t)(uintptr_t)args; 78 uint16_t port_id = port_rxq_id & 0xffff; 79 uint16_t qid = (port_rxq_id >> 16) & 0xffff; 80 struct rte_eth_rxq_info qinfo; 81 struct rte_port *port; 82 83 port = &ports[port_id]; 84 if (port->port_status != RTE_PORT_STARTED) { 85 printf("%s port_status(%d) is incorrect, stop avail_thresh " 86 "event processing.\n", 87 __func__, port->port_status); 88 return; 89 } 90 printf("%s disable shaper\n", __func__); 91 if (rte_eth_rx_queue_info_get(port_id, qid, &qinfo)) { 92 printf("rx_queue_info_get returns error\n"); 93 return; 94 } 95 /* Rearm the available descriptor threshold event. */ 96 if (rte_eth_rx_avail_thresh_set(port_id, qid, qinfo.avail_thresh)) { 97 printf("config avail_thresh returns error\n"); 98 return; 99 } 100 /* Only disable the shaper when avail_thresh_triggered is set. */ 101 if (host_shaper_avail_thresh_triggered[port_id] && 102 rte_pmd_mlx5_host_shaper_config(port_id, 0, 0)) 103 printf("%s disable shaper returns error\n", __func__); 104 } 105 106 void 107 mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id) 108 { 109 struct rte_eth_dev_info dev_info; 110 uint32_t port_rxq_id = port_id | (rxq_id << 16); 111 112 /* Ensure it's MLX5 port. */ 113 if (rte_eth_dev_info_get(port_id, &dev_info) != 0 || 114 (strncmp(dev_info.driver_name, "mlx5", 4) != 0)) 115 return; 116 rte_eal_alarm_set(SHAPER_DISABLE_DELAY_US, 117 mlx5_test_host_shaper_disable, 118 (void *)(uintptr_t)port_rxq_id); 119 printf("%s port_id:%u rxq_id:%u\n", __func__, port_id, rxq_id); 120 } 121 122 /** 123 * Configure host shaper's avail_thresh_triggered and current rate. 124 * 125 * @param[in] avail_thresh_triggered 126 * Disable/enable avail_thresh_triggered. 127 * @param[in] rate 128 * Configure current host shaper rate. 129 * @return 130 * On success, returns 0. 131 * On failure, returns < 0. 132 */ 133 static int 134 mlx5_test_set_port_host_shaper(uint16_t port_id, uint16_t avail_thresh_triggered, uint8_t rate) 135 { 136 struct rte_eth_link link; 137 bool port_id_valid = false; 138 uint16_t pid; 139 int ret; 140 141 RTE_ETH_FOREACH_DEV(pid) 142 if (port_id == pid) { 143 port_id_valid = true; 144 break; 145 } 146 if (!port_id_valid) 147 return -EINVAL; 148 ret = rte_eth_link_get_nowait(port_id, &link); 149 if (ret < 0) 150 return ret; 151 host_shaper_avail_thresh_triggered[port_id] = avail_thresh_triggered ? 1 : 0; 152 if (!avail_thresh_triggered) { 153 ret = rte_pmd_mlx5_host_shaper_config(port_id, 0, 154 RTE_BIT32(RTE_PMD_MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 155 } else { 156 ret = rte_pmd_mlx5_host_shaper_config(port_id, 1, 157 RTE_BIT32(RTE_PMD_MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 158 } 159 if (ret) 160 return ret; 161 ret = rte_pmd_mlx5_host_shaper_config(port_id, rate, 0); 162 if (ret) 163 return ret; 164 return 0; 165 } 166 167 #ifndef RTE_EXEC_ENV_WINDOWS 168 static const char* 169 mlx5_test_get_socket_path(char *extend) 170 { 171 if (strstr(extend, "socket=") == extend) { 172 const char *socket_path = strchr(extend, '=') + 1; 173 174 TESTPMD_LOG(DEBUG, "MLX5 socket path is %s\n", socket_path); 175 return socket_path; 176 } 177 178 TESTPMD_LOG(ERR, "Failed to extract a valid socket path from %s\n", 179 extend); 180 return NULL; 181 } 182 183 static int 184 mlx5_test_extend_devargs(char *identifier, char *extend) 185 { 186 struct sockaddr_un un = { 187 .sun_family = AF_UNIX, 188 }; 189 int cmd_fd; 190 int pd_handle; 191 struct iovec iov = { 192 .iov_base = &pd_handle, 193 .iov_len = sizeof(int), 194 }; 195 union { 196 char buf[CMSG_SPACE(sizeof(int))]; 197 struct cmsghdr align; 198 } control; 199 struct msghdr msgh = { 200 .msg_iov = NULL, 201 .msg_iovlen = 0, 202 }; 203 struct cmsghdr *cmsg; 204 const char *path = mlx5_test_get_socket_path(extend + 1); 205 size_t len = 1; 206 int socket_fd; 207 int ret; 208 209 if (path == NULL) { 210 TESTPMD_LOG(ERR, "Invalid devargs extension is specified\n"); 211 return -1; 212 } 213 214 /* Initialize IPC channel. */ 215 socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 216 if (socket_fd < 0) { 217 TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n", 218 strerror(errno)); 219 return -1; 220 } 221 rte_strlcpy(un.sun_path, path, sizeof(un.sun_path)); 222 if (connect(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { 223 TESTPMD_LOG(ERR, "Failed to connect %s: %s\n", un.sun_path, 224 strerror(errno)); 225 close(socket_fd); 226 return -1; 227 } 228 229 /* Send the request message. */ 230 do { 231 ret = sendmsg(socket_fd, &msgh, 0); 232 } while (ret < 0 && errno == EINTR); 233 if (ret < 0) { 234 TESTPMD_LOG(ERR, "Failed to send request to (%s): %s\n", path, 235 strerror(errno)); 236 close(socket_fd); 237 return -1; 238 } 239 240 msgh.msg_iov = &iov; 241 msgh.msg_iovlen = 1; 242 msgh.msg_control = control.buf; 243 msgh.msg_controllen = sizeof(control.buf); 244 do { 245 ret = recvmsg(socket_fd, &msgh, 0); 246 } while (ret < 0); 247 if (ret != sizeof(int) || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) { 248 TESTPMD_LOG(ERR, "truncated msg"); 249 close(socket_fd); 250 return -1; 251 } 252 253 /* Translate the FD. */ 254 cmsg = CMSG_FIRSTHDR(&msgh); 255 if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 256 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 257 TESTPMD_LOG(ERR, "Fail to get FD using SCM_RIGHTS mechanism\n"); 258 close(socket_fd); 259 unlink(un.sun_path); 260 return -1; 261 } 262 memcpy(&cmd_fd, CMSG_DATA(cmsg), sizeof(int)); 263 264 TESTPMD_LOG(DEBUG, "Command FD (%d) and PD handle (%d) " 265 "are successfully imported from remote process\n", 266 cmd_fd, pd_handle); 267 268 /* Cleanup IPC channel. */ 269 close(socket_fd); 270 271 /* Calculate the new length of devargs string. */ 272 len += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); 273 /* Extend the devargs string. */ 274 snprintf(extend, len, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); 275 276 TESTPMD_LOG(DEBUG, "Attach port with extra devargs %s\n", identifier); 277 return 0; 278 } 279 280 static bool 281 is_delimiter_path_spaces(char *extend) 282 { 283 while (*extend != '\0') { 284 if (*extend != ' ') 285 return true; 286 extend++; 287 } 288 return false; 289 } 290 291 /* 292 * Extend devargs list with "cmd_fd" and "pd_handle" coming from external 293 * process. It happens only in this format: 294 * testpmd> mlx5 port attach (identifier) socket=<socket path> 295 * all "(identifier) socket=<socket path>" is in the same string pointed 296 * by the input parameter 'identifier'. 297 * 298 * @param identifier 299 * Identifier of port attach command line. 300 */ 301 static void 302 mlx5_test_attach_port_extend_devargs(char *identifier) 303 { 304 char *extend; 305 306 if (identifier == NULL) { 307 fprintf(stderr, "Invalid parameters are specified\n"); 308 return; 309 } 310 311 extend = strchr(identifier, ' '); 312 if (extend != NULL && is_delimiter_path_spaces(extend) && 313 mlx5_test_extend_devargs(identifier, extend) < 0) { 314 TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n", 315 identifier); 316 return; 317 } 318 319 attach_port(identifier); 320 } 321 #endif 322 323 static inline const char * 324 mode2string(uint8_t mode) 325 { 326 switch (mode) { 327 case 0: 328 return "ignored\t"; 329 case 1: 330 return "fixed\t"; 331 case 2: 332 return "matchable"; 333 default: 334 break; 335 } 336 return "unknown"; 337 } 338 339 static inline uint8_t 340 string2mode(const char *mode) 341 { 342 if (strcmp(mode, "ignored") == 0) 343 return 0; 344 if (strcmp(mode, "fixed") == 0) 345 return 1; 346 if (strcmp(mode, "matchable") == 0) 347 return 2; 348 return UINT8_MAX; 349 } 350 351 static int 352 mlx5_test_parse_geneve_option_data(const char *buff, uint8_t data_len, 353 rte_be32_t **match_data_mask) 354 { 355 rte_be32_t *data; 356 char *buff2; 357 char *token; 358 uint8_t i = 0; 359 360 if (data_len == 0) { 361 *match_data_mask = NULL; 362 return 0; 363 } 364 365 data = calloc(data_len, sizeof(rte_be32_t)); 366 if (data == NULL) { 367 TESTPMD_LOG(ERR, "Fail to allocate memory for GENEVE TLV option data\n"); 368 return -ENOMEM; 369 } 370 371 buff2 = strdup(buff); 372 if (buff2 == NULL) { 373 TESTPMD_LOG(ERR, 374 "Fail to duplicate GENEVE TLV option data string (%s)\n", 375 buff); 376 free(data); 377 return -ENOMEM; 378 } 379 380 token = strtok(buff2, SPACE_DELIMITER); 381 while (token != NULL) { 382 if (i == data_len) { 383 TESTPMD_LOG(ERR, 384 "GENEVE TLV option has more data then given data length %u\n", 385 data_len); 386 free(buff2); 387 free(data); 388 return -EINVAL; 389 } 390 391 if (strcmp(token, "0xffffffff") == 0) 392 data[i] = 0xffffffff; 393 else 394 data[i] = 0x0; 395 396 token = strtok(NULL, SPACE_DELIMITER); 397 i++; 398 } 399 400 free(buff2); 401 *match_data_mask = data; 402 return 0; 403 } 404 405 /* *** SET HOST_SHAPER FOR A PORT *** */ 406 struct cmd_port_host_shaper_result { 407 cmdline_fixed_string_t mlx5; 408 cmdline_fixed_string_t set; 409 cmdline_fixed_string_t port; 410 uint16_t port_num; 411 cmdline_fixed_string_t host_shaper; 412 cmdline_fixed_string_t avail_thresh_triggered; 413 uint16_t fr; 414 cmdline_fixed_string_t rate; 415 uint8_t rate_num; 416 }; 417 418 static void cmd_port_host_shaper_parsed(void *parsed_result, 419 __rte_unused struct cmdline *cl, 420 __rte_unused void *data) 421 { 422 struct cmd_port_host_shaper_result *res = parsed_result; 423 int ret = 0; 424 425 if ((strcmp(res->mlx5, "mlx5") == 0) && 426 (strcmp(res->set, "set") == 0) && 427 (strcmp(res->port, "port") == 0) && 428 (strcmp(res->host_shaper, "host_shaper") == 0) && 429 (strcmp(res->avail_thresh_triggered, "avail_thresh_triggered") == 0) && 430 (strcmp(res->rate, "rate") == 0)) 431 ret = mlx5_test_set_port_host_shaper(res->port_num, res->fr, 432 res->rate_num); 433 if (ret < 0) 434 printf("cmd_port_host_shaper error: (%s)\n", strerror(-ret)); 435 } 436 437 static cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 = 438 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 439 mlx5, "mlx5"); 440 static cmdline_parse_token_string_t cmd_port_host_shaper_set = 441 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 442 set, "set"); 443 static cmdline_parse_token_string_t cmd_port_host_shaper_port = 444 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 445 port, "port"); 446 static cmdline_parse_token_num_t cmd_port_host_shaper_portnum = 447 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 448 port_num, RTE_UINT16); 449 static cmdline_parse_token_string_t cmd_port_host_shaper_host_shaper = 450 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 451 host_shaper, "host_shaper"); 452 static cmdline_parse_token_string_t cmd_port_host_shaper_avail_thresh_triggered = 453 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 454 avail_thresh_triggered, "avail_thresh_triggered"); 455 static cmdline_parse_token_num_t cmd_port_host_shaper_fr = 456 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 457 fr, RTE_UINT16); 458 static cmdline_parse_token_string_t cmd_port_host_shaper_rate = 459 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 460 rate, "rate"); 461 static cmdline_parse_token_num_t cmd_port_host_shaper_rate_num = 462 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 463 rate_num, RTE_UINT8); 464 static cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper = { 465 .f = cmd_port_host_shaper_parsed, 466 .data = (void *)0, 467 .help_str = "mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> " 468 "rate <rate_num>: Set HOST_SHAPER avail_thresh_triggered and rate with port_id", 469 .tokens = { 470 (void *)&cmd_port_host_shaper_mlx5, 471 (void *)&cmd_port_host_shaper_set, 472 (void *)&cmd_port_host_shaper_port, 473 (void *)&cmd_port_host_shaper_portnum, 474 (void *)&cmd_port_host_shaper_host_shaper, 475 (void *)&cmd_port_host_shaper_avail_thresh_triggered, 476 (void *)&cmd_port_host_shaper_fr, 477 (void *)&cmd_port_host_shaper_rate, 478 (void *)&cmd_port_host_shaper_rate_num, 479 NULL, 480 } 481 }; 482 483 #ifndef RTE_EXEC_ENV_WINDOWS 484 /* *** attach a specified port *** */ 485 struct mlx5_cmd_operate_attach_port_result { 486 cmdline_fixed_string_t mlx5; 487 cmdline_fixed_string_t port; 488 cmdline_fixed_string_t keyword; 489 cmdline_multi_string_t identifier; 490 }; 491 492 static void mlx5_cmd_operate_attach_port_parsed(void *parsed_result, 493 __rte_unused struct cmdline *cl, 494 __rte_unused void *data) 495 { 496 struct mlx5_cmd_operate_attach_port_result *res = parsed_result; 497 498 if (!strcmp(res->keyword, "attach")) 499 mlx5_test_attach_port_extend_devargs(res->identifier); 500 else 501 fprintf(stderr, "Unknown parameter\n"); 502 } 503 504 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_mlx5 = 505 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 506 mlx5, "mlx5"); 507 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_port = 508 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 509 port, "port"); 510 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_keyword = 511 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 512 keyword, "attach"); 513 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_identifier = 514 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 515 identifier, TOKEN_STRING_MULTI); 516 517 static cmdline_parse_inst_t mlx5_cmd_operate_attach_port = { 518 .f = mlx5_cmd_operate_attach_port_parsed, 519 .data = NULL, 520 .help_str = "mlx5 port attach <identifier> socket=<path>: " 521 "(identifier: pci address or virtual dev name" 522 ", path (optional): socket path to get cmd FD and PD handle)", 523 .tokens = { 524 (void *)&mlx5_cmd_operate_attach_port_mlx5, 525 (void *)&mlx5_cmd_operate_attach_port_port, 526 (void *)&mlx5_cmd_operate_attach_port_keyword, 527 (void *)&mlx5_cmd_operate_attach_port_identifier, 528 NULL, 529 }, 530 }; 531 #endif 532 533 /* Map HW queue index to rte queue index. */ 534 struct mlx5_cmd_map_ext_rxq { 535 cmdline_fixed_string_t mlx5; 536 cmdline_fixed_string_t port; 537 portid_t port_id; 538 cmdline_fixed_string_t ext_rxq; 539 cmdline_fixed_string_t map; 540 uint16_t sw_queue_id; 541 uint32_t hw_queue_id; 542 }; 543 544 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_mlx5 = 545 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, mlx5, "mlx5"); 546 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_port = 547 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port, "port"); 548 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_port_id = 549 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port_id, RTE_UINT16); 550 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_ext_rxq = 551 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, ext_rxq, 552 "ext_rxq"); 553 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_map = 554 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, map, "map"); 555 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_sw_queue_id = 556 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, sw_queue_id, 557 RTE_UINT16); 558 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_hw_queue_id = 559 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, hw_queue_id, 560 RTE_UINT32); 561 562 static void 563 mlx5_cmd_map_ext_rxq_parsed(void *parsed_result, 564 __rte_unused struct cmdline *cl, 565 __rte_unused void *data) 566 { 567 struct mlx5_cmd_map_ext_rxq *res = parsed_result; 568 int ret; 569 570 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 571 return; 572 ret = rte_pmd_mlx5_external_rx_queue_id_map(res->port_id, 573 res->sw_queue_id, 574 res->hw_queue_id); 575 switch (ret) { 576 case 0: 577 break; 578 case -EINVAL: 579 fprintf(stderr, "invalid ethdev index (%u), out of range\n", 580 res->sw_queue_id); 581 break; 582 case -ENODEV: 583 fprintf(stderr, "invalid port_id %u\n", res->port_id); 584 break; 585 case -ENOTSUP: 586 fprintf(stderr, "function not implemented or supported\n"); 587 break; 588 case -EEXIST: 589 fprintf(stderr, "mapping with index %u already exists\n", 590 res->sw_queue_id); 591 break; 592 default: 593 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 594 } 595 } 596 597 cmdline_parse_inst_t mlx5_cmd_map_ext_rxq = { 598 .f = mlx5_cmd_map_ext_rxq_parsed, 599 .data = NULL, 600 .help_str = "mlx5 port <port_id> ext_rxq map <sw_queue_id> <hw_queue_id>", 601 .tokens = { 602 (void *)&mlx5_cmd_map_ext_rxq_mlx5, 603 (void *)&mlx5_cmd_map_ext_rxq_port, 604 (void *)&mlx5_cmd_map_ext_rxq_port_id, 605 (void *)&mlx5_cmd_map_ext_rxq_ext_rxq, 606 (void *)&mlx5_cmd_map_ext_rxq_map, 607 (void *)&mlx5_cmd_map_ext_rxq_sw_queue_id, 608 (void *)&mlx5_cmd_map_ext_rxq_hw_queue_id, 609 NULL, 610 } 611 }; 612 613 /* Unmap HW queue index to rte queue index. */ 614 struct mlx5_cmd_unmap_ext_rxq { 615 cmdline_fixed_string_t mlx5; 616 cmdline_fixed_string_t port; 617 portid_t port_id; 618 cmdline_fixed_string_t ext_rxq; 619 cmdline_fixed_string_t unmap; 620 uint16_t queue_id; 621 }; 622 623 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_mlx5 = 624 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, mlx5, "mlx5"); 625 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_port = 626 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port, "port"); 627 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_port_id = 628 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port_id, 629 RTE_UINT16); 630 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_ext_rxq = 631 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, ext_rxq, 632 "ext_rxq"); 633 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_unmap = 634 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, unmap, "unmap"); 635 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_queue_id = 636 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, queue_id, 637 RTE_UINT16); 638 639 static void 640 mlx5_cmd_unmap_ext_rxq_parsed(void *parsed_result, 641 __rte_unused struct cmdline *cl, 642 __rte_unused void *data) 643 { 644 struct mlx5_cmd_unmap_ext_rxq *res = parsed_result; 645 int ret; 646 647 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 648 return; 649 ret = rte_pmd_mlx5_external_rx_queue_id_unmap(res->port_id, 650 res->queue_id); 651 switch (ret) { 652 case 0: 653 break; 654 case -EINVAL: 655 fprintf(stderr, "invalid rte_flow index (%u), " 656 "out of range, doesn't exist or still referenced\n", 657 res->queue_id); 658 break; 659 case -ENODEV: 660 fprintf(stderr, "invalid port_id %u\n", res->port_id); 661 break; 662 case -ENOTSUP: 663 fprintf(stderr, "function not implemented or supported\n"); 664 break; 665 default: 666 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 667 } 668 } 669 670 cmdline_parse_inst_t mlx5_cmd_unmap_ext_rxq = { 671 .f = mlx5_cmd_unmap_ext_rxq_parsed, 672 .data = NULL, 673 .help_str = "mlx5 port <port_id> ext_rxq unmap <queue_id>", 674 .tokens = { 675 (void *)&mlx5_cmd_unmap_ext_rxq_mlx5, 676 (void *)&mlx5_cmd_unmap_ext_rxq_port, 677 (void *)&mlx5_cmd_unmap_ext_rxq_port_id, 678 (void *)&mlx5_cmd_unmap_ext_rxq_ext_rxq, 679 (void *)&mlx5_cmd_unmap_ext_rxq_unmap, 680 (void *)&mlx5_cmd_unmap_ext_rxq_queue_id, 681 NULL, 682 } 683 }; 684 685 /* Set flow engine mode with flags command. */ 686 struct mlx5_cmd_set_flow_engine_mode { 687 cmdline_fixed_string_t mlx5; 688 cmdline_fixed_string_t set; 689 cmdline_fixed_string_t flow_engine; 690 cmdline_multi_string_t mode; 691 }; 692 693 static int 694 parse_multi_token_flow_engine_mode(char *t_str, 695 enum rte_pmd_mlx5_flow_engine_mode *mode, uint32_t *flag) 696 { 697 uint64_t val; 698 char *token; 699 int ret; 700 701 *flag = 0; 702 /* First token: mode string */ 703 token = strtok_r(t_str, PARSE_DELIMITER, &t_str); 704 if (token == NULL) 705 return -1; 706 707 if (!strcmp(token, "active")) 708 *mode = RTE_PMD_MLX5_FLOW_ENGINE_MODE_ACTIVE; 709 else if (!strcmp(token, "standby")) 710 *mode = RTE_PMD_MLX5_FLOW_ENGINE_MODE_STANDBY; 711 else 712 return -1; 713 714 /* Second token: flag */ 715 token = strtok_r(t_str, PARSE_DELIMITER, &t_str); 716 if (token == NULL) 717 return 0; 718 719 ret = parse_uint(&val, token); 720 if (ret != 0 || val > UINT32_MAX) 721 return -1; 722 723 *flag = val; 724 return 0; 725 } 726 727 static void 728 mlx5_cmd_set_flow_engine_mode_parsed(void *parsed_result, 729 __rte_unused struct cmdline *cl, 730 __rte_unused void *data) 731 { 732 struct mlx5_cmd_set_flow_engine_mode *res = parsed_result; 733 enum rte_pmd_mlx5_flow_engine_mode mode; 734 uint32_t flag; 735 int ret; 736 737 ret = parse_multi_token_flow_engine_mode(res->mode, &mode, &flag); 738 739 if (ret < 0) { 740 fprintf(stderr, "Bad input\n"); 741 return; 742 } 743 744 ret = rte_pmd_mlx5_flow_engine_set_mode(mode, flag); 745 746 if (ret < 0) 747 fprintf(stderr, "Fail to set flow_engine to %s mode with flag 0x%x, error %s\n", 748 mode == RTE_PMD_MLX5_FLOW_ENGINE_MODE_ACTIVE ? "active" : "standby", flag, 749 strerror(-ret)); 750 else 751 TESTPMD_LOG(DEBUG, "Set %d ports flow_engine to %s mode with flag 0x%x\n", ret, 752 mode == RTE_PMD_MLX5_FLOW_ENGINE_MODE_ACTIVE ? "active" : "standby", flag); 753 } 754 755 cmdline_parse_token_string_t mlx5_cmd_set_flow_engine_mode_mlx5 = 756 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_flow_engine_mode, mlx5, 757 "mlx5"); 758 cmdline_parse_token_string_t mlx5_cmd_set_flow_engine_mode_set = 759 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_flow_engine_mode, set, 760 "set"); 761 cmdline_parse_token_string_t mlx5_cmd_set_flow_engine_mode_flow_engine = 762 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_flow_engine_mode, flow_engine, 763 "flow_engine"); 764 cmdline_parse_token_string_t mlx5_cmd_set_flow_engine_mode_mode = 765 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_flow_engine_mode, mode, 766 TOKEN_STRING_MULTI); 767 768 cmdline_parse_inst_t mlx5_cmd_set_flow_engine_mode = { 769 .f = &mlx5_cmd_set_flow_engine_mode_parsed, 770 .data = NULL, 771 .help_str = "mlx5 set flow_engine <active|standby> [<flag>]", 772 .tokens = { 773 (void *)&mlx5_cmd_set_flow_engine_mode_mlx5, 774 (void *)&mlx5_cmd_set_flow_engine_mode_set, 775 (void *)&mlx5_cmd_set_flow_engine_mode_flow_engine, 776 (void *)&mlx5_cmd_set_flow_engine_mode_mode, 777 NULL, 778 } 779 }; 780 781 /* Prepare single GENEVE TLV option and add it into global option list. */ 782 struct mlx5_cmd_set_tlv_option { 783 cmdline_fixed_string_t mlx5; 784 cmdline_fixed_string_t set; 785 cmdline_fixed_string_t tlv_option; 786 cmdline_fixed_string_t class; 787 uint16_t class_id; 788 cmdline_fixed_string_t type; 789 uint8_t type_id; 790 cmdline_fixed_string_t len; 791 uint8_t option_len; 792 cmdline_fixed_string_t offset; 793 uint8_t off; 794 cmdline_fixed_string_t sample_len; 795 uint8_t length; 796 cmdline_fixed_string_t class_mode; 797 cmdline_fixed_string_t cmode; 798 cmdline_fixed_string_t data; 799 cmdline_fixed_string_t data_mask; 800 }; 801 802 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_mlx5 = 803 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, mlx5, "mlx5"); 804 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_set = 805 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, set, "set"); 806 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_tlv_option = 807 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, tlv_option, 808 "tlv_option"); 809 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_class = 810 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, class, 811 "class"); 812 cmdline_parse_token_num_t mlx5_cmd_set_tlv_option_class_id = 813 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_set_tlv_option, class_id, 814 RTE_UINT16); 815 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_type = 816 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, type, "type"); 817 cmdline_parse_token_num_t mlx5_cmd_set_tlv_option_type_id = 818 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_set_tlv_option, type_id, 819 RTE_UINT8); 820 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_len = 821 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, len, "len"); 822 cmdline_parse_token_num_t mlx5_cmd_set_tlv_option_option_len = 823 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_set_tlv_option, option_len, 824 RTE_UINT8); 825 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_offset = 826 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, offset, 827 "offset"); 828 cmdline_parse_token_num_t mlx5_cmd_set_tlv_option_off = 829 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_set_tlv_option, off, RTE_UINT8); 830 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_sample_len = 831 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, sample_len, 832 "sample_len"); 833 cmdline_parse_token_num_t mlx5_cmd_set_tlv_option_length = 834 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_set_tlv_option, length, 835 RTE_UINT8); 836 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_class_mode = 837 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, class_mode, 838 "class_mode"); 839 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_cmode = 840 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, cmode, 841 "ignored#fixed#matchable"); 842 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_data = 843 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, data, "data"); 844 cmdline_parse_token_string_t mlx5_cmd_set_tlv_option_data_mask = 845 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_set_tlv_option, data_mask, ""); 846 847 static void 848 mlx5_cmd_set_tlv_option_parsed(void *parsed_result, 849 __rte_unused struct cmdline *cl, 850 __rte_unused void *data) 851 { 852 struct mlx5_cmd_set_tlv_option *res = parsed_result; 853 struct rte_pmd_mlx5_geneve_tlv *option; 854 uint8_t class_mode; 855 int ret; 856 857 if (tlv_mng.nb_options == MAX_GENEVE_OPTIONS_RESOURCES) { 858 fprintf(stderr, "GENEVE TLV option list is full\n"); 859 return; 860 } 861 862 if (res->option_len < res->length + res->off) { 863 fprintf(stderr, 864 "GENEVE TLV option length (%u) cannot be less than offset (%u) + sample_len (%u)\n", 865 res->option_len, res->length, res->off); 866 return; 867 } 868 869 if (res->option_len > 32) { 870 fprintf(stderr, 871 "GENEVE TLV option length (%u) must be less than 32\n", 872 res->option_len); 873 return; 874 } 875 876 class_mode = string2mode(res->cmode); 877 if (class_mode == UINT8_MAX) { 878 fprintf(stderr, "Invalid class mode \"%s\"\n", res->cmode); 879 return; 880 } 881 882 if (res->length > 0) { 883 if (strcmp(res->data, "data") || !strcmp(res->data_mask, "")) { 884 fprintf(stderr, 885 "sample_len is %u but any data isn't provided\n", 886 res->length); 887 return; 888 } 889 } else { 890 if (!strcmp(res->data, "data") && strcmp(res->data_mask, "")) { 891 fprintf(stderr, 892 "sample_len is 0 but data is provided (%s)\n", 893 res->data_mask); 894 return; 895 } 896 } 897 898 option = &tlv_mng.tlv_list[tlv_mng.nb_options]; 899 ret = mlx5_test_parse_geneve_option_data(res->data_mask, res->length, 900 &option->match_data_mask); 901 if (ret < 0) 902 return; 903 904 option->match_on_class_mode = class_mode; 905 option->option_class = rte_cpu_to_be_16(res->class_id); 906 option->option_type = res->type_id; 907 option->option_len = res->option_len; 908 option->offset = res->off; 909 option->sample_len = res->length; 910 tlv_mng.nb_options++; 911 912 TESTPMD_LOG(DEBUG, 913 "set new option in global list, now it has %u options\n", 914 tlv_mng.nb_options); 915 } 916 917 cmdline_parse_inst_t mlx5_cmd_set_tlv_option = { 918 .f = mlx5_cmd_set_tlv_option_parsed, 919 .data = NULL, 920 .help_str = "mlx5 set tlv_option class <class_id> type <type_id> len " 921 "<option_len> offset <sample_offset> sample_len " 922 "<sample_length> class_mode <ignored|fixed|matchable> data <mask1 [mask2 [...]>", 923 .tokens = { 924 (void *)&mlx5_cmd_set_tlv_option_mlx5, 925 (void *)&mlx5_cmd_set_tlv_option_set, 926 (void *)&mlx5_cmd_set_tlv_option_tlv_option, 927 (void *)&mlx5_cmd_set_tlv_option_class, 928 (void *)&mlx5_cmd_set_tlv_option_class_id, 929 (void *)&mlx5_cmd_set_tlv_option_type, 930 (void *)&mlx5_cmd_set_tlv_option_type_id, 931 (void *)&mlx5_cmd_set_tlv_option_len, 932 (void *)&mlx5_cmd_set_tlv_option_option_len, 933 (void *)&mlx5_cmd_set_tlv_option_offset, 934 (void *)&mlx5_cmd_set_tlv_option_off, 935 (void *)&mlx5_cmd_set_tlv_option_sample_len, 936 (void *)&mlx5_cmd_set_tlv_option_length, 937 (void *)&mlx5_cmd_set_tlv_option_class_mode, 938 (void *)&mlx5_cmd_set_tlv_option_cmode, 939 (void *)&mlx5_cmd_set_tlv_option_data, 940 (void *)&mlx5_cmd_set_tlv_option_data_mask, 941 NULL, 942 } 943 }; 944 945 /* Print all GENEVE TLV options which are configured so far. */ 946 struct mlx5_cmd_list_tlv_options { 947 cmdline_fixed_string_t mlx5; 948 cmdline_fixed_string_t list; 949 cmdline_fixed_string_t tlv_options; 950 }; 951 952 cmdline_parse_token_string_t mlx5_cmd_list_tlv_options_mlx5 = 953 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_list_tlv_options, mlx5, 954 "mlx5"); 955 cmdline_parse_token_string_t mlx5_cmd_list_tlv_options_list = 956 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_list_tlv_options, list, 957 "list"); 958 cmdline_parse_token_string_t mlx5_cmd_list_tlv_options_tlv_options = 959 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_list_tlv_options, tlv_options, 960 "tlv_options"); 961 962 static void 963 mlx5_cmd_list_tlv_options_parsed(__rte_unused void *parsed_result, 964 __rte_unused struct cmdline *cl, 965 __rte_unused void *data) 966 { 967 struct rte_pmd_mlx5_geneve_tlv *option; 968 uint8_t i, j; 969 970 printf("ID\tType\tClass\tClass_mode\tLen\tOffset\tSample_len\tData\n"); 971 for (i = 0; i < tlv_mng.nb_options; ++i) { 972 option = &tlv_mng.tlv_list[i]; 973 printf("%u\t%u\t%u\t%s\t%u\t%u\t%u\t\t", i, 974 option->option_type, rte_be_to_cpu_16(option->option_class), 975 mode2string(option->match_on_class_mode), 976 option->option_len, 977 option->offset, option->sample_len); 978 for (j = 0; j < option->sample_len; ++j) 979 printf("0x%x ", option->match_data_mask[j]); 980 printf("\n"); 981 } 982 } 983 984 cmdline_parse_inst_t mlx5_cmd_list_tlv_options = { 985 .f = mlx5_cmd_list_tlv_options_parsed, 986 .data = NULL, 987 .help_str = "mlx5 list tlv_options", 988 .tokens = { 989 (void *)&mlx5_cmd_list_tlv_options_mlx5, 990 (void *)&mlx5_cmd_list_tlv_options_list, 991 (void *)&mlx5_cmd_list_tlv_options_tlv_options, 992 NULL, 993 } 994 }; 995 996 /* Clear all GENEVE TLV options which are configured so far. */ 997 struct mlx5_cmd_flush_tlv_options { 998 cmdline_fixed_string_t mlx5; 999 cmdline_fixed_string_t flush; 1000 cmdline_fixed_string_t tlv_options; 1001 cmdline_fixed_string_t max; 1002 uint8_t number; 1003 }; 1004 1005 cmdline_parse_token_string_t mlx5_cmd_flush_tlv_options_mlx5 = 1006 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_flush_tlv_options, mlx5, 1007 "mlx5"); 1008 cmdline_parse_token_string_t mlx5_cmd_flush_tlv_options_flush = 1009 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_flush_tlv_options, flush, 1010 "flush"); 1011 cmdline_parse_token_string_t mlx5_cmd_flush_tlv_options_tlv_options = 1012 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_flush_tlv_options, tlv_options, 1013 "tlv_options"); 1014 cmdline_parse_token_string_t mlx5_cmd_flush_tlv_options_max = 1015 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_flush_tlv_options, max, "max"); 1016 cmdline_parse_token_num_t mlx5_cmd_flush_tlv_options_number = 1017 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_flush_tlv_options, number, 1018 RTE_UINT8); 1019 1020 static void 1021 mlx5_cmd_flush_tlv_options_parsed(void *parsed_result, 1022 __rte_unused struct cmdline *cl, 1023 __rte_unused void *data) 1024 { 1025 struct mlx5_cmd_flush_tlv_options *res = parsed_result; 1026 struct rte_pmd_mlx5_geneve_tlv *option; 1027 uint8_t nb_options_flush = tlv_mng.nb_options; 1028 uint8_t nb_options_left = 0; 1029 1030 if (strcmp(res->max, "max") == 0 && res->number < tlv_mng.nb_options) { 1031 nb_options_left = tlv_mng.nb_options - res->number; 1032 nb_options_flush = RTE_MIN(res->number, nb_options_flush); 1033 } 1034 1035 while (tlv_mng.nb_options > nb_options_left) { 1036 tlv_mng.nb_options--; 1037 option = &tlv_mng.tlv_list[tlv_mng.nb_options]; 1038 if (option->match_data_mask) { 1039 free(option->match_data_mask); 1040 option->match_data_mask = NULL; 1041 } 1042 } 1043 1044 TESTPMD_LOG(DEBUG, "Flush %u latest configured GENEVE TLV options, " 1045 "current number of options in the list is %u\n", 1046 nb_options_flush, nb_options_left); 1047 } 1048 1049 cmdline_parse_inst_t mlx5_cmd_flush_tlv_options = { 1050 .f = mlx5_cmd_flush_tlv_options_parsed, 1051 .data = NULL, 1052 .help_str = "mlx5 flush tlv_options max <nb_options>", 1053 .tokens = { 1054 (void *)&mlx5_cmd_flush_tlv_options_mlx5, 1055 (void *)&mlx5_cmd_flush_tlv_options_flush, 1056 (void *)&mlx5_cmd_flush_tlv_options_tlv_options, 1057 (void *)&mlx5_cmd_flush_tlv_options_max, 1058 (void *)&mlx5_cmd_flush_tlv_options_number, 1059 NULL, 1060 } 1061 }; 1062 1063 /* Create GENEVE TLV parser using option list which is configured before. */ 1064 struct mlx5_cmd_apply_tlv_options { 1065 cmdline_fixed_string_t mlx5; 1066 cmdline_fixed_string_t port; 1067 portid_t port_id; 1068 cmdline_fixed_string_t apply; 1069 cmdline_fixed_string_t tlv_options; 1070 }; 1071 1072 cmdline_parse_token_string_t mlx5_cmd_apply_tlv_options_mlx5 = 1073 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_apply_tlv_options, mlx5, 1074 "mlx5"); 1075 cmdline_parse_token_string_t mlx5_cmd_apply_tlv_options_port = 1076 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_apply_tlv_options, port, 1077 "port"); 1078 cmdline_parse_token_num_t mlx5_cmd_apply_tlv_options_port_id = 1079 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_apply_tlv_options, port_id, 1080 RTE_UINT16); 1081 cmdline_parse_token_string_t mlx5_cmd_apply_tlv_options_apply = 1082 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_apply_tlv_options, apply, 1083 "apply"); 1084 cmdline_parse_token_string_t mlx5_cmd_apply_tlv_options_tlv_options = 1085 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_apply_tlv_options, tlv_options, 1086 "tlv_options"); 1087 1088 static void 1089 mlx5_cmd_apply_tlv_options_parsed(void *parsed_result, 1090 __rte_unused struct cmdline *cl, 1091 __rte_unused void *data) 1092 { 1093 struct mlx5_cmd_apply_tlv_options *res = parsed_result; 1094 struct mlx5_port *port; 1095 void *handle; 1096 1097 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 1098 return; 1099 1100 if (tlv_mng.nb_options == 0) { 1101 fprintf(stderr, "The option list is empty, please set options\n"); 1102 return; 1103 } 1104 1105 handle = rte_pmd_mlx5_create_geneve_tlv_parser(res->port_id, 1106 tlv_mng.tlv_list, 1107 tlv_mng.nb_options); 1108 if (handle == NULL) { 1109 fprintf(stderr, 1110 "Fail to create GENEVE TLV parser, nb_option=%u: %s\n", 1111 tlv_mng.nb_options, strerror(rte_errno)); 1112 return; 1113 } 1114 1115 TESTPMD_LOG(DEBUG, "GENEVE TLV options parser is successfully created:" 1116 " nb_option=%u, handle=%p\n", tlv_mng.nb_options, handle); 1117 1118 port = &private_port[res->port_id]; 1119 port->geneve_tlv_parser_handle = handle; 1120 } 1121 1122 cmdline_parse_inst_t mlx5_cmd_apply_tlv_options = { 1123 .f = mlx5_cmd_apply_tlv_options_parsed, 1124 .data = NULL, 1125 .help_str = "mlx5 port <port_id> apply tlv_options", 1126 .tokens = { 1127 (void *)&mlx5_cmd_apply_tlv_options_mlx5, 1128 (void *)&mlx5_cmd_apply_tlv_options_port, 1129 (void *)&mlx5_cmd_apply_tlv_options_port_id, 1130 (void *)&mlx5_cmd_apply_tlv_options_apply, 1131 (void *)&mlx5_cmd_apply_tlv_options_tlv_options, 1132 NULL, 1133 } 1134 }; 1135 1136 /* Destroy GENEVE TLV parser created by apply command. */ 1137 struct mlx5_cmd_destroy_tlv_options { 1138 cmdline_fixed_string_t mlx5; 1139 cmdline_fixed_string_t port; 1140 portid_t port_id; 1141 cmdline_fixed_string_t destroy; 1142 cmdline_fixed_string_t tlv_options; 1143 }; 1144 1145 cmdline_parse_token_string_t mlx5_cmd_destroy_tlv_options_mlx5 = 1146 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_destroy_tlv_options, mlx5, 1147 "mlx5"); 1148 cmdline_parse_token_string_t mlx5_cmd_destroy_tlv_options_port = 1149 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_destroy_tlv_options, port, 1150 "port"); 1151 cmdline_parse_token_num_t mlx5_cmd_destroy_tlv_options_port_id = 1152 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_destroy_tlv_options, port_id, 1153 RTE_UINT16); 1154 cmdline_parse_token_string_t mlx5_cmd_destroy_tlv_options_destroy = 1155 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_destroy_tlv_options, destroy, 1156 "destroy"); 1157 cmdline_parse_token_string_t mlx5_cmd_destroy_tlv_options_tlv_options = 1158 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_destroy_tlv_options, tlv_options, 1159 "tlv_options"); 1160 1161 static void 1162 mlx5_cmd_destroy_tlv_options_parsed(void *parsed_result, 1163 __rte_unused struct cmdline *cl, 1164 __rte_unused void *data) 1165 { 1166 struct mlx5_cmd_destroy_tlv_options *res = parsed_result; 1167 struct mlx5_port *port; 1168 int ret; 1169 1170 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 1171 return; 1172 1173 port = &private_port[res->port_id]; 1174 if (!port->geneve_tlv_parser_handle) 1175 return; 1176 1177 ret = rte_pmd_mlx5_destroy_geneve_tlv_parser(port->geneve_tlv_parser_handle); 1178 if (ret < 0) { 1179 fprintf(stderr, "Fail to destroy GENEVE TLV parser: %s\n", 1180 strerror(-ret)); 1181 return; 1182 } 1183 1184 TESTPMD_LOG(DEBUG, "GENEVE TLV options parser is successfully released:" 1185 " handle=%p\n", port->geneve_tlv_parser_handle); 1186 1187 port->geneve_tlv_parser_handle = NULL; 1188 } 1189 1190 cmdline_parse_inst_t mlx5_cmd_destroy_tlv_options = { 1191 .f = mlx5_cmd_destroy_tlv_options_parsed, 1192 .data = NULL, 1193 .help_str = "mlx5 port <port_id> destroy tlv_options", 1194 .tokens = { 1195 (void *)&mlx5_cmd_destroy_tlv_options_mlx5, 1196 (void *)&mlx5_cmd_destroy_tlv_options_port, 1197 (void *)&mlx5_cmd_destroy_tlv_options_port_id, 1198 (void *)&mlx5_cmd_destroy_tlv_options_destroy, 1199 (void *)&mlx5_cmd_destroy_tlv_options_tlv_options, 1200 NULL, 1201 } 1202 }; 1203 1204 /* Dump SQ Context for a given port/queue*/ 1205 struct mlx5_cmd_dump_sq_context_options { 1206 cmdline_fixed_string_t mlx5; 1207 cmdline_fixed_string_t port; 1208 portid_t port_id; 1209 cmdline_fixed_string_t queue; 1210 queueid_t queue_id; 1211 cmdline_fixed_string_t dump; 1212 cmdline_fixed_string_t sq_context; 1213 cmdline_fixed_string_t file_name; 1214 }; 1215 1216 cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_mlx5 = 1217 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, mlx5, 1218 "mlx5"); 1219 cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_port = 1220 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, port, 1221 "port"); 1222 cmdline_parse_token_num_t mlx5_cmd_dump_sq_context_options_port_id = 1223 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, port_id, 1224 RTE_UINT16); 1225 cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_queue = 1226 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, queue, 1227 "queue"); 1228 cmdline_parse_token_num_t mlx5_cmd_dump_sq_context_options_queue_id = 1229 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, queue_id, 1230 RTE_UINT16); 1231 cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_dump = 1232 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, dump, 1233 "dump"); 1234 cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_sq_context = 1235 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, sq_context, 1236 "sq_context"); 1237 cmdline_parse_token_string_t mlx5_cmd_dump_sq_context_options_file_name = 1238 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_sq_context_options, file_name, 1239 NULL); 1240 1241 static void 1242 mlx5_cmd_dump_sq_context_options_parsed(void *parsed_result, 1243 __rte_unused struct cmdline *cl, 1244 __rte_unused void *data) 1245 { 1246 struct mlx5_cmd_dump_sq_context_options *res = parsed_result; 1247 int ret; 1248 1249 ret = rte_pmd_mlx5_txq_dump_contexts(res->port_id, res->queue_id, res->file_name); 1250 1251 switch (ret) { 1252 case 0: 1253 break; 1254 case -EINVAL: 1255 fprintf(stderr, "invalid queue index (%u), out of range\n", 1256 res->queue_id); 1257 break; 1258 case -ENODEV: 1259 fprintf(stderr, "invalid port_id %u\n", res->port_id); 1260 break; 1261 case -EIO: 1262 fprintf(stderr, "File Access Error (%s)\n", strerror(rte_errno)); 1263 break; 1264 default: 1265 fprintf(stderr, "Unable to dump SQ/CQ HW Context (%s)\n", strerror(rte_errno)); 1266 } 1267 } 1268 1269 cmdline_parse_inst_t mlx5_cmd_dump_sq_context_options = { 1270 .f = mlx5_cmd_dump_sq_context_options_parsed, 1271 .data = NULL, 1272 .help_str = "mlx5 port <port_id> queue <queue_id> dump sq_context <file_name>", 1273 .tokens = { 1274 (void *)&mlx5_cmd_dump_sq_context_options_mlx5, 1275 (void *)&mlx5_cmd_dump_sq_context_options_port, 1276 (void *)&mlx5_cmd_dump_sq_context_options_port_id, 1277 (void *)&mlx5_cmd_dump_sq_context_options_queue, 1278 (void *)&mlx5_cmd_dump_sq_context_options_queue_id, 1279 (void *)&mlx5_cmd_dump_sq_context_options_dump, 1280 (void *)&mlx5_cmd_dump_sq_context_options_sq_context, 1281 (void *)&mlx5_cmd_dump_sq_context_options_file_name, 1282 NULL, 1283 } 1284 }; 1285 1286 /* Dump RQ Context for a given port/queue*/ 1287 struct mlx5_cmd_dump_rq_context_options { 1288 cmdline_fixed_string_t mlx5; 1289 cmdline_fixed_string_t port; 1290 portid_t port_id; 1291 cmdline_fixed_string_t queue; 1292 queueid_t queue_id; 1293 cmdline_fixed_string_t dump; 1294 cmdline_fixed_string_t rq_context; 1295 cmdline_fixed_string_t file_name; 1296 }; 1297 1298 cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_mlx5 = 1299 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, mlx5, 1300 "mlx5"); 1301 cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_port = 1302 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, port, 1303 "port"); 1304 cmdline_parse_token_num_t mlx5_cmd_dump_rq_context_options_port_id = 1305 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, port_id, 1306 RTE_UINT16); 1307 cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_queue = 1308 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, queue, 1309 "queue"); 1310 cmdline_parse_token_num_t mlx5_cmd_dump_rq_context_options_queue_id = 1311 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, queue_id, 1312 RTE_UINT16); 1313 cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_dump = 1314 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, dump, 1315 "dump"); 1316 cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_rq_context = 1317 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, rq_context, 1318 "rq_context"); 1319 cmdline_parse_token_string_t mlx5_cmd_dump_rq_context_options_file_name = 1320 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_dump_rq_context_options, file_name, 1321 NULL); 1322 1323 static void 1324 mlx5_cmd_dump_rq_context_options_parsed(void *parsed_result, 1325 __rte_unused struct cmdline *cl, 1326 __rte_unused void *data) 1327 { 1328 struct mlx5_cmd_dump_rq_context_options *res = parsed_result; 1329 int ret; 1330 1331 ret = rte_pmd_mlx5_rxq_dump_contexts(res->port_id, res->queue_id, res->file_name); 1332 1333 switch (ret) { 1334 case 0: 1335 break; 1336 case -EINVAL: 1337 fprintf(stderr, "invalid queue index (%u), out of range\n", 1338 res->queue_id); 1339 break; 1340 case -ENODEV: 1341 fprintf(stderr, "invalid port_id %u\n", res->port_id); 1342 break; 1343 case -EIO: 1344 fprintf(stderr, "File Access Error (%s)\n", strerror(rte_errno)); 1345 break; 1346 default: 1347 fprintf(stderr, "Unable to dump RQ/CQ HW Context (%s)\n", strerror(rte_errno)); 1348 } 1349 } 1350 1351 cmdline_parse_inst_t mlx5_cmd_dump_rq_context_options = { 1352 .f = mlx5_cmd_dump_rq_context_options_parsed, 1353 .data = NULL, 1354 .help_str = "mlx5 port <port_id> queue <queue_id> dump rq_context <file_name>", 1355 .tokens = { 1356 (void *)&mlx5_cmd_dump_rq_context_options_mlx5, 1357 (void *)&mlx5_cmd_dump_rq_context_options_port, 1358 (void *)&mlx5_cmd_dump_rq_context_options_port_id, 1359 (void *)&mlx5_cmd_dump_rq_context_options_queue, 1360 (void *)&mlx5_cmd_dump_rq_context_options_queue_id, 1361 (void *)&mlx5_cmd_dump_rq_context_options_dump, 1362 (void *)&mlx5_cmd_dump_rq_context_options_rq_context, 1363 (void *)&mlx5_cmd_dump_rq_context_options_file_name, 1364 NULL, 1365 } 1366 }; 1367 1368 static struct testpmd_driver_commands mlx5_driver_cmds = { 1369 .commands = { 1370 { 1371 .ctx = &mlx5_test_cmd_port_host_shaper, 1372 .help = "mlx5 set port (port_id) host_shaper avail_thresh_triggered (on|off)" 1373 "rate (rate_num):\n" 1374 " Set HOST_SHAPER avail_thresh_triggered and rate with port_id\n\n", 1375 }, 1376 #ifndef RTE_EXEC_ENV_WINDOWS 1377 { 1378 .ctx = &mlx5_cmd_operate_attach_port, 1379 .help = "mlx5 port attach (ident) socket=(path)\n" 1380 " Attach physical or virtual dev by pci address or virtual device name " 1381 "and add \"cmd_fd\" and \"pd_handle\" devargs before attaching\n\n", 1382 }, 1383 #endif 1384 { 1385 .ctx = &mlx5_cmd_map_ext_rxq, 1386 .help = "mlx5 port (port_id) ext_rxq map (sw_queue_id) (hw_queue_id)\n" 1387 " Map HW queue index (32-bit) to ethdev" 1388 " queue index (16-bit) for external RxQ\n\n", 1389 }, 1390 { 1391 .ctx = &mlx5_cmd_unmap_ext_rxq, 1392 .help = "mlx5 port (port_id) ext_rxq unmap (sw_queue_id)\n" 1393 " Unmap external Rx queue ethdev index mapping\n\n", 1394 }, 1395 { 1396 .ctx = &mlx5_cmd_set_flow_engine_mode, 1397 .help = "mlx5 set flow_engine (active|standby) [(flag)]\n" 1398 " Set flow_engine to the specific mode with flag.\n\n" 1399 }, 1400 { 1401 .ctx = &mlx5_cmd_set_tlv_option, 1402 .help = "mlx5 set tlv_option class (class_id) type " 1403 "(type_id) len (option_length) offset " 1404 "(sample_offset) sample_len (sample_length) " 1405 "class_mode (ignored|fixed|matchable) " 1406 "data (mask1) [(mask2) [...]]\n" 1407 " Set single GENEVE TLV option inside global list " 1408 "using later by apply command\n\n", 1409 }, 1410 { 1411 .ctx = &mlx5_cmd_list_tlv_options, 1412 .help = "mlx5 list tlv_options\n" 1413 " Print all GENEVE TLV options which are configured " 1414 "so far by TLV option set command\n\n", 1415 }, 1416 { 1417 .ctx = &mlx5_cmd_flush_tlv_options, 1418 .help = "mlx5 flush tlv_options [max (number options)]\n" 1419 " Clear all GENEVE TLV options which are configured " 1420 "so far by TLV option set command\n\n", 1421 }, 1422 { 1423 .ctx = &mlx5_cmd_apply_tlv_options, 1424 .help = "mlx5 port (port_id) apply tlv_options\n" 1425 " Create GENEVE TLV parser using option list which is " 1426 "configured before by TLV option set command\n\n", 1427 }, 1428 { 1429 .ctx = &mlx5_cmd_destroy_tlv_options, 1430 .help = "mlx5 port (port_id) destroy tlv_options\n" 1431 " Destroy GENEVE TLV parser\n\n", 1432 }, 1433 { 1434 .ctx = &mlx5_cmd_dump_sq_context_options, 1435 .help = "mlx5 port (port_id) queue (queue_id) dump sq_context (file_name)\n" 1436 " Dump mlx5 SQ Context\n\n", 1437 }, 1438 { 1439 .ctx = &mlx5_cmd_dump_rq_context_options, 1440 .help = "mlx5 port (port_id) queue (queue_id) dump rq_context (file_name)\n" 1441 " Dump mlx5 RQ Context\n\n", 1442 }, 1443 { 1444 .ctx = NULL, 1445 }, 1446 } 1447 }; 1448 TESTPMD_ADD_DRIVER_COMMANDS(mlx5_driver_cmds); 1449