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