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