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