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