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