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