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