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 = 0; 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 = 0; 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> reset\n" 2110 "index from <index0> to <index1>\n" 2111 " | table <table_name> match <field0> ...\n"; 2112 2113 static void 2114 cmd_pipeline_meter_reset(char **tokens, 2115 uint32_t n_tokens, 2116 char *out, 2117 size_t out_size, 2118 void *obj __rte_unused) 2119 { 2120 struct rte_swx_pipeline *p; 2121 struct rte_swx_ctl_pipeline *ctl; 2122 const char *pipeline_name, *name; 2123 2124 if (n_tokens < 6) { 2125 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2126 return; 2127 } 2128 2129 pipeline_name = tokens[1]; 2130 p = rte_swx_pipeline_find(pipeline_name); 2131 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 2132 if (!p || !ctl) { 2133 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2134 return; 2135 } 2136 2137 if (strcmp(tokens[2], "meter")) { 2138 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2139 return; 2140 } 2141 2142 name = tokens[3]; 2143 2144 if (strcmp(tokens[4], "reset")) { 2145 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); 2146 return; 2147 } 2148 2149 /* index. */ 2150 if (!strcmp(tokens[5], "index")) { 2151 uint32_t idx0 = 0, idx1 = 0; 2152 2153 if (n_tokens != 10) { 2154 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2155 return; 2156 } 2157 2158 if (strcmp(tokens[6], "from")) { 2159 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2160 return; 2161 } 2162 2163 if (parser_read_uint32(&idx0, tokens[7])) { 2164 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2165 return; 2166 } 2167 2168 if (strcmp(tokens[8], "to")) { 2169 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2170 return; 2171 } 2172 2173 if (parser_read_uint32(&idx1, tokens[9]) || (idx1 < idx0)) { 2174 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2175 return; 2176 } 2177 2178 for ( ; idx0 <= idx1; idx0++) { 2179 int status; 2180 2181 status = rte_swx_ctl_meter_reset(p, name, idx0); 2182 if (status) { 2183 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2184 return; 2185 } 2186 } 2187 2188 return; 2189 } 2190 2191 /* table. */ 2192 if (!strcmp(tokens[5], "table")) { 2193 struct rte_swx_table_entry *entry; 2194 char *table_name; 2195 int status; 2196 2197 if (n_tokens < 9) { 2198 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2199 return; 2200 } 2201 2202 table_name = tokens[6]; 2203 2204 if (strcmp(tokens[7], "match")) { 2205 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2206 return; 2207 } 2208 2209 entry = parse_table_entry(ctl, table_name, &tokens[7], n_tokens - 7); 2210 if (!entry) { 2211 snprintf(out, out_size, "Invalid match tokens.\n"); 2212 return; 2213 } 2214 2215 status = rte_swx_ctl_meter_reset_with_key(p, name, table_name, entry->key); 2216 table_entry_free(entry); 2217 if (status) { 2218 snprintf(out, out_size, "Command failed.\n"); 2219 return; 2220 } 2221 2222 return; 2223 } 2224 2225 /* anything else. */ 2226 snprintf(out, out_size, "Invalid token %s\n.", tokens[5]); 2227 return; 2228 } 2229 2230 static const char cmd_pipeline_meter_set_help[] = 2231 "pipeline <pipeline_name> meter <meter_array_name> set profile <profile_name>\n" 2232 "index from <index0> to <index1>\n" 2233 " | table <table_name> match <field0> ...\n"; 2234 2235 static void 2236 cmd_pipeline_meter_set(char **tokens, 2237 uint32_t n_tokens, 2238 char *out, 2239 size_t out_size, 2240 void *obj __rte_unused) 2241 { 2242 struct rte_swx_pipeline *p; 2243 struct rte_swx_ctl_pipeline *ctl; 2244 const char *pipeline_name, *name, *profile_name; 2245 2246 if (n_tokens < 8) { 2247 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2248 return; 2249 } 2250 2251 pipeline_name = tokens[1]; 2252 p = rte_swx_pipeline_find(pipeline_name); 2253 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 2254 if (!p || !ctl) { 2255 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2256 return; 2257 } 2258 2259 if (strcmp(tokens[2], "meter")) { 2260 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2261 return; 2262 } 2263 2264 name = tokens[3]; 2265 2266 if (strcmp(tokens[4], "set")) { 2267 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); 2268 return; 2269 } 2270 2271 if (strcmp(tokens[5], "profile")) { 2272 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2273 return; 2274 } 2275 2276 profile_name = tokens[6]; 2277 2278 /* index. */ 2279 if (!strcmp(tokens[7], "index")) { 2280 uint32_t idx0 = 0, idx1 = 0; 2281 2282 if (n_tokens != 12) { 2283 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2284 return; 2285 } 2286 2287 if (strcmp(tokens[8], "from")) { 2288 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2289 return; 2290 } 2291 2292 if (parser_read_uint32(&idx0, tokens[9])) { 2293 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2294 return; 2295 } 2296 2297 if (strcmp(tokens[10], "to")) { 2298 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2299 return; 2300 } 2301 2302 if (parser_read_uint32(&idx1, tokens[11]) || (idx1 < idx0)) { 2303 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2304 return; 2305 } 2306 2307 for ( ; idx0 <= idx1; idx0++) { 2308 int status; 2309 2310 status = rte_swx_ctl_meter_set(p, name, idx0, profile_name); 2311 if (status) { 2312 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2313 return; 2314 } 2315 } 2316 2317 return; 2318 } 2319 2320 /* table. */ 2321 if (!strcmp(tokens[7], "table")) { 2322 struct rte_swx_table_entry *entry; 2323 char *table_name; 2324 int status; 2325 2326 if (n_tokens < 11) { 2327 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2328 return; 2329 } 2330 2331 table_name = tokens[8]; 2332 2333 if (strcmp(tokens[9], "match")) { 2334 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2335 return; 2336 } 2337 2338 entry = parse_table_entry(ctl, table_name, &tokens[9], n_tokens - 9); 2339 if (!entry) { 2340 snprintf(out, out_size, "Invalid match tokens.\n"); 2341 return; 2342 } 2343 2344 status = rte_swx_ctl_meter_set_with_key(p, 2345 name, 2346 table_name, 2347 entry->key, 2348 profile_name); 2349 table_entry_free(entry); 2350 if (status) { 2351 snprintf(out, out_size, "Command failed.\n"); 2352 return; 2353 } 2354 2355 return; 2356 } 2357 2358 /* anything else. */ 2359 snprintf(out, out_size, "Invalid token %s\n.", tokens[7]); 2360 return; 2361 } 2362 2363 static const char cmd_pipeline_meter_stats_help[] = 2364 "pipeline <pipeline_name> meter <meter_array_name> stats\n" 2365 "index from <index0> to <index1>\n" 2366 " | table <table_name> match <field0> ...\n"; 2367 2368 static void 2369 cmd_pipeline_meter_stats(char **tokens, 2370 uint32_t n_tokens, 2371 char *out, 2372 size_t out_size, 2373 void *obj __rte_unused) 2374 { 2375 struct rte_swx_ctl_meter_stats stats; 2376 struct rte_swx_pipeline *p; 2377 struct rte_swx_ctl_pipeline *ctl; 2378 const char *pipeline_name, *name; 2379 2380 if (n_tokens < 6) { 2381 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2382 return; 2383 } 2384 2385 pipeline_name = tokens[1]; 2386 p = rte_swx_pipeline_find(pipeline_name); 2387 ctl = rte_swx_ctl_pipeline_find(pipeline_name); 2388 if (!p || !ctl) { 2389 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2390 return; 2391 } 2392 2393 if (strcmp(tokens[2], "meter")) { 2394 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2395 return; 2396 } 2397 2398 name = tokens[3]; 2399 2400 if (strcmp(tokens[4], "stats")) { 2401 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2402 return; 2403 } 2404 2405 /* index. */ 2406 if (!strcmp(tokens[5], "index")) { 2407 uint32_t idx0 = 0, idx1 = 0; 2408 2409 if (n_tokens != 10) { 2410 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2411 return; 2412 } 2413 2414 if (strcmp(tokens[6], "from")) { 2415 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2416 return; 2417 } 2418 2419 if (parser_read_uint32(&idx0, tokens[7])) { 2420 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2421 return; 2422 } 2423 2424 if (strcmp(tokens[8], "to")) { 2425 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2426 return; 2427 } 2428 2429 if (parser_read_uint32(&idx1, tokens[9]) || (idx1 < idx0)) { 2430 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2431 return; 2432 } 2433 2434 /* Table header. */ 2435 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2436 "-------", 2437 "----------------", "----------------", "----------------", 2438 "----------------", "----------------", "----------------"); 2439 out_size -= strlen(out); 2440 out += strlen(out); 2441 2442 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2443 "METER #", 2444 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2445 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2446 out_size -= strlen(out); 2447 out += strlen(out); 2448 2449 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2450 "-------", 2451 "----------------", "----------------", "----------------", 2452 "----------------", "----------------", "----------------"); 2453 out_size -= strlen(out); 2454 out += strlen(out); 2455 2456 /* Table rows. */ 2457 for ( ; idx0 <= idx1; idx0++) { 2458 int status; 2459 2460 status = rte_swx_ctl_meter_stats_read(p, name, idx0, &stats); 2461 if (status) { 2462 snprintf(out, out_size, "Meter stats error at index %u.\n", idx0); 2463 out_size -= strlen(out); 2464 out += strlen(out); 2465 return; 2466 } 2467 2468 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2469 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2470 idx0, 2471 stats.n_pkts[RTE_COLOR_GREEN], 2472 stats.n_pkts[RTE_COLOR_YELLOW], 2473 stats.n_pkts[RTE_COLOR_RED], 2474 stats.n_bytes[RTE_COLOR_GREEN], 2475 stats.n_bytes[RTE_COLOR_YELLOW], 2476 stats.n_bytes[RTE_COLOR_RED]); 2477 out_size -= strlen(out); 2478 out += strlen(out); 2479 } 2480 2481 return; 2482 } 2483 2484 /* table. */ 2485 if (!strcmp(tokens[5], "table")) { 2486 struct rte_swx_table_entry *entry; 2487 char *table_name; 2488 int status; 2489 2490 if (n_tokens < 9) { 2491 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2492 return; 2493 } 2494 2495 table_name = tokens[6]; 2496 2497 if (strcmp(tokens[7], "match")) { 2498 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2499 return; 2500 } 2501 2502 entry = parse_table_entry(ctl, table_name, &tokens[7], n_tokens - 7); 2503 if (!entry) { 2504 snprintf(out, out_size, "Invalid match tokens.\n"); 2505 return; 2506 } 2507 2508 status = rte_swx_ctl_meter_stats_read_with_key(p, 2509 name, 2510 table_name, 2511 entry->key, 2512 &stats); 2513 table_entry_free(entry); 2514 if (status) { 2515 snprintf(out, out_size, "Command failed.\n"); 2516 return; 2517 } 2518 2519 /* Table header. */ 2520 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2521 "-------", 2522 "----------------", "----------------", "----------------", 2523 "----------------", "----------------", "----------------"); 2524 out_size -= strlen(out); 2525 out += strlen(out); 2526 2527 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2528 "METER #", 2529 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2530 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2531 out_size -= strlen(out); 2532 out += strlen(out); 2533 2534 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2535 "-------", 2536 "----------------", "----------------", "----------------", 2537 "----------------", "----------------", "----------------"); 2538 out_size -= strlen(out); 2539 out += strlen(out); 2540 2541 /* Table row. */ 2542 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2543 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2544 0, 2545 stats.n_pkts[RTE_COLOR_GREEN], 2546 stats.n_pkts[RTE_COLOR_YELLOW], 2547 stats.n_pkts[RTE_COLOR_RED], 2548 stats.n_bytes[RTE_COLOR_GREEN], 2549 stats.n_bytes[RTE_COLOR_YELLOW], 2550 stats.n_bytes[RTE_COLOR_RED]); 2551 out_size -= strlen(out); 2552 out += strlen(out); 2553 2554 return; 2555 } 2556 2557 /* anything else. */ 2558 snprintf(out, out_size, "Invalid token %s\n.", tokens[5]); 2559 return; 2560 } 2561 2562 static const char cmd_pipeline_stats_help[] = 2563 "pipeline <pipeline_name> stats\n"; 2564 2565 static void 2566 cmd_pipeline_stats(char **tokens, 2567 uint32_t n_tokens, 2568 char *out, 2569 size_t out_size, 2570 void *obj __rte_unused) 2571 { 2572 struct rte_swx_ctl_pipeline_info info; 2573 struct rte_swx_pipeline *p; 2574 uint32_t i; 2575 int status; 2576 2577 if (n_tokens != 3) { 2578 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2579 return; 2580 } 2581 2582 p = rte_swx_pipeline_find(tokens[1]); 2583 if (!p) { 2584 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2585 return; 2586 } 2587 2588 if (strcmp(tokens[2], "stats")) { 2589 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2590 return; 2591 } 2592 2593 status = rte_swx_ctl_pipeline_info_get(p, &info); 2594 if (status) { 2595 snprintf(out, out_size, "Pipeline info get error."); 2596 return; 2597 } 2598 2599 snprintf(out, out_size, "Input ports:\n"); 2600 out_size -= strlen(out); 2601 out += strlen(out); 2602 2603 for (i = 0; i < info.n_ports_in; i++) { 2604 struct rte_swx_port_in_stats stats; 2605 2606 rte_swx_ctl_pipeline_port_in_stats_read(p, i, &stats); 2607 2608 snprintf(out, out_size, "\tPort %u:" 2609 " packets %" PRIu64 2610 " bytes %" PRIu64 2611 " empty %" PRIu64 "\n", 2612 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 2613 out_size -= strlen(out); 2614 out += strlen(out); 2615 } 2616 2617 snprintf(out, out_size, "\nOutput ports:\n"); 2618 out_size -= strlen(out); 2619 out += strlen(out); 2620 2621 for (i = 0; i < info.n_ports_out; i++) { 2622 struct rte_swx_port_out_stats stats; 2623 2624 rte_swx_ctl_pipeline_port_out_stats_read(p, i, &stats); 2625 2626 if (i != info.n_ports_out - 1) 2627 snprintf(out, out_size, "\tPort %u:", i); 2628 else 2629 snprintf(out, out_size, "\tDROP:"); 2630 2631 out_size -= strlen(out); 2632 out += strlen(out); 2633 2634 snprintf(out, 2635 out_size, 2636 " packets %" PRIu64 2637 " bytes %" PRIu64 2638 " packets dropped %" PRIu64 2639 " bytes dropped %" PRIu64 2640 " clone %" PRIu64 2641 " clonerr %" PRIu64 "\n", 2642 stats.n_pkts, 2643 stats.n_bytes, 2644 stats.n_pkts_drop, 2645 stats.n_bytes_drop, 2646 stats.n_pkts_clone, 2647 stats.n_pkts_clone_err); 2648 2649 out_size -= strlen(out); 2650 out += strlen(out); 2651 } 2652 2653 snprintf(out, out_size, "\nTables:\n"); 2654 out_size -= strlen(out); 2655 out += strlen(out); 2656 2657 for (i = 0; i < info.n_tables; i++) { 2658 struct rte_swx_ctl_table_info table_info; 2659 uint64_t n_pkts_action[info.n_actions]; 2660 struct rte_swx_table_stats stats = { 2661 .n_pkts_hit = 0, 2662 .n_pkts_miss = 0, 2663 .n_pkts_action = n_pkts_action, 2664 }; 2665 uint32_t j; 2666 2667 status = rte_swx_ctl_table_info_get(p, i, &table_info); 2668 if (status) { 2669 snprintf(out, out_size, "Table info get error."); 2670 return; 2671 } 2672 2673 status = rte_swx_ctl_pipeline_table_stats_read(p, table_info.name, &stats); 2674 if (status) { 2675 snprintf(out, out_size, "Table stats read error."); 2676 return; 2677 } 2678 2679 snprintf(out, out_size, "\tTable %s:\n" 2680 "\t\tHit (packets): %" PRIu64 "\n" 2681 "\t\tMiss (packets): %" PRIu64 "\n", 2682 table_info.name, 2683 stats.n_pkts_hit, 2684 stats.n_pkts_miss); 2685 out_size -= strlen(out); 2686 out += strlen(out); 2687 2688 for (j = 0; j < info.n_actions; j++) { 2689 struct rte_swx_ctl_action_info action_info; 2690 2691 status = rte_swx_ctl_action_info_get(p, j, &action_info); 2692 if (status) { 2693 snprintf(out, out_size, "Action info get error."); 2694 return; 2695 } 2696 2697 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2698 action_info.name, 2699 stats.n_pkts_action[j]); 2700 out_size -= strlen(out); 2701 out += strlen(out); 2702 } 2703 } 2704 2705 snprintf(out, out_size, "\nLearner tables:\n"); 2706 out_size -= strlen(out); 2707 out += strlen(out); 2708 2709 for (i = 0; i < info.n_learners; i++) { 2710 struct rte_swx_ctl_learner_info learner_info; 2711 uint64_t n_pkts_action[info.n_actions]; 2712 struct rte_swx_learner_stats stats = { 2713 .n_pkts_hit = 0, 2714 .n_pkts_miss = 0, 2715 .n_pkts_action = n_pkts_action, 2716 }; 2717 uint32_t j; 2718 2719 status = rte_swx_ctl_learner_info_get(p, i, &learner_info); 2720 if (status) { 2721 snprintf(out, out_size, "Learner table info get error."); 2722 return; 2723 } 2724 2725 status = rte_swx_ctl_pipeline_learner_stats_read(p, learner_info.name, &stats); 2726 if (status) { 2727 snprintf(out, out_size, "Learner table stats read error."); 2728 return; 2729 } 2730 2731 snprintf(out, out_size, "\tLearner table %s:\n" 2732 "\t\tHit (packets): %" PRIu64 "\n" 2733 "\t\tMiss (packets): %" PRIu64 "\n" 2734 "\t\tLearn OK (packets): %" PRIu64 "\n" 2735 "\t\tLearn error (packets): %" PRIu64 "\n" 2736 "\t\tRearm (packets): %" PRIu64 "\n" 2737 "\t\tForget (packets): %" PRIu64 "\n", 2738 learner_info.name, 2739 stats.n_pkts_hit, 2740 stats.n_pkts_miss, 2741 stats.n_pkts_learn_ok, 2742 stats.n_pkts_learn_err, 2743 stats.n_pkts_rearm, 2744 stats.n_pkts_forget); 2745 out_size -= strlen(out); 2746 out += strlen(out); 2747 2748 for (j = 0; j < info.n_actions; j++) { 2749 struct rte_swx_ctl_action_info action_info; 2750 2751 status = rte_swx_ctl_action_info_get(p, j, &action_info); 2752 if (status) { 2753 snprintf(out, out_size, "Action info get error."); 2754 return; 2755 } 2756 2757 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2758 action_info.name, 2759 stats.n_pkts_action[j]); 2760 out_size -= strlen(out); 2761 out += strlen(out); 2762 } 2763 } 2764 } 2765 2766 static const char cmd_pipeline_mirror_session_help[] = 2767 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow " 2768 "truncate <truncation_length>\n"; 2769 2770 static void 2771 cmd_pipeline_mirror_session(char **tokens, 2772 uint32_t n_tokens, 2773 char *out, 2774 size_t out_size, 2775 void *obj __rte_unused) 2776 { 2777 struct rte_swx_pipeline_mirroring_session_params params; 2778 struct rte_swx_pipeline *p; 2779 uint32_t session_id = 0; 2780 int status; 2781 2782 if (n_tokens != 11) { 2783 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2784 return; 2785 } 2786 2787 if (strcmp(tokens[0], "pipeline")) { 2788 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2789 return; 2790 } 2791 2792 p = rte_swx_pipeline_find(tokens[1]); 2793 if (!p) { 2794 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2795 return; 2796 } 2797 2798 if (strcmp(tokens[2], "mirror")) { 2799 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror"); 2800 return; 2801 } 2802 2803 if (strcmp(tokens[3], "session")) { 2804 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "session"); 2805 return; 2806 } 2807 2808 if (parser_read_uint32(&session_id, tokens[4])) { 2809 snprintf(out, out_size, MSG_ARG_INVALID, "session_id"); 2810 return; 2811 } 2812 2813 if (strcmp(tokens[5], "port")) { 2814 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2815 return; 2816 } 2817 2818 if (parser_read_uint32(¶ms.port_id, tokens[6])) { 2819 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2820 return; 2821 } 2822 2823 if (strcmp(tokens[7], "clone")) { 2824 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "clone"); 2825 return; 2826 } 2827 2828 if (!strcmp(tokens[8], "fast")) 2829 params.fast_clone = 1; 2830 else if (!strcmp(tokens[8], "slow")) 2831 params.fast_clone = 0; 2832 else { 2833 snprintf(out, out_size, MSG_ARG_INVALID, "clone"); 2834 return; 2835 } 2836 2837 if (strcmp(tokens[9], "truncate")) { 2838 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "truncate"); 2839 return; 2840 } 2841 2842 if (parser_read_uint32(¶ms.truncation_length, tokens[10])) { 2843 snprintf(out, out_size, MSG_ARG_INVALID, "truncation_length"); 2844 return; 2845 } 2846 2847 status = rte_swx_ctl_pipeline_mirroring_session_set(p, session_id, ¶ms); 2848 if (status) { 2849 snprintf(out, out_size, "Command failed!\n"); 2850 return; 2851 } 2852 } 2853 2854 static const char cmd_thread_pipeline_enable_help[] = 2855 "thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]\n"; 2856 2857 #ifndef TIMER_PERIOD_MS_DEFAULT 2858 #define TIMER_PERIOD_MS_DEFAULT 10 2859 #endif 2860 2861 static void 2862 cmd_thread_pipeline_enable(char **tokens, 2863 uint32_t n_tokens, 2864 char *out, 2865 size_t out_size, 2866 void *obj __rte_unused) 2867 { 2868 char *pipeline_name; 2869 struct rte_swx_pipeline *p; 2870 uint32_t thread_id, timer_period_ms = TIMER_PERIOD_MS_DEFAULT; 2871 int status; 2872 2873 if ((n_tokens != 5) && (n_tokens != 7)) { 2874 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2875 return; 2876 } 2877 2878 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2879 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2880 return; 2881 } 2882 2883 if (strcmp(tokens[2], "pipeline") != 0) { 2884 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2885 return; 2886 } 2887 2888 pipeline_name = tokens[3]; 2889 p = rte_swx_pipeline_find(pipeline_name); 2890 if (!p) { 2891 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2892 return; 2893 } 2894 2895 if (strcmp(tokens[4], "enable") != 0) { 2896 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2897 return; 2898 } 2899 2900 if (n_tokens == 7) { 2901 if (strcmp(tokens[5], "period") != 0) { 2902 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); 2903 return; 2904 } 2905 2906 if (parser_read_uint32(&timer_period_ms, tokens[6]) != 0) { 2907 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); 2908 return; 2909 } 2910 } 2911 2912 status = thread_pipeline_enable(thread_id, p, timer_period_ms); 2913 if (status) { 2914 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 2915 return; 2916 } 2917 } 2918 2919 static const char cmd_thread_pipeline_disable_help[] = 2920 "thread <thread_id> pipeline <pipeline_name> disable\n"; 2921 2922 static void 2923 cmd_thread_pipeline_disable(char **tokens, 2924 uint32_t n_tokens, 2925 char *out, 2926 size_t out_size, 2927 void *obj __rte_unused) 2928 { 2929 struct rte_swx_pipeline *p; 2930 char *pipeline_name; 2931 uint32_t thread_id; 2932 int status; 2933 2934 if (n_tokens != 5) { 2935 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2936 return; 2937 } 2938 2939 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2940 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2941 return; 2942 } 2943 2944 if (strcmp(tokens[2], "pipeline") != 0) { 2945 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2946 return; 2947 } 2948 2949 pipeline_name = tokens[3]; 2950 p = rte_swx_pipeline_find(pipeline_name); 2951 if (!p) { 2952 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2953 return; 2954 } 2955 2956 if (strcmp(tokens[4], "disable") != 0) { 2957 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2958 return; 2959 } 2960 2961 status = thread_pipeline_disable(thread_id, p); 2962 if (status) { 2963 snprintf(out, out_size, MSG_CMD_FAIL, 2964 "thread pipeline disable"); 2965 return; 2966 } 2967 } 2968 2969 static void 2970 cmd_help(char **tokens, 2971 uint32_t n_tokens, 2972 char *out, 2973 size_t out_size, 2974 void *arg __rte_unused) 2975 { 2976 tokens++; 2977 n_tokens--; 2978 2979 if (n_tokens == 0) { 2980 snprintf(out, out_size, 2981 "Type 'help <command>' for command details.\n\n" 2982 "List of commands:\n" 2983 "\tmempool\n" 2984 "\tethdev\n" 2985 "\tpipeline codegen\n" 2986 "\tpipeline libbuild\n" 2987 "\tpipeline build\n" 2988 "\tpipeline table add\n" 2989 "\tpipeline table delete\n" 2990 "\tpipeline table default\n" 2991 "\tpipeline table show\n" 2992 "\tpipeline selector group add\n" 2993 "\tpipeline selector group delete\n" 2994 "\tpipeline selector group member add\n" 2995 "\tpipeline selector group member delete\n" 2996 "\tpipeline selector show\n" 2997 "\tpipeline learner default\n" 2998 "\tpipeline commit\n" 2999 "\tpipeline abort\n" 3000 "\tpipeline regrd\n" 3001 "\tpipeline regwr\n" 3002 "\tpipeline meter profile add\n" 3003 "\tpipeline meter profile delete\n" 3004 "\tpipeline meter reset\n" 3005 "\tpipeline meter set\n" 3006 "\tpipeline meter stats\n" 3007 "\tpipeline stats\n" 3008 "\tpipeline mirror session\n" 3009 "\tthread pipeline enable\n" 3010 "\tthread pipeline disable\n\n"); 3011 return; 3012 } 3013 3014 if (strcmp(tokens[0], "mempool") == 0) { 3015 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 3016 return; 3017 } 3018 3019 if (strcmp(tokens[0], "ethdev") == 0) { 3020 snprintf(out, out_size, "\n%s\n", cmd_ethdev_help); 3021 return; 3022 } 3023 3024 if (strcmp(tokens[0], "ring") == 0) { 3025 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 3026 return; 3027 } 3028 3029 if ((strcmp(tokens[0], "pipeline") == 0) && 3030 (n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) { 3031 snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help); 3032 return; 3033 } 3034 3035 if ((strcmp(tokens[0], "pipeline") == 0) && 3036 (n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) { 3037 snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help); 3038 return; 3039 } 3040 3041 if ((strcmp(tokens[0], "pipeline") == 0) && 3042 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 3043 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 3044 return; 3045 } 3046 3047 if ((strcmp(tokens[0], "pipeline") == 0) && 3048 (n_tokens == 3) && 3049 (strcmp(tokens[1], "table") == 0) && 3050 (strcmp(tokens[2], "add") == 0)) { 3051 snprintf(out, out_size, "\n%s\n", 3052 cmd_pipeline_table_add_help); 3053 return; 3054 } 3055 3056 if ((strcmp(tokens[0], "pipeline") == 0) && 3057 (n_tokens == 3) && 3058 (strcmp(tokens[1], "table") == 0) && 3059 (strcmp(tokens[2], "delete") == 0)) { 3060 snprintf(out, out_size, "\n%s\n", 3061 cmd_pipeline_table_delete_help); 3062 return; 3063 } 3064 3065 if ((strcmp(tokens[0], "pipeline") == 0) && 3066 (n_tokens == 3) && 3067 (strcmp(tokens[1], "table") == 0) && 3068 (strcmp(tokens[2], "default") == 0)) { 3069 snprintf(out, out_size, "\n%s\n", 3070 cmd_pipeline_table_default_help); 3071 return; 3072 } 3073 3074 if ((strcmp(tokens[0], "pipeline") == 0) && 3075 (n_tokens == 3) && 3076 (strcmp(tokens[1], "table") == 0) && 3077 (strcmp(tokens[2], "show") == 0)) { 3078 snprintf(out, out_size, "\n%s\n", 3079 cmd_pipeline_table_show_help); 3080 return; 3081 } 3082 3083 if ((strcmp(tokens[0], "pipeline") == 0) && 3084 (n_tokens == 4) && 3085 (strcmp(tokens[1], "selector") == 0) && 3086 (strcmp(tokens[2], "group") == 0) && 3087 (strcmp(tokens[3], "add") == 0)) { 3088 snprintf(out, out_size, "\n%s\n", 3089 cmd_pipeline_selector_group_add_help); 3090 return; 3091 } 3092 3093 if ((strcmp(tokens[0], "pipeline") == 0) && 3094 (n_tokens == 4) && 3095 (strcmp(tokens[1], "selector") == 0) && 3096 (strcmp(tokens[2], "group") == 0) && 3097 (strcmp(tokens[3], "delete") == 0)) { 3098 snprintf(out, out_size, "\n%s\n", 3099 cmd_pipeline_selector_group_delete_help); 3100 return; 3101 } 3102 3103 if ((strcmp(tokens[0], "pipeline") == 0) && 3104 (n_tokens == 5) && 3105 (strcmp(tokens[1], "selector") == 0) && 3106 (strcmp(tokens[2], "group") == 0) && 3107 (strcmp(tokens[3], "member") == 0) && 3108 (strcmp(tokens[4], "add") == 0)) { 3109 snprintf(out, out_size, "\n%s\n", 3110 cmd_pipeline_selector_group_member_add_help); 3111 return; 3112 } 3113 3114 if ((strcmp(tokens[0], "pipeline") == 0) && 3115 (n_tokens == 5) && 3116 (strcmp(tokens[1], "selector") == 0) && 3117 (strcmp(tokens[2], "group") == 0) && 3118 (strcmp(tokens[3], "member") == 0) && 3119 (strcmp(tokens[4], "delete") == 0)) { 3120 snprintf(out, out_size, "\n%s\n", 3121 cmd_pipeline_selector_group_member_delete_help); 3122 return; 3123 } 3124 3125 if ((strcmp(tokens[0], "pipeline") == 0) && 3126 (n_tokens == 3) && 3127 (strcmp(tokens[1], "selector") == 0) && 3128 (strcmp(tokens[2], "show") == 0)) { 3129 snprintf(out, out_size, "\n%s\n", 3130 cmd_pipeline_selector_show_help); 3131 return; 3132 } 3133 3134 if ((strcmp(tokens[0], "pipeline") == 0) && 3135 (n_tokens == 3) && 3136 (strcmp(tokens[1], "learner") == 0) && 3137 (strcmp(tokens[2], "default") == 0)) { 3138 snprintf(out, out_size, "\n%s\n", 3139 cmd_pipeline_learner_default_help); 3140 return; 3141 } 3142 3143 if ((strcmp(tokens[0], "pipeline") == 0) && 3144 (n_tokens == 2) && 3145 (strcmp(tokens[1], "commit") == 0)) { 3146 snprintf(out, out_size, "\n%s\n", 3147 cmd_pipeline_commit_help); 3148 return; 3149 } 3150 3151 if ((strcmp(tokens[0], "pipeline") == 0) && 3152 (n_tokens == 2) && 3153 (strcmp(tokens[1], "abort") == 0)) { 3154 snprintf(out, out_size, "\n%s\n", 3155 cmd_pipeline_abort_help); 3156 return; 3157 } 3158 3159 if ((strcmp(tokens[0], "pipeline") == 0) && 3160 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 3161 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 3162 return; 3163 } 3164 3165 if ((strcmp(tokens[0], "pipeline") == 0) && 3166 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 3167 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 3168 return; 3169 } 3170 3171 if (!strcmp(tokens[0], "pipeline") && 3172 (n_tokens == 4) && !strcmp(tokens[1], "meter") 3173 && !strcmp(tokens[2], "profile") 3174 && !strcmp(tokens[3], "add")) { 3175 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 3176 return; 3177 } 3178 3179 if (!strcmp(tokens[0], "pipeline") && 3180 (n_tokens == 4) && !strcmp(tokens[1], "meter") 3181 && !strcmp(tokens[2], "profile") 3182 && !strcmp(tokens[3], "delete")) { 3183 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 3184 return; 3185 } 3186 3187 if (!strcmp(tokens[0], "pipeline") && 3188 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3189 && !strcmp(tokens[2], "reset")) { 3190 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 3191 return; 3192 } 3193 3194 if (!strcmp(tokens[0], "pipeline") && 3195 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3196 && !strcmp(tokens[2], "set")) { 3197 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 3198 return; 3199 } 3200 3201 if (!strcmp(tokens[0], "pipeline") && 3202 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3203 && !strcmp(tokens[2], "stats")) { 3204 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 3205 return; 3206 } 3207 3208 if ((strcmp(tokens[0], "pipeline") == 0) && 3209 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 3210 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 3211 return; 3212 } 3213 3214 if (!strcmp(tokens[0], "pipeline") && 3215 (n_tokens == 3) && !strcmp(tokens[1], "mirror") 3216 && !strcmp(tokens[2], "session")) { 3217 snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_session_help); 3218 return; 3219 } 3220 3221 if ((n_tokens == 3) && 3222 (strcmp(tokens[0], "thread") == 0) && 3223 (strcmp(tokens[1], "pipeline") == 0)) { 3224 if (strcmp(tokens[2], "enable") == 0) { 3225 snprintf(out, out_size, "\n%s\n", 3226 cmd_thread_pipeline_enable_help); 3227 return; 3228 } 3229 3230 if (strcmp(tokens[2], "disable") == 0) { 3231 snprintf(out, out_size, "\n%s\n", 3232 cmd_thread_pipeline_disable_help); 3233 return; 3234 } 3235 } 3236 3237 snprintf(out, out_size, "Invalid command\n"); 3238 } 3239 3240 void 3241 cli_process(char *in, char *out, size_t out_size, void *obj) 3242 { 3243 char *tokens[CMD_MAX_TOKENS]; 3244 uint32_t n_tokens = RTE_DIM(tokens); 3245 int status; 3246 3247 if (is_comment(in)) 3248 return; 3249 3250 status = parse_tokenize_string(in, tokens, &n_tokens); 3251 if (status) { 3252 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 3253 return; 3254 } 3255 3256 if (n_tokens == 0) 3257 return; 3258 3259 if (strcmp(tokens[0], "help") == 0) { 3260 cmd_help(tokens, n_tokens, out, out_size, obj); 3261 return; 3262 } 3263 3264 if (strcmp(tokens[0], "mempool") == 0) { 3265 cmd_mempool(tokens, n_tokens, out, out_size, obj); 3266 return; 3267 } 3268 3269 if (strcmp(tokens[0], "ethdev") == 0) { 3270 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 3271 cmd_ethdev_show(tokens, n_tokens, out, out_size, obj); 3272 return; 3273 } 3274 3275 cmd_ethdev(tokens, n_tokens, out, out_size, obj); 3276 return; 3277 } 3278 3279 if (strcmp(tokens[0], "ring") == 0) { 3280 cmd_ring(tokens, n_tokens, out, out_size, obj); 3281 return; 3282 } 3283 3284 if (strcmp(tokens[0], "pipeline") == 0) { 3285 if ((n_tokens >= 3) && 3286 (strcmp(tokens[1], "codegen") == 0)) { 3287 cmd_pipeline_codegen(tokens, n_tokens, out, out_size, 3288 obj); 3289 return; 3290 } 3291 3292 if ((n_tokens >= 3) && 3293 (strcmp(tokens[1], "libbuild") == 0)) { 3294 cmd_pipeline_libbuild(tokens, n_tokens, out, out_size, 3295 obj); 3296 return; 3297 } 3298 3299 if ((n_tokens >= 3) && 3300 (strcmp(tokens[2], "build") == 0)) { 3301 cmd_pipeline_build(tokens, n_tokens, out, out_size, 3302 obj); 3303 return; 3304 } 3305 3306 if ((n_tokens >= 5) && 3307 (strcmp(tokens[2], "table") == 0) && 3308 (strcmp(tokens[4], "add") == 0)) { 3309 cmd_pipeline_table_add(tokens, n_tokens, out, 3310 out_size, obj); 3311 return; 3312 } 3313 3314 if ((n_tokens >= 5) && 3315 (strcmp(tokens[2], "table") == 0) && 3316 (strcmp(tokens[4], "delete") == 0)) { 3317 cmd_pipeline_table_delete(tokens, n_tokens, out, 3318 out_size, obj); 3319 return; 3320 } 3321 3322 if ((n_tokens >= 5) && 3323 (strcmp(tokens[2], "table") == 0) && 3324 (strcmp(tokens[4], "default") == 0)) { 3325 cmd_pipeline_table_default(tokens, n_tokens, out, 3326 out_size, obj); 3327 return; 3328 } 3329 3330 if ((n_tokens >= 5) && 3331 (strcmp(tokens[2], "table") == 0) && 3332 (strcmp(tokens[4], "show") == 0)) { 3333 cmd_pipeline_table_show(tokens, n_tokens, out, 3334 out_size, obj); 3335 return; 3336 } 3337 3338 if ((n_tokens >= 6) && 3339 (strcmp(tokens[2], "selector") == 0) && 3340 (strcmp(tokens[4], "group") == 0) && 3341 (strcmp(tokens[5], "add") == 0)) { 3342 cmd_pipeline_selector_group_add(tokens, n_tokens, out, 3343 out_size, obj); 3344 return; 3345 } 3346 3347 if ((n_tokens >= 6) && 3348 (strcmp(tokens[2], "selector") == 0) && 3349 (strcmp(tokens[4], "group") == 0) && 3350 (strcmp(tokens[5], "delete") == 0)) { 3351 cmd_pipeline_selector_group_delete(tokens, n_tokens, out, 3352 out_size, obj); 3353 return; 3354 } 3355 3356 if ((n_tokens >= 7) && 3357 (strcmp(tokens[2], "selector") == 0) && 3358 (strcmp(tokens[4], "group") == 0) && 3359 (strcmp(tokens[5], "member") == 0) && 3360 (strcmp(tokens[6], "add") == 0)) { 3361 cmd_pipeline_selector_group_member_add(tokens, n_tokens, out, 3362 out_size, obj); 3363 return; 3364 } 3365 3366 if ((n_tokens >= 7) && 3367 (strcmp(tokens[2], "selector") == 0) && 3368 (strcmp(tokens[4], "group") == 0) && 3369 (strcmp(tokens[5], "member") == 0) && 3370 (strcmp(tokens[6], "delete") == 0)) { 3371 cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out, 3372 out_size, obj); 3373 return; 3374 } 3375 3376 if ((n_tokens >= 5) && 3377 (strcmp(tokens[2], "selector") == 0) && 3378 (strcmp(tokens[4], "show") == 0)) { 3379 cmd_pipeline_selector_show(tokens, n_tokens, out, 3380 out_size, obj); 3381 return; 3382 } 3383 3384 if ((n_tokens >= 5) && 3385 (strcmp(tokens[2], "learner") == 0) && 3386 (strcmp(tokens[4], "default") == 0)) { 3387 cmd_pipeline_learner_default(tokens, n_tokens, out, 3388 out_size, obj); 3389 return; 3390 } 3391 3392 if ((n_tokens >= 3) && 3393 (strcmp(tokens[2], "commit") == 0)) { 3394 cmd_pipeline_commit(tokens, n_tokens, out, 3395 out_size, obj); 3396 return; 3397 } 3398 3399 if ((n_tokens >= 3) && 3400 (strcmp(tokens[2], "abort") == 0)) { 3401 cmd_pipeline_abort(tokens, n_tokens, out, 3402 out_size, obj); 3403 return; 3404 } 3405 3406 if ((n_tokens >= 3) && 3407 (strcmp(tokens[2], "regrd") == 0)) { 3408 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 3409 return; 3410 } 3411 3412 if ((n_tokens >= 3) && 3413 (strcmp(tokens[2], "regwr") == 0)) { 3414 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 3415 return; 3416 } 3417 3418 if ((n_tokens >= 6) && 3419 (strcmp(tokens[2], "meter") == 0) && 3420 (strcmp(tokens[3], "profile") == 0) && 3421 (strcmp(tokens[5], "add") == 0)) { 3422 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 3423 return; 3424 } 3425 3426 if ((n_tokens >= 6) && 3427 (strcmp(tokens[2], "meter") == 0) && 3428 (strcmp(tokens[3], "profile") == 0) && 3429 (strcmp(tokens[5], "delete") == 0)) { 3430 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 3431 return; 3432 } 3433 3434 if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[4], "reset")) { 3435 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 3436 return; 3437 } 3438 3439 if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[4], "set")) { 3440 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 3441 return; 3442 } 3443 3444 if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[4], "stats")) { 3445 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 3446 return; 3447 } 3448 3449 if ((n_tokens >= 3) && 3450 (strcmp(tokens[2], "stats") == 0)) { 3451 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 3452 obj); 3453 return; 3454 } 3455 3456 if ((n_tokens >= 4) && 3457 (strcmp(tokens[2], "mirror") == 0) && 3458 (strcmp(tokens[3], "session") == 0)) { 3459 cmd_pipeline_mirror_session(tokens, n_tokens, out, out_size, obj); 3460 return; 3461 } 3462 } 3463 3464 if (strcmp(tokens[0], "thread") == 0) { 3465 if ((n_tokens >= 5) && 3466 (strcmp(tokens[4], "enable") == 0)) { 3467 cmd_thread_pipeline_enable(tokens, n_tokens, 3468 out, out_size, obj); 3469 return; 3470 } 3471 3472 if ((n_tokens >= 5) && 3473 (strcmp(tokens[4], "disable") == 0)) { 3474 cmd_thread_pipeline_disable(tokens, n_tokens, 3475 out, out_size, obj); 3476 return; 3477 } 3478 } 3479 3480 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 3481 } 3482 3483 int 3484 cli_script_process(const char *file_name, 3485 size_t msg_in_len_max, 3486 size_t msg_out_len_max, 3487 void *obj) 3488 { 3489 char *msg_in = NULL, *msg_out = NULL; 3490 FILE *f = NULL; 3491 3492 /* Check input arguments */ 3493 if ((file_name == NULL) || 3494 (strlen(file_name) == 0) || 3495 (msg_in_len_max == 0) || 3496 (msg_out_len_max == 0)) 3497 return -EINVAL; 3498 3499 msg_in = malloc(msg_in_len_max + 1); 3500 msg_out = malloc(msg_out_len_max + 1); 3501 if ((msg_in == NULL) || 3502 (msg_out == NULL)) { 3503 free(msg_out); 3504 free(msg_in); 3505 return -ENOMEM; 3506 } 3507 3508 /* Open input file */ 3509 f = fopen(file_name, "r"); 3510 if (f == NULL) { 3511 free(msg_out); 3512 free(msg_in); 3513 return -EIO; 3514 } 3515 3516 /* Read file */ 3517 for ( ; ; ) { 3518 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 3519 break; 3520 3521 printf("%s", msg_in); 3522 msg_out[0] = 0; 3523 3524 cli_process(msg_in, 3525 msg_out, 3526 msg_out_len_max, 3527 obj); 3528 3529 if (strlen(msg_out)) 3530 printf("%s", msg_out); 3531 } 3532 3533 /* Close file */ 3534 fclose(f); 3535 free(msg_out); 3536 free(msg_in); 3537 return 0; 3538 } 3539