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