1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #include <ctype.h> 6 #include <stdio.h> 7 #include <stdint.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 12 #include <rte_common.h> 13 #include <rte_ethdev.h> 14 #include <rte_ring.h> 15 #include <rte_swx_port_ethdev.h> 16 #include <rte_swx_port_ring.h> 17 #include <rte_swx_port_source_sink.h> 18 #include <rte_swx_port_fd.h> 19 #include <rte_swx_pipeline.h> 20 #include <rte_swx_ctl.h> 21 22 #include "cli.h" 23 24 #include "obj.h" 25 #include "thread.h" 26 27 #ifndef CMD_MAX_TOKENS 28 #define CMD_MAX_TOKENS 256 29 #endif 30 31 #ifndef MAX_LINE_SIZE 32 #define MAX_LINE_SIZE 2048 33 #endif 34 35 #define MSG_OUT_OF_MEMORY "Not enough memory.\n" 36 #define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n" 37 #define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n" 38 #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n" 39 #define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n" 40 #define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\".\n" 41 #define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n" 42 #define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n" 43 #define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n" 44 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n" 45 #define MSG_CMD_FAIL "Command \"%s\" failed.\n" 46 47 #define skip_white_spaces(pos) \ 48 ({ \ 49 __typeof__(pos) _p = (pos); \ 50 for ( ; isspace(*_p); _p++) \ 51 ; \ 52 _p; \ 53 }) 54 55 static int 56 parser_read_uint64(uint64_t *value, const char *p) 57 { 58 char *next; 59 uint64_t val; 60 61 p = skip_white_spaces(p); 62 if (!isdigit(*p)) 63 return -EINVAL; 64 65 val = strtoul(p, &next, 0); 66 if (p == next) 67 return -EINVAL; 68 69 p = next; 70 switch (*p) { 71 case 'T': 72 val *= 1024ULL; 73 /* fall through */ 74 case 'G': 75 val *= 1024ULL; 76 /* fall through */ 77 case 'M': 78 val *= 1024ULL; 79 /* fall through */ 80 case 'k': 81 case 'K': 82 val *= 1024ULL; 83 p++; 84 break; 85 } 86 87 p = skip_white_spaces(p); 88 if (*p != '\0') 89 return -EINVAL; 90 91 *value = val; 92 return 0; 93 } 94 95 static int 96 parser_read_uint32(uint32_t *value, const char *p) 97 { 98 uint64_t val = 0; 99 int ret = parser_read_uint64(&val, p); 100 101 if (ret < 0) 102 return ret; 103 104 if (val > UINT32_MAX) 105 return -ERANGE; 106 107 *value = val; 108 return 0; 109 } 110 111 #define PARSE_DELIMITER " \f\n\r\t\v" 112 113 static int 114 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens) 115 { 116 uint32_t i; 117 118 if ((string == NULL) || 119 (tokens == NULL) || 120 (*n_tokens < 1)) 121 return -EINVAL; 122 123 for (i = 0; i < *n_tokens; i++) { 124 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string); 125 if (tokens[i] == NULL) 126 break; 127 } 128 129 if ((i == *n_tokens) && strtok_r(string, PARSE_DELIMITER, &string)) 130 return -E2BIG; 131 132 *n_tokens = i; 133 return 0; 134 } 135 136 static int 137 is_comment(char *in) 138 { 139 if ((strlen(in) && index("!#%;", in[0])) || 140 (strncmp(in, "//", 2) == 0) || 141 (strncmp(in, "--", 2) == 0)) 142 return 1; 143 144 return 0; 145 } 146 147 static void 148 table_entry_free(struct rte_swx_table_entry *entry) 149 { 150 if (!entry) 151 return; 152 153 free(entry->key); 154 free(entry->key_mask); 155 free(entry->action_data); 156 free(entry); 157 } 158 159 static struct rte_swx_table_entry * 160 parse_table_entry(struct rte_swx_ctl_pipeline *p, 161 char *table_name, 162 char **tokens, 163 uint32_t n_tokens) 164 { 165 struct rte_swx_table_entry *entry; 166 char *line; 167 uint32_t i; 168 169 /* Buffer allocation. */ 170 line = malloc(MAX_LINE_SIZE); 171 if (!line) 172 return NULL; 173 174 /* Copy tokens to buffer. Since the tokens were initially part of a buffer of size 175 * MAX_LINE_LENGTH, it is guaranteed that putting back some of them into a buffer of the 176 * same size separated by a single space will not result in buffer overrun. 177 */ 178 line[0] = 0; 179 for (i = 0; i < n_tokens; i++) { 180 if (i) 181 strcat(line, " "); 182 183 strcat(line, tokens[i]); 184 } 185 186 /* Read the table entry from the input buffer. */ 187 entry = rte_swx_ctl_pipeline_table_entry_read(p, table_name, line, NULL); 188 189 /* Buffer free. */ 190 free(line); 191 192 return entry; 193 } 194 195 static const char cmd_mempool_help[] = 196 "mempool <mempool_name> " 197 "meta <mbuf_private_size> " 198 "pkt <pkt_buffer_size> " 199 "pool <pool_size> " 200 "cache <cache_size> " 201 "numa <numa_node>\n"; 202 203 static void 204 cmd_mempool(char **tokens, 205 uint32_t n_tokens, 206 char *out, 207 size_t out_size, 208 void *obj __rte_unused) 209 { 210 struct rte_mempool *mp; 211 char *mempool_name; 212 uint32_t mbuf_private_size, pkt_buffer_size, pool_size, cache_size, numa_node; 213 214 if (n_tokens != 12) { 215 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 216 return; 217 } 218 219 mempool_name = tokens[1]; 220 221 if (strcmp(tokens[2], "meta")) { 222 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meta"); 223 return; 224 } 225 226 if (parser_read_uint32(&mbuf_private_size, tokens[3])) { 227 snprintf(out, out_size, MSG_ARG_INVALID, "mbuf_private_size"); 228 return; 229 } 230 231 if (strcmp(tokens[4], "pkt")) { 232 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkt"); 233 return; 234 } 235 236 if (parser_read_uint32(&pkt_buffer_size, tokens[5])) { 237 snprintf(out, out_size, MSG_ARG_INVALID, "pkt_buffer_size"); 238 return; 239 } 240 241 if (strcmp(tokens[6], "pool")) { 242 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool"); 243 return; 244 } 245 246 if (parser_read_uint32(&pool_size, tokens[7])) { 247 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size"); 248 return; 249 } 250 251 if (strcmp(tokens[8], "cache")) { 252 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); 253 return; 254 } 255 256 if (parser_read_uint32(&cache_size, tokens[9])) { 257 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); 258 return; 259 } 260 261 if (strcmp(tokens[10], "numa")) { 262 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa"); 263 return; 264 } 265 266 if (parser_read_uint32(&numa_node, tokens[11])) { 267 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node"); 268 return; 269 } 270 271 mp = rte_pktmbuf_pool_create(mempool_name, 272 pool_size, 273 cache_size, 274 mbuf_private_size, 275 pkt_buffer_size, 276 numa_node); 277 if (!mp) { 278 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 279 return; 280 } 281 } 282 283 static const char cmd_ethdev_help[] = 284 "ethdev <ethdev_name>\n" 285 " rxq <n_queues> <queue_size> <mempool_name>\n" 286 " txq <n_queues> <queue_size>\n" 287 " promiscuous on | off\n" 288 " [rss <qid_0> ... <qid_n>]\n"; 289 290 static void 291 cmd_ethdev(char **tokens, 292 uint32_t n_tokens, 293 char *out, 294 size_t out_size, 295 void *obj __rte_unused) 296 { 297 struct ethdev_params p; 298 struct ethdev_params_rss rss; 299 char *name; 300 int status; 301 302 memset(&p, 0, sizeof(p)); 303 memset(&rss, 0, sizeof(rss)); 304 305 if (n_tokens < 11 || n_tokens > 12 + ETHDEV_RXQ_RSS_MAX) { 306 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 307 return; 308 } 309 name = tokens[1]; 310 311 if (strcmp(tokens[2], "rxq") != 0) { 312 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 313 return; 314 } 315 316 if (parser_read_uint32(&p.rx.n_queues, tokens[3]) != 0) { 317 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 318 return; 319 } 320 if (parser_read_uint32(&p.rx.queue_size, tokens[4]) != 0) { 321 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 322 return; 323 } 324 325 p.rx.mempool_name = tokens[5]; 326 327 if (strcmp(tokens[6], "txq") != 0) { 328 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 329 return; 330 } 331 332 if (parser_read_uint32(&p.tx.n_queues, tokens[7]) != 0) { 333 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 334 return; 335 } 336 337 if (parser_read_uint32(&p.tx.queue_size, tokens[8]) != 0) { 338 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 339 return; 340 } 341 342 if (strcmp(tokens[9], "promiscuous") != 0) { 343 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous"); 344 return; 345 } 346 347 if (strcmp(tokens[10], "on") == 0) 348 p.promiscuous = 1; 349 else if (strcmp(tokens[10], "off") == 0) 350 p.promiscuous = 0; 351 else { 352 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off"); 353 return; 354 } 355 356 /* RSS */ 357 p.rx.rss = NULL; 358 if (n_tokens > 11) { 359 uint32_t queue_id, i; 360 361 if (strcmp(tokens[11], "rss") != 0) { 362 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss"); 363 return; 364 } 365 366 p.rx.rss = &rss; 367 368 rss.n_queues = 0; 369 for (i = 12; i < n_tokens; i++) { 370 if (parser_read_uint32(&queue_id, tokens[i]) != 0) { 371 snprintf(out, out_size, MSG_ARG_INVALID, 372 "queue_id"); 373 return; 374 } 375 376 rss.queue_id[rss.n_queues] = queue_id; 377 rss.n_queues++; 378 } 379 } 380 381 status = ethdev_config(name, &p); 382 if (status) { 383 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 384 return; 385 } 386 } 387 388 static void 389 ethdev_show(uint16_t port_id, char **out, size_t *out_size) 390 { 391 char name[RTE_ETH_NAME_MAX_LEN]; 392 struct rte_eth_dev_info info; 393 struct rte_eth_stats stats; 394 struct rte_ether_addr addr; 395 struct rte_eth_link link; 396 uint32_t length; 397 uint16_t mtu = 0; 398 399 if (!rte_eth_dev_is_valid_port(port_id)) 400 return; 401 402 rte_eth_dev_get_name_by_port(port_id, name); 403 rte_eth_dev_info_get(port_id, &info); 404 rte_eth_stats_get(port_id, &stats); 405 rte_eth_macaddr_get(port_id, &addr); 406 rte_eth_link_get(port_id, &link); 407 rte_eth_dev_get_mtu(port_id, &mtu); 408 409 snprintf(*out, *out_size, 410 "%s: flags=<%s> mtu %u\n" 411 "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n" 412 "\tport# %u speed %s\n" 413 "\tRX packets %" PRIu64" bytes %" PRIu64"\n" 414 "\tRX errors %" PRIu64" missed %" PRIu64" no-mbuf %" PRIu64"\n" 415 "\tTX packets %" PRIu64" bytes %" PRIu64"\n" 416 "\tTX errors %" PRIu64"\n\n", 417 name, 418 link.link_status ? "UP" : "DOWN", 419 mtu, 420 RTE_ETHER_ADDR_BYTES(&addr), 421 info.nb_rx_queues, 422 info.nb_tx_queues, 423 port_id, 424 rte_eth_link_speed_to_str(link.link_speed), 425 stats.ipackets, 426 stats.ibytes, 427 stats.ierrors, 428 stats.imissed, 429 stats.rx_nombuf, 430 stats.opackets, 431 stats.obytes, 432 stats.oerrors); 433 434 length = strlen(*out); 435 *out_size -= length; 436 *out += length; 437 } 438 439 440 static char cmd_ethdev_show_help[] = 441 "ethdev show [ <ethdev_name> ]\n"; 442 443 static void 444 cmd_ethdev_show(char **tokens, 445 uint32_t n_tokens, 446 char *out, 447 size_t out_size, 448 void *obj __rte_unused) 449 { 450 uint16_t port_id; 451 452 if (n_tokens != 2 && n_tokens != 3) { 453 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 454 return; 455 } 456 457 /* Single device. */ 458 if (n_tokens == 3) { 459 int status; 460 461 status = rte_eth_dev_get_port_by_name(tokens[2], &port_id); 462 if (status) 463 snprintf(out, out_size, "Error: Invalid Ethernet device name.\n"); 464 465 ethdev_show(port_id, &out, &out_size); 466 return; 467 } 468 469 /* All devices. */ 470 for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) 471 if (rte_eth_dev_is_valid_port(port_id)) 472 ethdev_show(port_id, &out, &out_size); 473 } 474 475 static const char cmd_ring_help[] = 476 "ring <ring_name> size <size> numa <numa_node>\n"; 477 478 static void 479 cmd_ring(char **tokens, 480 uint32_t n_tokens, 481 char *out, 482 size_t out_size, 483 void *obj __rte_unused) 484 { 485 struct rte_ring *r; 486 char *name; 487 uint32_t size, numa_node; 488 489 if (n_tokens != 6) { 490 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 491 return; 492 } 493 494 name = tokens[1]; 495 496 if (strcmp(tokens[2], "size")) { 497 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 498 return; 499 } 500 501 if (parser_read_uint32(&size, tokens[3])) { 502 snprintf(out, out_size, MSG_ARG_INVALID, "size"); 503 return; 504 } 505 506 if (strcmp(tokens[4], "numa")) { 507 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa"); 508 return; 509 } 510 511 if (parser_read_uint32(&numa_node, tokens[5])) { 512 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node"); 513 return; 514 } 515 516 r = rte_ring_create( 517 name, 518 size, 519 (int)numa_node, 520 RING_F_SP_ENQ | RING_F_SC_DEQ); 521 if (!r) { 522 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 523 return; 524 } 525 } 526 527 static const char cmd_cryptodev_help[] = 528 "cryptodev <cryptodev_name> queues <n_queue_pairs> qsize <queue_size>\n"; 529 530 static void 531 cmd_cryptodev(char **tokens, 532 uint32_t n_tokens, 533 char *out, 534 size_t out_size, 535 void *obj __rte_unused) 536 { 537 struct cryptodev_params params; 538 char *cryptodev_name; 539 int status; 540 541 if (n_tokens != 6) { 542 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 543 return; 544 } 545 546 if (strcmp(tokens[0], "cryptodev")) { 547 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cryptodev"); 548 return; 549 } 550 551 cryptodev_name = tokens[1]; 552 553 if (strcmp(tokens[2], "queues")) { 554 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "queues"); 555 return; 556 } 557 558 if (parser_read_uint32(¶ms.n_queue_pairs, tokens[3])) { 559 snprintf(out, out_size, MSG_ARG_INVALID, "n_queue_pairs"); 560 return; 561 } 562 563 if (strcmp(tokens[4], "qsize")) { 564 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize"); 565 return; 566 } 567 568 569 if (parser_read_uint32(¶ms.queue_size, tokens[5])) { 570 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 571 return; 572 } 573 574 status = cryptodev_config(cryptodev_name, ¶ms); 575 if (status) 576 snprintf(out, out_size, "Crypto device configuration failed (%d).\n", status); 577 } 578 579 static const char cmd_pipeline_codegen_help[] = 580 "pipeline codegen <spec_file> <code_file>\n"; 581 582 static void 583 cmd_pipeline_codegen(char **tokens, 584 uint32_t n_tokens, 585 char *out, 586 size_t out_size, 587 void *obj __rte_unused) 588 { 589 FILE *spec_file = NULL; 590 FILE *code_file = NULL; 591 uint32_t err_line; 592 const char *err_msg; 593 int status; 594 595 if (n_tokens != 4) { 596 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 597 return; 598 } 599 600 spec_file = fopen(tokens[2], "r"); 601 if (!spec_file) { 602 snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]); 603 return; 604 } 605 606 code_file = fopen(tokens[3], "w"); 607 if (!code_file) { 608 snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]); 609 fclose(spec_file); 610 return; 611 } 612 613 status = rte_swx_pipeline_codegen(spec_file, 614 code_file, 615 &err_line, 616 &err_msg); 617 618 fclose(spec_file); 619 fclose(code_file); 620 621 if (status) { 622 snprintf(out, out_size, "Error %d at line %u: %s\n.", 623 status, err_line, err_msg); 624 return; 625 } 626 } 627 628 static const char cmd_pipeline_libbuild_help[] = 629 "pipeline libbuild <code_file> <lib_file>\n"; 630 631 static void 632 cmd_pipeline_libbuild(char **tokens, 633 uint32_t n_tokens, 634 char *out, 635 size_t out_size, 636 void *obj __rte_unused) 637 { 638 char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL; 639 char *install_dir, *cwd = NULL, *buffer = NULL; 640 size_t length; 641 int status = 0; 642 643 if (n_tokens != 4) { 644 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 645 goto free; 646 } 647 648 install_dir = getenv("RTE_INSTALL_DIR"); 649 if (!install_dir) { 650 cwd = malloc(MAX_LINE_SIZE); 651 if (!cwd) { 652 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 653 goto free; 654 } 655 656 install_dir = getcwd(cwd, MAX_LINE_SIZE); 657 if (!install_dir) { 658 snprintf(out, out_size, "Error: Path too long.\n"); 659 goto free; 660 } 661 } 662 663 snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir); 664 out_size -= strlen(out); 665 out += strlen(out); 666 667 code_file = tokens[2]; 668 length = strnlen(code_file, MAX_LINE_SIZE); 669 if ((length < 3) || 670 (code_file[length - 2] != '.') || 671 (code_file[length - 1] != 'c')) { 672 snprintf(out, out_size, MSG_ARG_INVALID, "code_file"); 673 goto free; 674 } 675 676 lib_file = tokens[3]; 677 length = strnlen(lib_file, MAX_LINE_SIZE); 678 if ((length < 4) || 679 (lib_file[length - 3] != '.') || 680 (lib_file[length - 2] != 's') || 681 (lib_file[length - 1] != 'o')) { 682 snprintf(out, out_size, MSG_ARG_INVALID, "lib_file"); 683 goto free; 684 } 685 686 obj_file = malloc(length); 687 log_file = malloc(length + 2); 688 if (!obj_file || !log_file) { 689 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 690 goto free; 691 } 692 693 memcpy(obj_file, lib_file, length - 2); 694 obj_file[length - 2] = 'o'; 695 obj_file[length - 1] = 0; 696 697 memcpy(log_file, lib_file, length - 2); 698 log_file[length - 2] = 'l'; 699 log_file[length - 1] = 'o'; 700 log_file[length] = 'g'; 701 log_file[length + 1] = 0; 702 703 buffer = malloc(MAX_LINE_SIZE); 704 if (!buffer) { 705 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 706 goto free; 707 } 708 709 snprintf(buffer, 710 MAX_LINE_SIZE, 711 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s " 712 "-I %s/lib/pipeline " 713 "-I %s/lib/eal/include " 714 "-I %s/lib/eal/x86/include " 715 "-I %s/lib/eal/include/generic " 716 "-I %s/lib/meter " 717 "-I %s/lib/port " 718 "-I %s/lib/table " 719 "-I %s/lib/pipeline " 720 "-I %s/config " 721 "-I %s/build " 722 "-I %s/lib/eal/linux/include " 723 ">%s 2>&1 " 724 "&& " 725 "gcc -shared %s -o %s " 726 ">>%s 2>&1", 727 obj_file, 728 code_file, 729 install_dir, 730 install_dir, 731 install_dir, 732 install_dir, 733 install_dir, 734 install_dir, 735 install_dir, 736 install_dir, 737 install_dir, 738 install_dir, 739 install_dir, 740 log_file, 741 obj_file, 742 lib_file, 743 log_file); 744 745 status = system(buffer); 746 if (status) { 747 snprintf(out, 748 out_size, 749 "Library build failed, see file \"%s\" for details.\n", 750 log_file); 751 goto free; 752 } 753 754 free: 755 free(cwd); 756 free(obj_file); 757 free(log_file); 758 free(buffer); 759 } 760 761 static const char cmd_pipeline_build_help[] = 762 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n"; 763 764 static void 765 cmd_pipeline_build(char **tokens, 766 uint32_t n_tokens, 767 char *out, 768 size_t out_size, 769 void *obj __rte_unused) 770 { 771 struct rte_swx_pipeline *p = NULL; 772 struct rte_swx_ctl_pipeline *ctl = NULL; 773 char *pipeline_name, *lib_file_name, *iospec_file_name; 774 FILE *iospec_file = NULL; 775 uint32_t numa_node = 0; 776 int status = 0; 777 778 /* Parsing. */ 779 if (n_tokens != 9) { 780 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 781 return; 782 } 783 784 pipeline_name = tokens[1]; 785 786 if (strcmp(tokens[2], "build")) { 787 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "build"); 788 return; 789 } 790 791 if (strcmp(tokens[3], "lib")) { 792 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "lib"); 793 return; 794 } 795 796 lib_file_name = tokens[4]; 797 798 if (strcmp(tokens[5], "io")) { 799 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "io"); 800 return; 801 } 802 803 iospec_file_name = tokens[6]; 804 805 if (strcmp(tokens[7], "numa")) { 806 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa"); 807 return; 808 } 809 810 if (parser_read_uint32(&numa_node, tokens[8])) { 811 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node"); 812 return; 813 } 814 815 /* I/O spec file open. */ 816 iospec_file = fopen(iospec_file_name, "r"); 817 if (!iospec_file) { 818 snprintf(out, out_size, "Cannot open file \"%s\".\n", iospec_file_name); 819 return; 820 } 821 822 status = rte_swx_pipeline_build_from_lib(&p, 823 pipeline_name, 824 lib_file_name, 825 iospec_file, 826 (int)numa_node); 827 if (status) { 828 snprintf(out, out_size, "Pipeline build failed (%d).", status); 829 goto free; 830 } 831 832 ctl = rte_swx_ctl_pipeline_create(p); 833 if (!ctl) { 834 snprintf(out, out_size, "Pipeline control create failed."); 835 goto free; 836 } 837 838 free: 839 if (status) 840 rte_swx_pipeline_free(p); 841 842 if (iospec_file) 843 fclose(iospec_file); 844 } 845 846 static int 847 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p, 848 const char *table_name, 849 FILE *file, 850 uint32_t *file_line_number) 851 { 852 char *line = NULL; 853 uint32_t line_id = 0; 854 int status = 0; 855 856 /* Buffer allocation. */ 857 line = malloc(MAX_LINE_SIZE); 858 if (!line) 859 return -ENOMEM; 860 861 /* File read. */ 862 for (line_id = 1; ; line_id++) { 863 struct rte_swx_table_entry *entry; 864 int is_blank_or_comment; 865 866 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 867 break; 868 869 entry = rte_swx_ctl_pipeline_table_entry_read(p, 870 table_name, 871 line, 872 &is_blank_or_comment); 873 if (!entry) { 874 if (is_blank_or_comment) 875 continue; 876 877 status = -EINVAL; 878 goto error; 879 } 880 881 status = rte_swx_ctl_pipeline_table_entry_add(p, 882 table_name, 883 entry); 884 table_entry_free(entry); 885 if (status) 886 goto error; 887 } 888 889 error: 890 free(line); 891 *file_line_number = line_id; 892 return status; 893 } 894 895 static const char cmd_pipeline_table_add_help[] = 896 "pipeline <pipeline_name> table <table_name> add <file_name>\n"; 897 898 static void 899 cmd_pipeline_table_add(char **tokens, 900 uint32_t n_tokens, 901 char *out, 902 size_t out_size, 903 void *obj __rte_unused) 904 { 905 struct rte_swx_ctl_pipeline *ctl; 906 char *pipeline_name, *table_name, *file_name; 907 FILE *file = NULL; 908 uint32_t file_line_number = 0; 909 int status; 910 911 if (n_tokens != 6) { 912 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 913 return; 914 } 915 916 pipeline_name = tokens[1]; 917 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 918 if (!ctl) { 919 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 920 return; 921 } 922 923 table_name = tokens[3]; 924 925 file_name = tokens[5]; 926 file = fopen(file_name, "r"); 927 if (!file) { 928 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 929 return; 930 } 931 932 status = pipeline_table_entries_add(ctl, 933 table_name, 934 file, 935 &file_line_number); 936 if (status) 937 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 938 file_name, 939 file_line_number); 940 941 fclose(file); 942 } 943 944 static int 945 pipeline_table_entries_delete(struct rte_swx_ctl_pipeline *p, 946 const char *table_name, 947 FILE *file, 948 uint32_t *file_line_number) 949 { 950 char *line = NULL; 951 uint32_t line_id = 0; 952 int status = 0; 953 954 /* Buffer allocation. */ 955 line = malloc(MAX_LINE_SIZE); 956 if (!line) 957 return -ENOMEM; 958 959 /* File read. */ 960 for (line_id = 1; ; line_id++) { 961 struct rte_swx_table_entry *entry; 962 int is_blank_or_comment; 963 964 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 965 break; 966 967 entry = rte_swx_ctl_pipeline_table_entry_read(p, 968 table_name, 969 line, 970 &is_blank_or_comment); 971 if (!entry) { 972 if (is_blank_or_comment) 973 continue; 974 975 status = -EINVAL; 976 goto error; 977 } 978 979 status = rte_swx_ctl_pipeline_table_entry_delete(p, 980 table_name, 981 entry); 982 table_entry_free(entry); 983 if (status) 984 goto error; 985 } 986 987 error: 988 *file_line_number = line_id; 989 free(line); 990 return status; 991 } 992 993 static const char cmd_pipeline_table_delete_help[] = 994 "pipeline <pipeline_name> table <table_name> delete <file_name>\n"; 995 996 static void 997 cmd_pipeline_table_delete(char **tokens, 998 uint32_t n_tokens, 999 char *out, 1000 size_t out_size, 1001 void *obj __rte_unused) 1002 { 1003 struct rte_swx_ctl_pipeline *ctl; 1004 char *pipeline_name, *table_name, *file_name; 1005 FILE *file = NULL; 1006 uint32_t file_line_number = 0; 1007 int status; 1008 1009 if (n_tokens != 6) { 1010 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1011 return; 1012 } 1013 1014 pipeline_name = tokens[1]; 1015 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1016 if (!ctl) { 1017 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1018 return; 1019 } 1020 1021 table_name = tokens[3]; 1022 1023 file_name = tokens[5]; 1024 file = fopen(file_name, "r"); 1025 if (!file) { 1026 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1027 return; 1028 } 1029 1030 status = pipeline_table_entries_delete(ctl, 1031 table_name, 1032 file, 1033 &file_line_number); 1034 if (status) 1035 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1036 file_name, 1037 file_line_number); 1038 1039 fclose(file); 1040 } 1041 1042 static int 1043 pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *p, 1044 const char *table_name, 1045 FILE *file, 1046 uint32_t *file_line_number) 1047 { 1048 char *line = NULL; 1049 uint32_t line_id = 0; 1050 int status = 0; 1051 1052 /* Buffer allocation. */ 1053 line = malloc(MAX_LINE_SIZE); 1054 if (!line) 1055 return -ENOMEM; 1056 1057 /* File read. */ 1058 for (line_id = 1; ; line_id++) { 1059 struct rte_swx_table_entry *entry; 1060 int is_blank_or_comment; 1061 1062 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1063 break; 1064 1065 entry = rte_swx_ctl_pipeline_table_entry_read(p, 1066 table_name, 1067 line, 1068 &is_blank_or_comment); 1069 if (!entry) { 1070 if (is_blank_or_comment) 1071 continue; 1072 1073 status = -EINVAL; 1074 goto error; 1075 } 1076 1077 status = rte_swx_ctl_pipeline_table_default_entry_add(p, 1078 table_name, 1079 entry); 1080 table_entry_free(entry); 1081 if (status) 1082 goto error; 1083 } 1084 1085 error: 1086 *file_line_number = line_id; 1087 free(line); 1088 return status; 1089 } 1090 1091 static const char cmd_pipeline_table_default_help[] = 1092 "pipeline <pipeline_name> table <table_name> default <file_name>\n"; 1093 1094 static void 1095 cmd_pipeline_table_default(char **tokens, 1096 uint32_t n_tokens, 1097 char *out, 1098 size_t out_size, 1099 void *obj __rte_unused) 1100 { 1101 struct rte_swx_ctl_pipeline *ctl; 1102 char *pipeline_name, *table_name, *file_name; 1103 FILE *file = NULL; 1104 uint32_t file_line_number = 0; 1105 int status; 1106 1107 if (n_tokens != 6) { 1108 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1109 return; 1110 } 1111 1112 pipeline_name = tokens[1]; 1113 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1114 if (!ctl) { 1115 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1116 return; 1117 } 1118 1119 table_name = tokens[3]; 1120 1121 file_name = tokens[5]; 1122 file = fopen(file_name, "r"); 1123 if (!file) { 1124 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1125 return; 1126 } 1127 1128 status = pipeline_table_default_entry_add(ctl, 1129 table_name, 1130 file, 1131 &file_line_number); 1132 if (status) 1133 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1134 file_name, 1135 file_line_number); 1136 1137 fclose(file); 1138 } 1139 1140 static const char cmd_pipeline_table_show_help[] = 1141 "pipeline <pipeline_name> table <table_name> show [filename]\n"; 1142 1143 static void 1144 cmd_pipeline_table_show(char **tokens, 1145 uint32_t n_tokens, 1146 char *out, 1147 size_t out_size, 1148 void *obj __rte_unused) 1149 { 1150 struct rte_swx_ctl_pipeline *ctl; 1151 char *pipeline_name, *table_name; 1152 FILE *file = NULL; 1153 int status; 1154 1155 if (n_tokens != 5 && n_tokens != 6) { 1156 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1157 return; 1158 } 1159 1160 pipeline_name = tokens[1]; 1161 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1162 if (!ctl) { 1163 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1164 return; 1165 } 1166 1167 table_name = tokens[3]; 1168 file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout; 1169 if (!file) { 1170 snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]); 1171 return; 1172 } 1173 1174 status = rte_swx_ctl_pipeline_table_fprintf(file, ctl, table_name); 1175 if (status) 1176 snprintf(out, out_size, MSG_ARG_INVALID, "table_name"); 1177 1178 if (file) 1179 fclose(file); 1180 } 1181 1182 static const char cmd_pipeline_selector_group_add_help[] = 1183 "pipeline <pipeline_name> selector <selector_name> group add\n"; 1184 1185 static void 1186 cmd_pipeline_selector_group_add(char **tokens, 1187 uint32_t n_tokens, 1188 char *out, 1189 size_t out_size, 1190 void *obj __rte_unused) 1191 { 1192 struct rte_swx_ctl_pipeline *ctl; 1193 char *pipeline_name, *selector_name; 1194 uint32_t group_id; 1195 int status; 1196 1197 if (n_tokens != 6) { 1198 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1199 return; 1200 } 1201 1202 pipeline_name = tokens[1]; 1203 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1204 if (!ctl) { 1205 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1206 return; 1207 } 1208 1209 if (strcmp(tokens[2], "selector") != 0) { 1210 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1211 return; 1212 } 1213 1214 selector_name = tokens[3]; 1215 1216 if (strcmp(tokens[4], "group") || 1217 strcmp(tokens[5], "add")) { 1218 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add"); 1219 return; 1220 } 1221 1222 status = rte_swx_ctl_pipeline_selector_group_add(ctl, 1223 selector_name, 1224 &group_id); 1225 if (status) 1226 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1227 else 1228 snprintf(out, out_size, "Group ID: %u\n", group_id); 1229 } 1230 1231 static const char cmd_pipeline_selector_group_delete_help[] = 1232 "pipeline <pipeline_name> selector <selector_name> group delete <group_id>\n"; 1233 1234 static void 1235 cmd_pipeline_selector_group_delete(char **tokens, 1236 uint32_t n_tokens, 1237 char *out, 1238 size_t out_size, 1239 void *obj __rte_unused) 1240 { 1241 struct rte_swx_ctl_pipeline *ctl; 1242 char *pipeline_name, *selector_name; 1243 uint32_t group_id; 1244 int status; 1245 1246 if (n_tokens != 7) { 1247 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1248 return; 1249 } 1250 1251 pipeline_name = tokens[1]; 1252 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1253 if (!ctl) { 1254 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1255 return; 1256 } 1257 1258 if (strcmp(tokens[2], "selector") != 0) { 1259 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1260 return; 1261 } 1262 1263 selector_name = tokens[3]; 1264 1265 if (strcmp(tokens[4], "group") || 1266 strcmp(tokens[5], "delete")) { 1267 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete"); 1268 return; 1269 } 1270 1271 if (parser_read_uint32(&group_id, tokens[6]) != 0) { 1272 snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); 1273 return; 1274 } 1275 1276 status = rte_swx_ctl_pipeline_selector_group_delete(ctl, 1277 selector_name, 1278 group_id); 1279 if (status) 1280 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1281 } 1282 1283 #define GROUP_MEMBER_INFO_TOKENS_MAX 6 1284 1285 static int 1286 token_is_comment(const char *token) 1287 { 1288 if ((token[0] == '#') || 1289 (token[0] == ';') || 1290 ((token[0] == '/') && (token[1] == '/'))) 1291 return 1; /* TRUE. */ 1292 1293 return 0; /* FALSE. */ 1294 } 1295 1296 static int 1297 pipeline_selector_group_member_read(const char *string, 1298 uint32_t *group_id, 1299 uint32_t *member_id, 1300 uint32_t *weight, 1301 int *is_blank_or_comment) 1302 { 1303 char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens; 1304 char *s0 = NULL, *s; 1305 uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0; 1306 int blank_or_comment = 0; 1307 1308 /* Check input arguments. */ 1309 if (!string || !string[0]) 1310 goto error; 1311 1312 /* Memory allocation. */ 1313 s0 = strdup(string); 1314 if (!s0) 1315 goto error; 1316 1317 /* Parse the string into tokens. */ 1318 for (s = s0; ; ) { 1319 char *token; 1320 1321 token = strtok_r(s, " \f\n\r\t\v", &s); 1322 if (!token || token_is_comment(token)) 1323 break; 1324 1325 if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX) 1326 goto error; 1327 1328 token_array[n_tokens] = token; 1329 n_tokens++; 1330 } 1331 1332 if (!n_tokens) { 1333 blank_or_comment = 1; 1334 goto error; 1335 } 1336 1337 tokens = token_array; 1338 1339 if (n_tokens < 4 || 1340 strcmp(tokens[0], "group") || 1341 strcmp(tokens[2], "member")) 1342 goto error; 1343 1344 /* 1345 * Group ID. 1346 */ 1347 if (parser_read_uint32(&group_id_val, tokens[1]) != 0) 1348 goto error; 1349 *group_id = group_id_val; 1350 1351 /* 1352 * Member ID. 1353 */ 1354 if (parser_read_uint32(&member_id_val, tokens[3]) != 0) 1355 goto error; 1356 *member_id = member_id_val; 1357 1358 tokens += 4; 1359 n_tokens -= 4; 1360 1361 /* 1362 * Weight. 1363 */ 1364 if (n_tokens && !strcmp(tokens[0], "weight")) { 1365 if (n_tokens < 2) 1366 goto error; 1367 1368 if (parser_read_uint32(&weight_val, tokens[1]) != 0) 1369 goto error; 1370 *weight = weight_val; 1371 1372 tokens += 2; 1373 n_tokens -= 2; 1374 } 1375 1376 if (n_tokens) 1377 goto error; 1378 1379 free(s0); 1380 return 0; 1381 1382 error: 1383 free(s0); 1384 if (is_blank_or_comment) 1385 *is_blank_or_comment = blank_or_comment; 1386 return -EINVAL; 1387 } 1388 1389 static int 1390 pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p, 1391 const char *selector_name, 1392 FILE *file, 1393 uint32_t *file_line_number) 1394 { 1395 char *line = NULL; 1396 uint32_t line_id = 0; 1397 int status = 0; 1398 1399 /* Buffer allocation. */ 1400 line = malloc(MAX_LINE_SIZE); 1401 if (!line) 1402 return -ENOMEM; 1403 1404 /* File read. */ 1405 for (line_id = 1; ; line_id++) { 1406 uint32_t group_id, member_id, weight; 1407 int is_blank_or_comment; 1408 1409 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1410 break; 1411 1412 status = pipeline_selector_group_member_read(line, 1413 &group_id, 1414 &member_id, 1415 &weight, 1416 &is_blank_or_comment); 1417 if (status) { 1418 if (is_blank_or_comment) 1419 continue; 1420 1421 goto error; 1422 } 1423 1424 status = rte_swx_ctl_pipeline_selector_group_member_add(p, 1425 selector_name, 1426 group_id, 1427 member_id, 1428 weight); 1429 if (status) 1430 goto error; 1431 } 1432 1433 error: 1434 free(line); 1435 *file_line_number = line_id; 1436 return status; 1437 } 1438 1439 static const char cmd_pipeline_selector_group_member_add_help[] = 1440 "pipeline <pipeline_name> selector <selector_name> group member add <file_name>"; 1441 1442 static void 1443 cmd_pipeline_selector_group_member_add(char **tokens, 1444 uint32_t n_tokens, 1445 char *out, 1446 size_t out_size, 1447 void *obj __rte_unused) 1448 { 1449 struct rte_swx_ctl_pipeline *ctl; 1450 char *pipeline_name, *selector_name, *file_name; 1451 FILE *file = NULL; 1452 uint32_t file_line_number = 0; 1453 int status; 1454 1455 if (n_tokens != 8) { 1456 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1457 return; 1458 } 1459 1460 pipeline_name = tokens[1]; 1461 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1462 if (!ctl) { 1463 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1464 return; 1465 } 1466 1467 if (strcmp(tokens[2], "selector") != 0) { 1468 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1469 return; 1470 } 1471 1472 selector_name = tokens[3]; 1473 1474 if (strcmp(tokens[4], "group") || 1475 strcmp(tokens[5], "member") || 1476 strcmp(tokens[6], "add")) { 1477 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add"); 1478 return; 1479 } 1480 1481 file_name = tokens[7]; 1482 file = fopen(file_name, "r"); 1483 if (!file) { 1484 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1485 return; 1486 } 1487 1488 status = pipeline_selector_group_members_add(ctl, 1489 selector_name, 1490 file, 1491 &file_line_number); 1492 if (status) 1493 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1494 file_name, 1495 file_line_number); 1496 1497 fclose(file); 1498 } 1499 1500 static int 1501 pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p, 1502 const char *selector_name, 1503 FILE *file, 1504 uint32_t *file_line_number) 1505 { 1506 char *line = NULL; 1507 uint32_t line_id = 0; 1508 int status = 0; 1509 1510 /* Buffer allocation. */ 1511 line = malloc(MAX_LINE_SIZE); 1512 if (!line) 1513 return -ENOMEM; 1514 1515 /* File read. */ 1516 for (line_id = 1; ; line_id++) { 1517 uint32_t group_id, member_id, weight; 1518 int is_blank_or_comment; 1519 1520 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1521 break; 1522 1523 status = pipeline_selector_group_member_read(line, 1524 &group_id, 1525 &member_id, 1526 &weight, 1527 &is_blank_or_comment); 1528 if (status) { 1529 if (is_blank_or_comment) 1530 continue; 1531 1532 goto error; 1533 } 1534 1535 status = rte_swx_ctl_pipeline_selector_group_member_delete(p, 1536 selector_name, 1537 group_id, 1538 member_id); 1539 if (status) 1540 goto error; 1541 } 1542 1543 error: 1544 free(line); 1545 *file_line_number = line_id; 1546 return status; 1547 } 1548 1549 static const char cmd_pipeline_selector_group_member_delete_help[] = 1550 "pipeline <pipeline_name> selector <selector_name> group member delete <file_name>"; 1551 1552 static void 1553 cmd_pipeline_selector_group_member_delete(char **tokens, 1554 uint32_t n_tokens, 1555 char *out, 1556 size_t out_size, 1557 void *obj __rte_unused) 1558 { 1559 struct rte_swx_ctl_pipeline *ctl; 1560 char *pipeline_name, *selector_name, *file_name; 1561 FILE *file = NULL; 1562 uint32_t file_line_number = 0; 1563 int status; 1564 1565 if (n_tokens != 8) { 1566 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1567 return; 1568 } 1569 1570 pipeline_name = tokens[1]; 1571 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1572 if (!ctl) { 1573 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1574 return; 1575 } 1576 1577 if (strcmp(tokens[2], "selector") != 0) { 1578 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1579 return; 1580 } 1581 1582 selector_name = tokens[3]; 1583 1584 if (strcmp(tokens[4], "group") || 1585 strcmp(tokens[5], "member") || 1586 strcmp(tokens[6], "delete")) { 1587 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete"); 1588 return; 1589 } 1590 1591 file_name = tokens[7]; 1592 file = fopen(file_name, "r"); 1593 if (!file) { 1594 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1595 return; 1596 } 1597 1598 status = pipeline_selector_group_members_delete(ctl, 1599 selector_name, 1600 file, 1601 &file_line_number); 1602 if (status) 1603 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1604 file_name, 1605 file_line_number); 1606 1607 fclose(file); 1608 } 1609 1610 static const char cmd_pipeline_selector_show_help[] = 1611 "pipeline <pipeline_name> selector <selector_name> show [filename]\n"; 1612 1613 static void 1614 cmd_pipeline_selector_show(char **tokens, 1615 uint32_t n_tokens, 1616 char *out, 1617 size_t out_size, 1618 void *obj __rte_unused) 1619 { 1620 struct rte_swx_ctl_pipeline *ctl; 1621 char *pipeline_name, *selector_name; 1622 FILE *file = NULL; 1623 int status; 1624 1625 if (n_tokens != 5 && n_tokens != 6) { 1626 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1627 return; 1628 } 1629 1630 pipeline_name = tokens[1]; 1631 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1632 if (!ctl) { 1633 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1634 return; 1635 } 1636 1637 selector_name = tokens[3]; 1638 1639 file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout; 1640 if (!file) { 1641 snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]); 1642 return; 1643 } 1644 1645 status = rte_swx_ctl_pipeline_selector_fprintf(file, ctl, selector_name); 1646 if (status) 1647 snprintf(out, out_size, MSG_ARG_INVALID, "selector_name"); 1648 1649 if (file) 1650 fclose(file); 1651 } 1652 1653 static int 1654 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p, 1655 const char *learner_name, 1656 FILE *file, 1657 uint32_t *file_line_number) 1658 { 1659 char *line = NULL; 1660 uint32_t line_id = 0; 1661 int status = 0; 1662 1663 /* Buffer allocation. */ 1664 line = malloc(MAX_LINE_SIZE); 1665 if (!line) 1666 return -ENOMEM; 1667 1668 /* File read. */ 1669 for (line_id = 1; ; line_id++) { 1670 struct rte_swx_table_entry *entry; 1671 int is_blank_or_comment; 1672 1673 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1674 break; 1675 1676 entry = rte_swx_ctl_pipeline_learner_default_entry_read(p, 1677 learner_name, 1678 line, 1679 &is_blank_or_comment); 1680 if (!entry) { 1681 if (is_blank_or_comment) 1682 continue; 1683 1684 status = -EINVAL; 1685 goto error; 1686 } 1687 1688 status = rte_swx_ctl_pipeline_learner_default_entry_add(p, 1689 learner_name, 1690 entry); 1691 table_entry_free(entry); 1692 if (status) 1693 goto error; 1694 } 1695 1696 error: 1697 *file_line_number = line_id; 1698 free(line); 1699 return status; 1700 } 1701 1702 static const char cmd_pipeline_learner_default_help[] = 1703 "pipeline <pipeline_name> learner <learner_name> default <file_name>\n"; 1704 1705 static void 1706 cmd_pipeline_learner_default(char **tokens, 1707 uint32_t n_tokens, 1708 char *out, 1709 size_t out_size, 1710 void *obj __rte_unused) 1711 { 1712 struct rte_swx_ctl_pipeline *ctl; 1713 char *pipeline_name, *learner_name, *file_name; 1714 FILE *file = NULL; 1715 uint32_t file_line_number = 0; 1716 int status; 1717 1718 if (n_tokens != 6) { 1719 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1720 return; 1721 } 1722 1723 pipeline_name = tokens[1]; 1724 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1725 if (!ctl) { 1726 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1727 return; 1728 } 1729 1730 learner_name = tokens[3]; 1731 1732 file_name = tokens[5]; 1733 file = fopen(file_name, "r"); 1734 if (!file) { 1735 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1736 return; 1737 } 1738 1739 status = pipeline_learner_default_entry_add(ctl, 1740 learner_name, 1741 file, 1742 &file_line_number); 1743 if (status) 1744 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1745 file_name, 1746 file_line_number); 1747 1748 fclose(file); 1749 } 1750 1751 static const char cmd_pipeline_commit_help[] = 1752 "pipeline <pipeline_name> commit\n"; 1753 1754 static void 1755 cmd_pipeline_commit(char **tokens, 1756 uint32_t n_tokens, 1757 char *out, 1758 size_t out_size, 1759 void *obj __rte_unused) 1760 { 1761 struct rte_swx_ctl_pipeline *ctl; 1762 char *pipeline_name; 1763 int status; 1764 1765 if (n_tokens != 3) { 1766 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1767 return; 1768 } 1769 1770 pipeline_name = tokens[1]; 1771 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1772 if (!ctl) { 1773 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1774 return; 1775 } 1776 1777 status = rte_swx_ctl_pipeline_commit(ctl, 1); 1778 if (status) 1779 snprintf(out, out_size, "Commit failed. " 1780 "Use \"commit\" to retry or \"abort\" to discard the pending work.\n"); 1781 } 1782 1783 static const char cmd_pipeline_abort_help[] = 1784 "pipeline <pipeline_name> abort\n"; 1785 1786 static void 1787 cmd_pipeline_abort(char **tokens, 1788 uint32_t n_tokens, 1789 char *out, 1790 size_t out_size, 1791 void *obj __rte_unused) 1792 { 1793 struct rte_swx_ctl_pipeline *ctl; 1794 char *pipeline_name; 1795 1796 if (n_tokens != 3) { 1797 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1798 return; 1799 } 1800 1801 pipeline_name = tokens[1]; 1802 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1803 if (!ctl) { 1804 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1805 return; 1806 } 1807 1808 rte_swx_ctl_pipeline_abort(ctl); 1809 } 1810 1811 static const char cmd_pipeline_regrd_help[] = 1812 "pipeline <pipeline_name> regrd <register_array_name>\n" 1813 "index <index>\n" 1814 " | table <table_name> match <field0> ...\n"; 1815 1816 static void 1817 cmd_pipeline_regrd(char **tokens, 1818 uint32_t n_tokens, 1819 char *out, 1820 size_t out_size, 1821 void *obj __rte_unused) 1822 { 1823 struct rte_swx_pipeline *p; 1824 struct rte_swx_ctl_pipeline *ctl; 1825 const char *pipeline_name, *name; 1826 uint64_t value; 1827 int status; 1828 1829 if (n_tokens < 5) { 1830 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1831 return; 1832 } 1833 1834 pipeline_name = tokens[1]; 1835 p = rte_swx_pipeline_find(pipeline_name); 1836 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1837 if (!p || !ctl) { 1838 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1839 return; 1840 } 1841 1842 if (strcmp(tokens[2], "regrd")) { 1843 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd"); 1844 return; 1845 } 1846 1847 name = tokens[3]; 1848 1849 /* index. */ 1850 if (!strcmp(tokens[4], "index")) { 1851 uint32_t idx = 0; 1852 1853 if (n_tokens != 6) { 1854 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1855 return; 1856 } 1857 1858 if (parser_read_uint32(&idx, tokens[5])) { 1859 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 1860 return; 1861 } 1862 1863 status = rte_swx_ctl_pipeline_regarray_read(p, name, idx, &value); 1864 if (status) { 1865 snprintf(out, out_size, "Command failed.\n"); 1866 return; 1867 } 1868 1869 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 1870 return; 1871 } 1872 1873 /* table. */ 1874 if (!strcmp(tokens[4], "table")) { 1875 struct rte_swx_table_entry *entry; 1876 char *table_name; 1877 1878 if (n_tokens < 8) { 1879 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1880 return; 1881 } 1882 1883 table_name = tokens[5]; 1884 1885 if (strcmp(tokens[6], "match")) { 1886 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 1887 return; 1888 } 1889 1890 entry = parse_table_entry(ctl, table_name, &tokens[6], n_tokens - 6); 1891 if (!entry) { 1892 snprintf(out, out_size, "Invalid match tokens.\n"); 1893 return; 1894 } 1895 1896 status = rte_swx_ctl_pipeline_regarray_read_with_key(p, 1897 name, 1898 table_name, 1899 entry->key, 1900 &value); 1901 table_entry_free(entry); 1902 if (status) { 1903 snprintf(out, out_size, "Command failed.\n"); 1904 return; 1905 } 1906 1907 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 1908 return; 1909 } 1910 1911 /* anything else. */ 1912 snprintf(out, out_size, "Invalid token %s\n.", tokens[4]); 1913 return; 1914 } 1915 1916 static const char cmd_pipeline_regwr_help[] = 1917 "pipeline <pipeline_name> regwr <register_array_name> value <value>\n" 1918 "index <index>\n" 1919 " | table <table_name> match <field0> ...\n"; 1920 1921 static void 1922 cmd_pipeline_regwr(char **tokens, 1923 uint32_t n_tokens, 1924 char *out, 1925 size_t out_size, 1926 void *obj __rte_unused) 1927 { 1928 struct rte_swx_pipeline *p; 1929 struct rte_swx_ctl_pipeline *ctl; 1930 const char *pipeline_name, *name; 1931 uint64_t value = 0; 1932 int status; 1933 1934 if (n_tokens < 7) { 1935 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1936 return; 1937 } 1938 1939 pipeline_name = tokens[1]; 1940 p = rte_swx_pipeline_find(pipeline_name); 1941 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 1942 if (!p || !ctl) { 1943 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1944 return; 1945 } 1946 1947 if (strcmp(tokens[2], "regwr")) { 1948 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr"); 1949 return; 1950 } 1951 1952 name = tokens[3]; 1953 1954 if (strcmp(tokens[4], "value")) { 1955 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "value"); 1956 return; 1957 } 1958 1959 if (parser_read_uint64(&value, tokens[5])) { 1960 snprintf(out, out_size, MSG_ARG_INVALID, "value"); 1961 return; 1962 } 1963 1964 /* index. */ 1965 if (!strcmp(tokens[6], "index")) { 1966 uint32_t idx = 0; 1967 1968 if (n_tokens != 8) { 1969 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1970 return; 1971 } 1972 1973 if (parser_read_uint32(&idx, tokens[7])) { 1974 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 1975 return; 1976 } 1977 1978 status = rte_swx_ctl_pipeline_regarray_write(p, name, idx, value); 1979 if (status) { 1980 snprintf(out, out_size, "Command failed.\n"); 1981 return; 1982 } 1983 1984 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 1985 return; 1986 } 1987 1988 /* table. */ 1989 if (!strcmp(tokens[6], "table")) { 1990 struct rte_swx_table_entry *entry; 1991 char *table_name; 1992 1993 if (n_tokens < 10) { 1994 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1995 return; 1996 } 1997 1998 table_name = tokens[7]; 1999 2000 if (strcmp(tokens[8], "match")) { 2001 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2002 return; 2003 } 2004 2005 entry = parse_table_entry(ctl, table_name, &tokens[8], n_tokens - 8); 2006 if (!entry) { 2007 snprintf(out, out_size, "Invalid match tokens.\n"); 2008 return; 2009 } 2010 2011 status = rte_swx_ctl_pipeline_regarray_write_with_key(p, 2012 name, 2013 table_name, 2014 entry->key, 2015 value); 2016 table_entry_free(entry); 2017 if (status) { 2018 snprintf(out, out_size, "Command failed.\n"); 2019 return; 2020 } 2021 2022 return; 2023 } 2024 2025 /* anything else. */ 2026 snprintf(out, out_size, "Invalid token %s\n.", tokens[6]); 2027 return; 2028 } 2029 2030 static const char cmd_pipeline_meter_profile_add_help[] = 2031 "pipeline <pipeline_name> meter profile <profile_name> add " 2032 "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 2033 2034 static void 2035 cmd_pipeline_meter_profile_add(char **tokens, 2036 uint32_t n_tokens, 2037 char *out, 2038 size_t out_size, 2039 void *obj __rte_unused) 2040 { 2041 struct rte_meter_trtcm_params params; 2042 struct rte_swx_pipeline *p; 2043 const char *profile_name; 2044 int status; 2045 2046 if (n_tokens != 14) { 2047 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2048 return; 2049 } 2050 2051 p = rte_swx_pipeline_find(tokens[1]); 2052 if (!p) { 2053 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2054 return; 2055 } 2056 2057 if (strcmp(tokens[2], "meter")) { 2058 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2059 return; 2060 } 2061 2062 if (strcmp(tokens[3], "profile")) { 2063 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2064 return; 2065 } 2066 2067 profile_name = tokens[4]; 2068 2069 if (strcmp(tokens[5], "add")) { 2070 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 2071 return; 2072 } 2073 2074 if (strcmp(tokens[6], "cir")) { 2075 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 2076 return; 2077 } 2078 2079 if (parser_read_uint64(¶ms.cir, tokens[7])) { 2080 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 2081 return; 2082 } 2083 2084 if (strcmp(tokens[8], "pir")) { 2085 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 2086 return; 2087 } 2088 2089 if (parser_read_uint64(¶ms.pir, tokens[9])) { 2090 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 2091 return; 2092 } 2093 2094 if (strcmp(tokens[10], "cbs")) { 2095 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 2096 return; 2097 } 2098 2099 if (parser_read_uint64(¶ms.cbs, tokens[11])) { 2100 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 2101 return; 2102 } 2103 2104 if (strcmp(tokens[12], "pbs")) { 2105 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 2106 return; 2107 } 2108 2109 if (parser_read_uint64(¶ms.pbs, tokens[13])) { 2110 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 2111 return; 2112 } 2113 2114 status = rte_swx_ctl_meter_profile_add(p, profile_name, ¶ms); 2115 if (status) { 2116 snprintf(out, out_size, "Command failed.\n"); 2117 return; 2118 } 2119 } 2120 2121 static const char cmd_pipeline_meter_profile_delete_help[] = 2122 "pipeline <pipeline_name> meter profile <profile_name> delete\n"; 2123 2124 static void 2125 cmd_pipeline_meter_profile_delete(char **tokens, 2126 uint32_t n_tokens, 2127 char *out, 2128 size_t out_size, 2129 void *obj __rte_unused) 2130 { 2131 struct rte_swx_pipeline *p; 2132 const char *profile_name; 2133 int status; 2134 2135 if (n_tokens != 6) { 2136 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2137 return; 2138 } 2139 2140 p = rte_swx_pipeline_find(tokens[1]); 2141 if (!p) { 2142 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2143 return; 2144 } 2145 2146 if (strcmp(tokens[2], "meter")) { 2147 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2148 return; 2149 } 2150 2151 if (strcmp(tokens[3], "profile")) { 2152 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2153 return; 2154 } 2155 2156 profile_name = tokens[4]; 2157 2158 if (strcmp(tokens[5], "delete")) { 2159 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 2160 return; 2161 } 2162 2163 status = rte_swx_ctl_meter_profile_delete(p, profile_name); 2164 if (status) { 2165 snprintf(out, out_size, "Command failed.\n"); 2166 return; 2167 } 2168 } 2169 2170 static const char cmd_pipeline_meter_reset_help[] = 2171 "pipeline <pipeline_name> meter <meter_array_name> reset\n" 2172 "index from <index0> to <index1>\n" 2173 " | table <table_name> match <field0> ...\n"; 2174 2175 static void 2176 cmd_pipeline_meter_reset(char **tokens, 2177 uint32_t n_tokens, 2178 char *out, 2179 size_t out_size, 2180 void *obj __rte_unused) 2181 { 2182 struct rte_swx_pipeline *p; 2183 struct rte_swx_ctl_pipeline *ctl; 2184 const char *pipeline_name, *name; 2185 2186 if (n_tokens < 6) { 2187 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2188 return; 2189 } 2190 2191 pipeline_name = tokens[1]; 2192 p = rte_swx_pipeline_find(pipeline_name); 2193 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 2194 if (!p || !ctl) { 2195 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2196 return; 2197 } 2198 2199 if (strcmp(tokens[2], "meter")) { 2200 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2201 return; 2202 } 2203 2204 name = tokens[3]; 2205 2206 if (strcmp(tokens[4], "reset")) { 2207 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); 2208 return; 2209 } 2210 2211 /* index. */ 2212 if (!strcmp(tokens[5], "index")) { 2213 uint32_t idx0 = 0, idx1 = 0; 2214 2215 if (n_tokens != 10) { 2216 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2217 return; 2218 } 2219 2220 if (strcmp(tokens[6], "from")) { 2221 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2222 return; 2223 } 2224 2225 if (parser_read_uint32(&idx0, tokens[7])) { 2226 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2227 return; 2228 } 2229 2230 if (strcmp(tokens[8], "to")) { 2231 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2232 return; 2233 } 2234 2235 if (parser_read_uint32(&idx1, tokens[9]) || (idx1 < idx0)) { 2236 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2237 return; 2238 } 2239 2240 for ( ; idx0 <= idx1; idx0++) { 2241 int status; 2242 2243 status = rte_swx_ctl_meter_reset(p, name, idx0); 2244 if (status) { 2245 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2246 return; 2247 } 2248 } 2249 2250 return; 2251 } 2252 2253 /* table. */ 2254 if (!strcmp(tokens[5], "table")) { 2255 struct rte_swx_table_entry *entry; 2256 char *table_name; 2257 int status; 2258 2259 if (n_tokens < 9) { 2260 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2261 return; 2262 } 2263 2264 table_name = tokens[6]; 2265 2266 if (strcmp(tokens[7], "match")) { 2267 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2268 return; 2269 } 2270 2271 entry = parse_table_entry(ctl, table_name, &tokens[7], n_tokens - 7); 2272 if (!entry) { 2273 snprintf(out, out_size, "Invalid match tokens.\n"); 2274 return; 2275 } 2276 2277 status = rte_swx_ctl_meter_reset_with_key(p, name, table_name, entry->key); 2278 table_entry_free(entry); 2279 if (status) { 2280 snprintf(out, out_size, "Command failed.\n"); 2281 return; 2282 } 2283 2284 return; 2285 } 2286 2287 /* anything else. */ 2288 snprintf(out, out_size, "Invalid token %s\n.", tokens[5]); 2289 return; 2290 } 2291 2292 static const char cmd_pipeline_meter_set_help[] = 2293 "pipeline <pipeline_name> meter <meter_array_name> set profile <profile_name>\n" 2294 "index from <index0> to <index1>\n" 2295 " | table <table_name> match <field0> ...\n"; 2296 2297 static void 2298 cmd_pipeline_meter_set(char **tokens, 2299 uint32_t n_tokens, 2300 char *out, 2301 size_t out_size, 2302 void *obj __rte_unused) 2303 { 2304 struct rte_swx_pipeline *p; 2305 struct rte_swx_ctl_pipeline *ctl; 2306 const char *pipeline_name, *name, *profile_name; 2307 2308 if (n_tokens < 8) { 2309 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2310 return; 2311 } 2312 2313 pipeline_name = tokens[1]; 2314 p = rte_swx_pipeline_find(pipeline_name); 2315 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 2316 if (!p || !ctl) { 2317 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2318 return; 2319 } 2320 2321 if (strcmp(tokens[2], "meter")) { 2322 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2323 return; 2324 } 2325 2326 name = tokens[3]; 2327 2328 if (strcmp(tokens[4], "set")) { 2329 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); 2330 return; 2331 } 2332 2333 if (strcmp(tokens[5], "profile")) { 2334 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2335 return; 2336 } 2337 2338 profile_name = tokens[6]; 2339 2340 /* index. */ 2341 if (!strcmp(tokens[7], "index")) { 2342 uint32_t idx0 = 0, idx1 = 0; 2343 2344 if (n_tokens != 12) { 2345 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2346 return; 2347 } 2348 2349 if (strcmp(tokens[8], "from")) { 2350 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2351 return; 2352 } 2353 2354 if (parser_read_uint32(&idx0, tokens[9])) { 2355 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2356 return; 2357 } 2358 2359 if (strcmp(tokens[10], "to")) { 2360 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2361 return; 2362 } 2363 2364 if (parser_read_uint32(&idx1, tokens[11]) || (idx1 < idx0)) { 2365 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2366 return; 2367 } 2368 2369 for ( ; idx0 <= idx1; idx0++) { 2370 int status; 2371 2372 status = rte_swx_ctl_meter_set(p, name, idx0, profile_name); 2373 if (status) { 2374 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2375 return; 2376 } 2377 } 2378 2379 return; 2380 } 2381 2382 /* table. */ 2383 if (!strcmp(tokens[7], "table")) { 2384 struct rte_swx_table_entry *entry; 2385 char *table_name; 2386 int status; 2387 2388 if (n_tokens < 11) { 2389 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2390 return; 2391 } 2392 2393 table_name = tokens[8]; 2394 2395 if (strcmp(tokens[9], "match")) { 2396 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2397 return; 2398 } 2399 2400 entry = parse_table_entry(ctl, table_name, &tokens[9], n_tokens - 9); 2401 if (!entry) { 2402 snprintf(out, out_size, "Invalid match tokens.\n"); 2403 return; 2404 } 2405 2406 status = rte_swx_ctl_meter_set_with_key(p, 2407 name, 2408 table_name, 2409 entry->key, 2410 profile_name); 2411 table_entry_free(entry); 2412 if (status) { 2413 snprintf(out, out_size, "Command failed.\n"); 2414 return; 2415 } 2416 2417 return; 2418 } 2419 2420 /* anything else. */ 2421 snprintf(out, out_size, "Invalid token %s\n.", tokens[7]); 2422 return; 2423 } 2424 2425 static const char cmd_pipeline_meter_stats_help[] = 2426 "pipeline <pipeline_name> meter <meter_array_name> stats\n" 2427 "index from <index0> to <index1>\n" 2428 " | table <table_name> match <field0> ...\n"; 2429 2430 static void 2431 cmd_pipeline_meter_stats(char **tokens, 2432 uint32_t n_tokens, 2433 char *out, 2434 size_t out_size, 2435 void *obj __rte_unused) 2436 { 2437 struct rte_swx_ctl_meter_stats stats; 2438 struct rte_swx_pipeline *p; 2439 struct rte_swx_ctl_pipeline *ctl; 2440 const char *pipeline_name, *name; 2441 2442 if (n_tokens < 6) { 2443 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2444 return; 2445 } 2446 2447 pipeline_name = tokens[1]; 2448 p = rte_swx_pipeline_find(pipeline_name); 2449 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 2450 if (!p || !ctl) { 2451 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2452 return; 2453 } 2454 2455 if (strcmp(tokens[2], "meter")) { 2456 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2457 return; 2458 } 2459 2460 name = tokens[3]; 2461 2462 if (strcmp(tokens[4], "stats")) { 2463 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2464 return; 2465 } 2466 2467 /* index. */ 2468 if (!strcmp(tokens[5], "index")) { 2469 uint32_t idx0 = 0, idx1 = 0; 2470 2471 if (n_tokens != 10) { 2472 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2473 return; 2474 } 2475 2476 if (strcmp(tokens[6], "from")) { 2477 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2478 return; 2479 } 2480 2481 if (parser_read_uint32(&idx0, tokens[7])) { 2482 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2483 return; 2484 } 2485 2486 if (strcmp(tokens[8], "to")) { 2487 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2488 return; 2489 } 2490 2491 if (parser_read_uint32(&idx1, tokens[9]) || (idx1 < idx0)) { 2492 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2493 return; 2494 } 2495 2496 /* Table header. */ 2497 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2498 "-------", 2499 "----------------", "----------------", "----------------", 2500 "----------------", "----------------", "----------------"); 2501 out_size -= strlen(out); 2502 out += strlen(out); 2503 2504 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2505 "METER #", 2506 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2507 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2508 out_size -= strlen(out); 2509 out += strlen(out); 2510 2511 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2512 "-------", 2513 "----------------", "----------------", "----------------", 2514 "----------------", "----------------", "----------------"); 2515 out_size -= strlen(out); 2516 out += strlen(out); 2517 2518 /* Table rows. */ 2519 for ( ; idx0 <= idx1; idx0++) { 2520 int status; 2521 2522 status = rte_swx_ctl_meter_stats_read(p, name, idx0, &stats); 2523 if (status) { 2524 snprintf(out, out_size, "Meter stats error at index %u.\n", idx0); 2525 out_size -= strlen(out); 2526 out += strlen(out); 2527 return; 2528 } 2529 2530 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2531 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2532 idx0, 2533 stats.n_pkts[RTE_COLOR_GREEN], 2534 stats.n_pkts[RTE_COLOR_YELLOW], 2535 stats.n_pkts[RTE_COLOR_RED], 2536 stats.n_bytes[RTE_COLOR_GREEN], 2537 stats.n_bytes[RTE_COLOR_YELLOW], 2538 stats.n_bytes[RTE_COLOR_RED]); 2539 out_size -= strlen(out); 2540 out += strlen(out); 2541 } 2542 2543 return; 2544 } 2545 2546 /* table. */ 2547 if (!strcmp(tokens[5], "table")) { 2548 struct rte_swx_table_entry *entry; 2549 char *table_name; 2550 int status; 2551 2552 if (n_tokens < 9) { 2553 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2554 return; 2555 } 2556 2557 table_name = tokens[6]; 2558 2559 if (strcmp(tokens[7], "match")) { 2560 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2561 return; 2562 } 2563 2564 entry = parse_table_entry(ctl, table_name, &tokens[7], n_tokens - 7); 2565 if (!entry) { 2566 snprintf(out, out_size, "Invalid match tokens.\n"); 2567 return; 2568 } 2569 2570 status = rte_swx_ctl_meter_stats_read_with_key(p, 2571 name, 2572 table_name, 2573 entry->key, 2574 &stats); 2575 table_entry_free(entry); 2576 if (status) { 2577 snprintf(out, out_size, "Command failed.\n"); 2578 return; 2579 } 2580 2581 /* Table header. */ 2582 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2583 "-------", 2584 "----------------", "----------------", "----------------", 2585 "----------------", "----------------", "----------------"); 2586 out_size -= strlen(out); 2587 out += strlen(out); 2588 2589 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2590 "METER #", 2591 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2592 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2593 out_size -= strlen(out); 2594 out += strlen(out); 2595 2596 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2597 "-------", 2598 "----------------", "----------------", "----------------", 2599 "----------------", "----------------", "----------------"); 2600 out_size -= strlen(out); 2601 out += strlen(out); 2602 2603 /* Table row. */ 2604 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2605 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2606 0, 2607 stats.n_pkts[RTE_COLOR_GREEN], 2608 stats.n_pkts[RTE_COLOR_YELLOW], 2609 stats.n_pkts[RTE_COLOR_RED], 2610 stats.n_bytes[RTE_COLOR_GREEN], 2611 stats.n_bytes[RTE_COLOR_YELLOW], 2612 stats.n_bytes[RTE_COLOR_RED]); 2613 out_size -= strlen(out); 2614 out += strlen(out); 2615 2616 return; 2617 } 2618 2619 /* anything else. */ 2620 snprintf(out, out_size, "Invalid token %s\n.", tokens[5]); 2621 return; 2622 } 2623 2624 static const char cmd_pipeline_stats_help[] = 2625 "pipeline <pipeline_name> stats\n"; 2626 2627 static void 2628 cmd_pipeline_stats(char **tokens, 2629 uint32_t n_tokens, 2630 char *out, 2631 size_t out_size, 2632 void *obj __rte_unused) 2633 { 2634 struct rte_swx_ctl_pipeline_info info; 2635 struct rte_swx_pipeline *p; 2636 uint32_t i; 2637 int status; 2638 2639 if (n_tokens != 3) { 2640 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2641 return; 2642 } 2643 2644 p = rte_swx_pipeline_find(tokens[1]); 2645 if (!p) { 2646 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2647 return; 2648 } 2649 2650 if (strcmp(tokens[2], "stats")) { 2651 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2652 return; 2653 } 2654 2655 status = rte_swx_ctl_pipeline_info_get(p, &info); 2656 if (status) { 2657 snprintf(out, out_size, "Pipeline info get error."); 2658 return; 2659 } 2660 2661 snprintf(out, out_size, "Input ports:\n"); 2662 out_size -= strlen(out); 2663 out += strlen(out); 2664 2665 for (i = 0; i < info.n_ports_in; i++) { 2666 struct rte_swx_port_in_stats stats; 2667 2668 rte_swx_ctl_pipeline_port_in_stats_read(p, i, &stats); 2669 2670 snprintf(out, out_size, "\tPort %u:" 2671 " packets %" PRIu64 2672 " bytes %" PRIu64 2673 " empty %" PRIu64 "\n", 2674 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 2675 out_size -= strlen(out); 2676 out += strlen(out); 2677 } 2678 2679 snprintf(out, out_size, "\nOutput ports:\n"); 2680 out_size -= strlen(out); 2681 out += strlen(out); 2682 2683 for (i = 0; i < info.n_ports_out; i++) { 2684 struct rte_swx_port_out_stats stats; 2685 2686 rte_swx_ctl_pipeline_port_out_stats_read(p, i, &stats); 2687 2688 if (i != info.n_ports_out - 1) 2689 snprintf(out, out_size, "\tPort %u:", i); 2690 else 2691 snprintf(out, out_size, "\tDROP:"); 2692 2693 out_size -= strlen(out); 2694 out += strlen(out); 2695 2696 snprintf(out, 2697 out_size, 2698 " packets %" PRIu64 2699 " bytes %" PRIu64 2700 " packets dropped %" PRIu64 2701 " bytes dropped %" PRIu64 2702 " clone %" PRIu64 2703 " clonerr %" PRIu64 "\n", 2704 stats.n_pkts, 2705 stats.n_bytes, 2706 stats.n_pkts_drop, 2707 stats.n_bytes_drop, 2708 stats.n_pkts_clone, 2709 stats.n_pkts_clone_err); 2710 2711 out_size -= strlen(out); 2712 out += strlen(out); 2713 } 2714 2715 snprintf(out, out_size, "\nTables:\n"); 2716 out_size -= strlen(out); 2717 out += strlen(out); 2718 2719 for (i = 0; i < info.n_tables; i++) { 2720 struct rte_swx_ctl_table_info table_info; 2721 uint64_t n_pkts_action[info.n_actions]; 2722 struct rte_swx_table_stats stats = { 2723 .n_pkts_hit = 0, 2724 .n_pkts_miss = 0, 2725 .n_pkts_action = n_pkts_action, 2726 }; 2727 uint32_t j; 2728 2729 status = rte_swx_ctl_table_info_get(p, i, &table_info); 2730 if (status) { 2731 snprintf(out, out_size, "Table info get error."); 2732 return; 2733 } 2734 2735 status = rte_swx_ctl_pipeline_table_stats_read(p, table_info.name, &stats); 2736 if (status) { 2737 snprintf(out, out_size, "Table stats read error."); 2738 return; 2739 } 2740 2741 snprintf(out, out_size, "\tTable %s:\n" 2742 "\t\tHit (packets): %" PRIu64 "\n" 2743 "\t\tMiss (packets): %" PRIu64 "\n", 2744 table_info.name, 2745 stats.n_pkts_hit, 2746 stats.n_pkts_miss); 2747 out_size -= strlen(out); 2748 out += strlen(out); 2749 2750 for (j = 0; j < info.n_actions; j++) { 2751 struct rte_swx_ctl_action_info action_info; 2752 2753 status = rte_swx_ctl_action_info_get(p, j, &action_info); 2754 if (status) { 2755 snprintf(out, out_size, "Action info get error."); 2756 return; 2757 } 2758 2759 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2760 action_info.name, 2761 stats.n_pkts_action[j]); 2762 out_size -= strlen(out); 2763 out += strlen(out); 2764 } 2765 } 2766 2767 snprintf(out, out_size, "\nLearner tables:\n"); 2768 out_size -= strlen(out); 2769 out += strlen(out); 2770 2771 for (i = 0; i < info.n_learners; i++) { 2772 struct rte_swx_ctl_learner_info learner_info; 2773 uint64_t n_pkts_action[info.n_actions]; 2774 struct rte_swx_learner_stats stats = { 2775 .n_pkts_hit = 0, 2776 .n_pkts_miss = 0, 2777 .n_pkts_action = n_pkts_action, 2778 }; 2779 uint32_t j; 2780 2781 status = rte_swx_ctl_learner_info_get(p, i, &learner_info); 2782 if (status) { 2783 snprintf(out, out_size, "Learner table info get error."); 2784 return; 2785 } 2786 2787 status = rte_swx_ctl_pipeline_learner_stats_read(p, learner_info.name, &stats); 2788 if (status) { 2789 snprintf(out, out_size, "Learner table stats read error."); 2790 return; 2791 } 2792 2793 snprintf(out, out_size, "\tLearner table %s:\n" 2794 "\t\tHit (packets): %" PRIu64 "\n" 2795 "\t\tMiss (packets): %" PRIu64 "\n" 2796 "\t\tLearn OK (packets): %" PRIu64 "\n" 2797 "\t\tLearn error (packets): %" PRIu64 "\n" 2798 "\t\tRearm (packets): %" PRIu64 "\n" 2799 "\t\tForget (packets): %" PRIu64 "\n", 2800 learner_info.name, 2801 stats.n_pkts_hit, 2802 stats.n_pkts_miss, 2803 stats.n_pkts_learn_ok, 2804 stats.n_pkts_learn_err, 2805 stats.n_pkts_rearm, 2806 stats.n_pkts_forget); 2807 out_size -= strlen(out); 2808 out += strlen(out); 2809 2810 for (j = 0; j < info.n_actions; j++) { 2811 struct rte_swx_ctl_action_info action_info; 2812 2813 status = rte_swx_ctl_action_info_get(p, j, &action_info); 2814 if (status) { 2815 snprintf(out, out_size, "Action info get error."); 2816 return; 2817 } 2818 2819 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2820 action_info.name, 2821 stats.n_pkts_action[j]); 2822 out_size -= strlen(out); 2823 out += strlen(out); 2824 } 2825 } 2826 } 2827 2828 static const char cmd_pipeline_mirror_session_help[] = 2829 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow " 2830 "truncate <truncation_length>\n"; 2831 2832 static void 2833 cmd_pipeline_mirror_session(char **tokens, 2834 uint32_t n_tokens, 2835 char *out, 2836 size_t out_size, 2837 void *obj __rte_unused) 2838 { 2839 struct rte_swx_pipeline_mirroring_session_params params; 2840 struct rte_swx_pipeline *p; 2841 uint32_t session_id = 0; 2842 int status; 2843 2844 if (n_tokens != 11) { 2845 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2846 return; 2847 } 2848 2849 if (strcmp(tokens[0], "pipeline")) { 2850 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2851 return; 2852 } 2853 2854 p = rte_swx_pipeline_find(tokens[1]); 2855 if (!p) { 2856 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2857 return; 2858 } 2859 2860 if (strcmp(tokens[2], "mirror")) { 2861 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror"); 2862 return; 2863 } 2864 2865 if (strcmp(tokens[3], "session")) { 2866 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "session"); 2867 return; 2868 } 2869 2870 if (parser_read_uint32(&session_id, tokens[4])) { 2871 snprintf(out, out_size, MSG_ARG_INVALID, "session_id"); 2872 return; 2873 } 2874 2875 if (strcmp(tokens[5], "port")) { 2876 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2877 return; 2878 } 2879 2880 if (parser_read_uint32(¶ms.port_id, tokens[6])) { 2881 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2882 return; 2883 } 2884 2885 if (strcmp(tokens[7], "clone")) { 2886 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "clone"); 2887 return; 2888 } 2889 2890 if (!strcmp(tokens[8], "fast")) 2891 params.fast_clone = 1; 2892 else if (!strcmp(tokens[8], "slow")) 2893 params.fast_clone = 0; 2894 else { 2895 snprintf(out, out_size, MSG_ARG_INVALID, "clone"); 2896 return; 2897 } 2898 2899 if (strcmp(tokens[9], "truncate")) { 2900 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "truncate"); 2901 return; 2902 } 2903 2904 if (parser_read_uint32(¶ms.truncation_length, tokens[10])) { 2905 snprintf(out, out_size, MSG_ARG_INVALID, "truncation_length"); 2906 return; 2907 } 2908 2909 status = rte_swx_ctl_pipeline_mirroring_session_set(p, session_id, ¶ms); 2910 if (status) { 2911 snprintf(out, out_size, "Command failed!\n"); 2912 return; 2913 } 2914 } 2915 2916 static const char cmd_thread_pipeline_enable_help[] = 2917 "thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]\n"; 2918 2919 #ifndef TIMER_PERIOD_MS_DEFAULT 2920 #define TIMER_PERIOD_MS_DEFAULT 10 2921 #endif 2922 2923 static void 2924 cmd_thread_pipeline_enable(char **tokens, 2925 uint32_t n_tokens, 2926 char *out, 2927 size_t out_size, 2928 void *obj __rte_unused) 2929 { 2930 char *pipeline_name; 2931 struct rte_swx_pipeline *p; 2932 uint32_t thread_id, timer_period_ms = TIMER_PERIOD_MS_DEFAULT; 2933 int status; 2934 2935 if ((n_tokens != 5) && (n_tokens != 7)) { 2936 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2937 return; 2938 } 2939 2940 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2941 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2942 return; 2943 } 2944 2945 if (strcmp(tokens[2], "pipeline") != 0) { 2946 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2947 return; 2948 } 2949 2950 pipeline_name = tokens[3]; 2951 p = rte_swx_pipeline_find(pipeline_name); 2952 if (!p) { 2953 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2954 return; 2955 } 2956 2957 if (strcmp(tokens[4], "enable") != 0) { 2958 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2959 return; 2960 } 2961 2962 if (n_tokens == 7) { 2963 if (strcmp(tokens[5], "period") != 0) { 2964 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); 2965 return; 2966 } 2967 2968 if (parser_read_uint32(&timer_period_ms, tokens[6]) != 0) { 2969 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); 2970 return; 2971 } 2972 } 2973 2974 status = thread_pipeline_enable(thread_id, p, timer_period_ms); 2975 if (status) { 2976 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 2977 return; 2978 } 2979 } 2980 2981 static const char cmd_thread_pipeline_disable_help[] = 2982 "thread <thread_id> pipeline <pipeline_name> disable\n"; 2983 2984 static void 2985 cmd_thread_pipeline_disable(char **tokens, 2986 uint32_t n_tokens, 2987 char *out, 2988 size_t out_size, 2989 void *obj __rte_unused) 2990 { 2991 struct rte_swx_pipeline *p; 2992 char *pipeline_name; 2993 uint32_t thread_id; 2994 int status; 2995 2996 if (n_tokens != 5) { 2997 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2998 return; 2999 } 3000 3001 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 3002 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 3003 return; 3004 } 3005 3006 if (strcmp(tokens[2], "pipeline") != 0) { 3007 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 3008 return; 3009 } 3010 3011 pipeline_name = tokens[3]; 3012 p = rte_swx_pipeline_find(pipeline_name); 3013 if (!p) { 3014 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 3015 return; 3016 } 3017 3018 if (strcmp(tokens[4], "disable") != 0) { 3019 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 3020 return; 3021 } 3022 3023 status = thread_pipeline_disable(thread_id, p); 3024 if (status) { 3025 snprintf(out, out_size, MSG_CMD_FAIL, 3026 "thread pipeline disable"); 3027 return; 3028 } 3029 } 3030 3031 static void 3032 cmd_help(char **tokens, 3033 uint32_t n_tokens, 3034 char *out, 3035 size_t out_size, 3036 void *arg __rte_unused) 3037 { 3038 tokens++; 3039 n_tokens--; 3040 3041 if (n_tokens == 0) { 3042 snprintf(out, out_size, 3043 "Type 'help <command>' for command details.\n\n" 3044 "List of commands:\n" 3045 "\tmempool\n" 3046 "\tethdev\n" 3047 "\tethdev show\n" 3048 "\tring\n" 3049 "\tcryptodev\n" 3050 "\tpipeline codegen\n" 3051 "\tpipeline libbuild\n" 3052 "\tpipeline build\n" 3053 "\tpipeline table add\n" 3054 "\tpipeline table delete\n" 3055 "\tpipeline table default\n" 3056 "\tpipeline table show\n" 3057 "\tpipeline selector group add\n" 3058 "\tpipeline selector group delete\n" 3059 "\tpipeline selector group member add\n" 3060 "\tpipeline selector group member delete\n" 3061 "\tpipeline selector show\n" 3062 "\tpipeline learner default\n" 3063 "\tpipeline commit\n" 3064 "\tpipeline abort\n" 3065 "\tpipeline regrd\n" 3066 "\tpipeline regwr\n" 3067 "\tpipeline meter profile add\n" 3068 "\tpipeline meter profile delete\n" 3069 "\tpipeline meter reset\n" 3070 "\tpipeline meter set\n" 3071 "\tpipeline meter stats\n" 3072 "\tpipeline stats\n" 3073 "\tpipeline mirror session\n" 3074 "\tthread pipeline enable\n" 3075 "\tthread pipeline disable\n\n"); 3076 return; 3077 } 3078 3079 if (strcmp(tokens[0], "mempool") == 0) { 3080 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 3081 return; 3082 } 3083 3084 if (!strcmp(tokens[0], "ethdev")) { 3085 if (n_tokens == 1) { 3086 snprintf(out, out_size, "\n%s\n", cmd_ethdev_help); 3087 return; 3088 } 3089 3090 if (n_tokens == 2 && !strcmp(tokens[1], "show")) { 3091 snprintf(out, out_size, "\n%s\n", cmd_ethdev_show_help); 3092 return; 3093 } 3094 } 3095 3096 if (strcmp(tokens[0], "ring") == 0) { 3097 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 3098 return; 3099 } 3100 3101 if (!strcmp(tokens[0], "cryptodev")) { 3102 snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help); 3103 return; 3104 } 3105 3106 if ((strcmp(tokens[0], "pipeline") == 0) && 3107 (n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) { 3108 snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help); 3109 return; 3110 } 3111 3112 if ((strcmp(tokens[0], "pipeline") == 0) && 3113 (n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) { 3114 snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help); 3115 return; 3116 } 3117 3118 if ((strcmp(tokens[0], "pipeline") == 0) && 3119 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 3120 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 3121 return; 3122 } 3123 3124 if ((strcmp(tokens[0], "pipeline") == 0) && 3125 (n_tokens == 3) && 3126 (strcmp(tokens[1], "table") == 0) && 3127 (strcmp(tokens[2], "add") == 0)) { 3128 snprintf(out, out_size, "\n%s\n", 3129 cmd_pipeline_table_add_help); 3130 return; 3131 } 3132 3133 if ((strcmp(tokens[0], "pipeline") == 0) && 3134 (n_tokens == 3) && 3135 (strcmp(tokens[1], "table") == 0) && 3136 (strcmp(tokens[2], "delete") == 0)) { 3137 snprintf(out, out_size, "\n%s\n", 3138 cmd_pipeline_table_delete_help); 3139 return; 3140 } 3141 3142 if ((strcmp(tokens[0], "pipeline") == 0) && 3143 (n_tokens == 3) && 3144 (strcmp(tokens[1], "table") == 0) && 3145 (strcmp(tokens[2], "default") == 0)) { 3146 snprintf(out, out_size, "\n%s\n", 3147 cmd_pipeline_table_default_help); 3148 return; 3149 } 3150 3151 if ((strcmp(tokens[0], "pipeline") == 0) && 3152 (n_tokens == 3) && 3153 (strcmp(tokens[1], "table") == 0) && 3154 (strcmp(tokens[2], "show") == 0)) { 3155 snprintf(out, out_size, "\n%s\n", 3156 cmd_pipeline_table_show_help); 3157 return; 3158 } 3159 3160 if ((strcmp(tokens[0], "pipeline") == 0) && 3161 (n_tokens == 4) && 3162 (strcmp(tokens[1], "selector") == 0) && 3163 (strcmp(tokens[2], "group") == 0) && 3164 (strcmp(tokens[3], "add") == 0)) { 3165 snprintf(out, out_size, "\n%s\n", 3166 cmd_pipeline_selector_group_add_help); 3167 return; 3168 } 3169 3170 if ((strcmp(tokens[0], "pipeline") == 0) && 3171 (n_tokens == 4) && 3172 (strcmp(tokens[1], "selector") == 0) && 3173 (strcmp(tokens[2], "group") == 0) && 3174 (strcmp(tokens[3], "delete") == 0)) { 3175 snprintf(out, out_size, "\n%s\n", 3176 cmd_pipeline_selector_group_delete_help); 3177 return; 3178 } 3179 3180 if ((strcmp(tokens[0], "pipeline") == 0) && 3181 (n_tokens == 5) && 3182 (strcmp(tokens[1], "selector") == 0) && 3183 (strcmp(tokens[2], "group") == 0) && 3184 (strcmp(tokens[3], "member") == 0) && 3185 (strcmp(tokens[4], "add") == 0)) { 3186 snprintf(out, out_size, "\n%s\n", 3187 cmd_pipeline_selector_group_member_add_help); 3188 return; 3189 } 3190 3191 if ((strcmp(tokens[0], "pipeline") == 0) && 3192 (n_tokens == 5) && 3193 (strcmp(tokens[1], "selector") == 0) && 3194 (strcmp(tokens[2], "group") == 0) && 3195 (strcmp(tokens[3], "member") == 0) && 3196 (strcmp(tokens[4], "delete") == 0)) { 3197 snprintf(out, out_size, "\n%s\n", 3198 cmd_pipeline_selector_group_member_delete_help); 3199 return; 3200 } 3201 3202 if ((strcmp(tokens[0], "pipeline") == 0) && 3203 (n_tokens == 3) && 3204 (strcmp(tokens[1], "selector") == 0) && 3205 (strcmp(tokens[2], "show") == 0)) { 3206 snprintf(out, out_size, "\n%s\n", 3207 cmd_pipeline_selector_show_help); 3208 return; 3209 } 3210 3211 if ((strcmp(tokens[0], "pipeline") == 0) && 3212 (n_tokens == 3) && 3213 (strcmp(tokens[1], "learner") == 0) && 3214 (strcmp(tokens[2], "default") == 0)) { 3215 snprintf(out, out_size, "\n%s\n", 3216 cmd_pipeline_learner_default_help); 3217 return; 3218 } 3219 3220 if ((strcmp(tokens[0], "pipeline") == 0) && 3221 (n_tokens == 2) && 3222 (strcmp(tokens[1], "commit") == 0)) { 3223 snprintf(out, out_size, "\n%s\n", 3224 cmd_pipeline_commit_help); 3225 return; 3226 } 3227 3228 if ((strcmp(tokens[0], "pipeline") == 0) && 3229 (n_tokens == 2) && 3230 (strcmp(tokens[1], "abort") == 0)) { 3231 snprintf(out, out_size, "\n%s\n", 3232 cmd_pipeline_abort_help); 3233 return; 3234 } 3235 3236 if ((strcmp(tokens[0], "pipeline") == 0) && 3237 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 3238 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 3239 return; 3240 } 3241 3242 if ((strcmp(tokens[0], "pipeline") == 0) && 3243 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 3244 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 3245 return; 3246 } 3247 3248 if (!strcmp(tokens[0], "pipeline") && 3249 (n_tokens == 4) && !strcmp(tokens[1], "meter") 3250 && !strcmp(tokens[2], "profile") 3251 && !strcmp(tokens[3], "add")) { 3252 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 3253 return; 3254 } 3255 3256 if (!strcmp(tokens[0], "pipeline") && 3257 (n_tokens == 4) && !strcmp(tokens[1], "meter") 3258 && !strcmp(tokens[2], "profile") 3259 && !strcmp(tokens[3], "delete")) { 3260 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 3261 return; 3262 } 3263 3264 if (!strcmp(tokens[0], "pipeline") && 3265 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3266 && !strcmp(tokens[2], "reset")) { 3267 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 3268 return; 3269 } 3270 3271 if (!strcmp(tokens[0], "pipeline") && 3272 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3273 && !strcmp(tokens[2], "set")) { 3274 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 3275 return; 3276 } 3277 3278 if (!strcmp(tokens[0], "pipeline") && 3279 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3280 && !strcmp(tokens[2], "stats")) { 3281 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 3282 return; 3283 } 3284 3285 if ((strcmp(tokens[0], "pipeline") == 0) && 3286 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 3287 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 3288 return; 3289 } 3290 3291 if (!strcmp(tokens[0], "pipeline") && 3292 (n_tokens == 3) && !strcmp(tokens[1], "mirror") 3293 && !strcmp(tokens[2], "session")) { 3294 snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_session_help); 3295 return; 3296 } 3297 3298 if ((n_tokens == 3) && 3299 (strcmp(tokens[0], "thread") == 0) && 3300 (strcmp(tokens[1], "pipeline") == 0)) { 3301 if (strcmp(tokens[2], "enable") == 0) { 3302 snprintf(out, out_size, "\n%s\n", 3303 cmd_thread_pipeline_enable_help); 3304 return; 3305 } 3306 3307 if (strcmp(tokens[2], "disable") == 0) { 3308 snprintf(out, out_size, "\n%s\n", 3309 cmd_thread_pipeline_disable_help); 3310 return; 3311 } 3312 } 3313 3314 snprintf(out, out_size, "Invalid command\n"); 3315 } 3316 3317 void 3318 cli_process(char *in, char *out, size_t out_size, void *obj) 3319 { 3320 char *tokens[CMD_MAX_TOKENS]; 3321 uint32_t n_tokens = RTE_DIM(tokens); 3322 int status; 3323 3324 if (is_comment(in)) 3325 return; 3326 3327 status = parse_tokenize_string(in, tokens, &n_tokens); 3328 if (status) { 3329 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 3330 return; 3331 } 3332 3333 if (n_tokens == 0) 3334 return; 3335 3336 if (strcmp(tokens[0], "help") == 0) { 3337 cmd_help(tokens, n_tokens, out, out_size, obj); 3338 return; 3339 } 3340 3341 if (strcmp(tokens[0], "mempool") == 0) { 3342 cmd_mempool(tokens, n_tokens, out, out_size, obj); 3343 return; 3344 } 3345 3346 if (strcmp(tokens[0], "ethdev") == 0) { 3347 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 3348 cmd_ethdev_show(tokens, n_tokens, out, out_size, obj); 3349 return; 3350 } 3351 3352 cmd_ethdev(tokens, n_tokens, out, out_size, obj); 3353 return; 3354 } 3355 3356 if (strcmp(tokens[0], "ring") == 0) { 3357 cmd_ring(tokens, n_tokens, out, out_size, obj); 3358 return; 3359 } 3360 3361 if (!strcmp(tokens[0], "cryptodev")) { 3362 cmd_cryptodev(tokens, n_tokens, out, out_size, obj); 3363 return; 3364 } 3365 3366 if (strcmp(tokens[0], "pipeline") == 0) { 3367 if ((n_tokens >= 3) && 3368 (strcmp(tokens[1], "codegen") == 0)) { 3369 cmd_pipeline_codegen(tokens, n_tokens, out, out_size, 3370 obj); 3371 return; 3372 } 3373 3374 if ((n_tokens >= 3) && 3375 (strcmp(tokens[1], "libbuild") == 0)) { 3376 cmd_pipeline_libbuild(tokens, n_tokens, out, out_size, 3377 obj); 3378 return; 3379 } 3380 3381 if ((n_tokens >= 3) && 3382 (strcmp(tokens[2], "build") == 0)) { 3383 cmd_pipeline_build(tokens, n_tokens, out, out_size, 3384 obj); 3385 return; 3386 } 3387 3388 if ((n_tokens >= 5) && 3389 (strcmp(tokens[2], "table") == 0) && 3390 (strcmp(tokens[4], "add") == 0)) { 3391 cmd_pipeline_table_add(tokens, n_tokens, out, 3392 out_size, obj); 3393 return; 3394 } 3395 3396 if ((n_tokens >= 5) && 3397 (strcmp(tokens[2], "table") == 0) && 3398 (strcmp(tokens[4], "delete") == 0)) { 3399 cmd_pipeline_table_delete(tokens, n_tokens, out, 3400 out_size, obj); 3401 return; 3402 } 3403 3404 if ((n_tokens >= 5) && 3405 (strcmp(tokens[2], "table") == 0) && 3406 (strcmp(tokens[4], "default") == 0)) { 3407 cmd_pipeline_table_default(tokens, n_tokens, out, 3408 out_size, obj); 3409 return; 3410 } 3411 3412 if ((n_tokens >= 5) && 3413 (strcmp(tokens[2], "table") == 0) && 3414 (strcmp(tokens[4], "show") == 0)) { 3415 cmd_pipeline_table_show(tokens, n_tokens, out, 3416 out_size, obj); 3417 return; 3418 } 3419 3420 if ((n_tokens >= 6) && 3421 (strcmp(tokens[2], "selector") == 0) && 3422 (strcmp(tokens[4], "group") == 0) && 3423 (strcmp(tokens[5], "add") == 0)) { 3424 cmd_pipeline_selector_group_add(tokens, n_tokens, out, 3425 out_size, obj); 3426 return; 3427 } 3428 3429 if ((n_tokens >= 6) && 3430 (strcmp(tokens[2], "selector") == 0) && 3431 (strcmp(tokens[4], "group") == 0) && 3432 (strcmp(tokens[5], "delete") == 0)) { 3433 cmd_pipeline_selector_group_delete(tokens, n_tokens, out, 3434 out_size, obj); 3435 return; 3436 } 3437 3438 if ((n_tokens >= 7) && 3439 (strcmp(tokens[2], "selector") == 0) && 3440 (strcmp(tokens[4], "group") == 0) && 3441 (strcmp(tokens[5], "member") == 0) && 3442 (strcmp(tokens[6], "add") == 0)) { 3443 cmd_pipeline_selector_group_member_add(tokens, n_tokens, out, 3444 out_size, obj); 3445 return; 3446 } 3447 3448 if ((n_tokens >= 7) && 3449 (strcmp(tokens[2], "selector") == 0) && 3450 (strcmp(tokens[4], "group") == 0) && 3451 (strcmp(tokens[5], "member") == 0) && 3452 (strcmp(tokens[6], "delete") == 0)) { 3453 cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out, 3454 out_size, obj); 3455 return; 3456 } 3457 3458 if ((n_tokens >= 5) && 3459 (strcmp(tokens[2], "selector") == 0) && 3460 (strcmp(tokens[4], "show") == 0)) { 3461 cmd_pipeline_selector_show(tokens, n_tokens, out, 3462 out_size, obj); 3463 return; 3464 } 3465 3466 if ((n_tokens >= 5) && 3467 (strcmp(tokens[2], "learner") == 0) && 3468 (strcmp(tokens[4], "default") == 0)) { 3469 cmd_pipeline_learner_default(tokens, n_tokens, out, 3470 out_size, obj); 3471 return; 3472 } 3473 3474 if ((n_tokens >= 3) && 3475 (strcmp(tokens[2], "commit") == 0)) { 3476 cmd_pipeline_commit(tokens, n_tokens, out, 3477 out_size, obj); 3478 return; 3479 } 3480 3481 if ((n_tokens >= 3) && 3482 (strcmp(tokens[2], "abort") == 0)) { 3483 cmd_pipeline_abort(tokens, n_tokens, out, 3484 out_size, obj); 3485 return; 3486 } 3487 3488 if ((n_tokens >= 3) && 3489 (strcmp(tokens[2], "regrd") == 0)) { 3490 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 3491 return; 3492 } 3493 3494 if ((n_tokens >= 3) && 3495 (strcmp(tokens[2], "regwr") == 0)) { 3496 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 3497 return; 3498 } 3499 3500 if ((n_tokens >= 6) && 3501 (strcmp(tokens[2], "meter") == 0) && 3502 (strcmp(tokens[3], "profile") == 0) && 3503 (strcmp(tokens[5], "add") == 0)) { 3504 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 3505 return; 3506 } 3507 3508 if ((n_tokens >= 6) && 3509 (strcmp(tokens[2], "meter") == 0) && 3510 (strcmp(tokens[3], "profile") == 0) && 3511 (strcmp(tokens[5], "delete") == 0)) { 3512 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 3513 return; 3514 } 3515 3516 if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[4], "reset")) { 3517 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 3518 return; 3519 } 3520 3521 if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[4], "set")) { 3522 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 3523 return; 3524 } 3525 3526 if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[4], "stats")) { 3527 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 3528 return; 3529 } 3530 3531 if ((n_tokens >= 3) && 3532 (strcmp(tokens[2], "stats") == 0)) { 3533 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 3534 obj); 3535 return; 3536 } 3537 3538 if ((n_tokens >= 4) && 3539 (strcmp(tokens[2], "mirror") == 0) && 3540 (strcmp(tokens[3], "session") == 0)) { 3541 cmd_pipeline_mirror_session(tokens, n_tokens, out, out_size, obj); 3542 return; 3543 } 3544 } 3545 3546 if (strcmp(tokens[0], "thread") == 0) { 3547 if ((n_tokens >= 5) && 3548 (strcmp(tokens[4], "enable") == 0)) { 3549 cmd_thread_pipeline_enable(tokens, n_tokens, 3550 out, out_size, obj); 3551 return; 3552 } 3553 3554 if ((n_tokens >= 5) && 3555 (strcmp(tokens[4], "disable") == 0)) { 3556 cmd_thread_pipeline_disable(tokens, n_tokens, 3557 out, out_size, obj); 3558 return; 3559 } 3560 } 3561 3562 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 3563 } 3564 3565 int 3566 cli_script_process(const char *file_name, 3567 size_t msg_in_len_max, 3568 size_t msg_out_len_max, 3569 void *obj) 3570 { 3571 char *msg_in = NULL, *msg_out = NULL; 3572 FILE *f = NULL; 3573 3574 /* Check input arguments */ 3575 if ((file_name == NULL) || 3576 (strlen(file_name) == 0) || 3577 (msg_in_len_max == 0) || 3578 (msg_out_len_max == 0)) 3579 return -EINVAL; 3580 3581 msg_in = malloc(msg_in_len_max + 1); 3582 msg_out = malloc(msg_out_len_max + 1); 3583 if ((msg_in == NULL) || 3584 (msg_out == NULL)) { 3585 free(msg_out); 3586 free(msg_in); 3587 return -ENOMEM; 3588 } 3589 3590 /* Open input file */ 3591 f = fopen(file_name, "r"); 3592 if (f == NULL) { 3593 free(msg_out); 3594 free(msg_in); 3595 return -EIO; 3596 } 3597 3598 /* Read file */ 3599 for ( ; ; ) { 3600 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 3601 break; 3602 3603 printf("%s", msg_in); 3604 msg_out[0] = 0; 3605 3606 cli_process(msg_in, 3607 msg_out, 3608 msg_out_len_max, 3609 obj); 3610 3611 if (strlen(msg_out)) 3612 printf("%s", msg_out); 3613 } 3614 3615 /* Close file */ 3616 fclose(f); 3617 free(msg_out); 3618 free(msg_in); 3619 return 0; 3620 } 3621