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