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