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