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 int 1831 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p, 1832 const char *learner_name, 1833 FILE *file, 1834 uint32_t *file_line_number) 1835 { 1836 char *line = NULL; 1837 uint32_t line_id = 0; 1838 int status = 0; 1839 1840 /* Buffer allocation. */ 1841 line = malloc(MAX_LINE_SIZE); 1842 if (!line) 1843 return -ENOMEM; 1844 1845 /* File read. */ 1846 for (line_id = 1; ; line_id++) { 1847 struct rte_swx_table_entry *entry; 1848 int is_blank_or_comment; 1849 1850 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1851 break; 1852 1853 entry = rte_swx_ctl_pipeline_learner_default_entry_read(p, 1854 learner_name, 1855 line, 1856 &is_blank_or_comment); 1857 if (!entry) { 1858 if (is_blank_or_comment) 1859 continue; 1860 1861 status = -EINVAL; 1862 goto error; 1863 } 1864 1865 status = rte_swx_ctl_pipeline_learner_default_entry_add(p, 1866 learner_name, 1867 entry); 1868 table_entry_free(entry); 1869 if (status) 1870 goto error; 1871 } 1872 1873 error: 1874 *file_line_number = line_id; 1875 free(line); 1876 return status; 1877 } 1878 1879 static const char cmd_pipeline_learner_default_help[] = 1880 "pipeline <pipeline_name> learner <learner_name> default <file_name>\n"; 1881 1882 static void 1883 cmd_pipeline_learner_default(char **tokens, 1884 uint32_t n_tokens, 1885 char *out, 1886 size_t out_size, 1887 void *obj) 1888 { 1889 struct pipeline *p; 1890 char *pipeline_name, *learner_name, *file_name; 1891 FILE *file = NULL; 1892 uint32_t file_line_number = 0; 1893 int status; 1894 1895 if (n_tokens != 6) { 1896 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1897 return; 1898 } 1899 1900 pipeline_name = tokens[1]; 1901 p = pipeline_find(obj, pipeline_name); 1902 if (!p || !p->ctl) { 1903 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1904 return; 1905 } 1906 1907 learner_name = tokens[3]; 1908 1909 file_name = tokens[5]; 1910 file = fopen(file_name, "r"); 1911 if (!file) { 1912 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1913 return; 1914 } 1915 1916 status = pipeline_learner_default_entry_add(p->ctl, 1917 learner_name, 1918 file, 1919 &file_line_number); 1920 if (status) 1921 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1922 file_name, 1923 file_line_number); 1924 1925 fclose(file); 1926 } 1927 1928 static const char cmd_pipeline_commit_help[] = 1929 "pipeline <pipeline_name> commit\n"; 1930 1931 static void 1932 cmd_pipeline_commit(char **tokens, 1933 uint32_t n_tokens, 1934 char *out, 1935 size_t out_size, 1936 void *obj) 1937 { 1938 struct pipeline *p; 1939 char *pipeline_name; 1940 int status; 1941 1942 if (n_tokens != 3) { 1943 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1944 return; 1945 } 1946 1947 pipeline_name = tokens[1]; 1948 p = pipeline_find(obj, pipeline_name); 1949 if (!p || !p->ctl) { 1950 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1951 return; 1952 } 1953 1954 status = rte_swx_ctl_pipeline_commit(p->ctl, 1); 1955 if (status) 1956 snprintf(out, out_size, "Commit failed. " 1957 "Use \"commit\" to retry or \"abort\" to discard the pending work.\n"); 1958 } 1959 1960 static const char cmd_pipeline_abort_help[] = 1961 "pipeline <pipeline_name> abort\n"; 1962 1963 static void 1964 cmd_pipeline_abort(char **tokens, 1965 uint32_t n_tokens, 1966 char *out, 1967 size_t out_size, 1968 void *obj) 1969 { 1970 struct pipeline *p; 1971 char *pipeline_name; 1972 1973 if (n_tokens != 3) { 1974 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1975 return; 1976 } 1977 1978 pipeline_name = tokens[1]; 1979 p = pipeline_find(obj, pipeline_name); 1980 if (!p || !p->ctl) { 1981 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1982 return; 1983 } 1984 1985 rte_swx_ctl_pipeline_abort(p->ctl); 1986 } 1987 1988 static const char cmd_pipeline_regrd_help[] = 1989 "pipeline <pipeline_name> regrd <register_array_name> <index>\n"; 1990 1991 static void 1992 cmd_pipeline_regrd(char **tokens, 1993 uint32_t n_tokens, 1994 char *out, 1995 size_t out_size, 1996 void *obj) 1997 { 1998 struct pipeline *p; 1999 const char *name; 2000 uint64_t value; 2001 uint32_t idx; 2002 int status; 2003 2004 if (n_tokens != 5) { 2005 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2006 return; 2007 } 2008 2009 p = pipeline_find(obj, tokens[1]); 2010 if (!p || !p->ctl) { 2011 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2012 return; 2013 } 2014 2015 if (strcmp(tokens[2], "regrd")) { 2016 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd"); 2017 return; 2018 } 2019 2020 name = tokens[3]; 2021 2022 if (parser_read_uint32(&idx, tokens[4])) { 2023 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 2024 return; 2025 } 2026 2027 status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value); 2028 if (status) { 2029 snprintf(out, out_size, "Command failed.\n"); 2030 return; 2031 } 2032 2033 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 2034 } 2035 2036 static const char cmd_pipeline_regwr_help[] = 2037 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n"; 2038 2039 static void 2040 cmd_pipeline_regwr(char **tokens, 2041 uint32_t n_tokens, 2042 char *out, 2043 size_t out_size, 2044 void *obj) 2045 { 2046 struct pipeline *p; 2047 const char *name; 2048 uint64_t value; 2049 uint32_t idx; 2050 int status; 2051 2052 if (n_tokens != 6) { 2053 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2054 return; 2055 } 2056 2057 p = pipeline_find(obj, tokens[1]); 2058 if (!p || !p->ctl) { 2059 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2060 return; 2061 } 2062 2063 if (strcmp(tokens[2], "regwr")) { 2064 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr"); 2065 return; 2066 } 2067 2068 name = tokens[3]; 2069 2070 if (parser_read_uint32(&idx, tokens[4])) { 2071 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 2072 return; 2073 } 2074 2075 if (parser_read_uint64(&value, tokens[5])) { 2076 snprintf(out, out_size, MSG_ARG_INVALID, "value"); 2077 return; 2078 } 2079 2080 status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value); 2081 if (status) { 2082 snprintf(out, out_size, "Command failed.\n"); 2083 return; 2084 } 2085 } 2086 2087 static const char cmd_pipeline_meter_profile_add_help[] = 2088 "pipeline <pipeline_name> meter profile <profile_name> add " 2089 "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 2090 2091 static void 2092 cmd_pipeline_meter_profile_add(char **tokens, 2093 uint32_t n_tokens, 2094 char *out, 2095 size_t out_size, 2096 void *obj) 2097 { 2098 struct rte_meter_trtcm_params params; 2099 struct pipeline *p; 2100 const char *profile_name; 2101 int status; 2102 2103 if (n_tokens != 14) { 2104 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2105 return; 2106 } 2107 2108 p = pipeline_find(obj, tokens[1]); 2109 if (!p || !p->ctl) { 2110 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2111 return; 2112 } 2113 2114 if (strcmp(tokens[2], "meter")) { 2115 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2116 return; 2117 } 2118 2119 if (strcmp(tokens[3], "profile")) { 2120 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2121 return; 2122 } 2123 2124 profile_name = tokens[4]; 2125 2126 if (strcmp(tokens[5], "add")) { 2127 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 2128 return; 2129 } 2130 2131 if (strcmp(tokens[6], "cir")) { 2132 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 2133 return; 2134 } 2135 2136 if (parser_read_uint64(¶ms.cir, tokens[7])) { 2137 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 2138 return; 2139 } 2140 2141 if (strcmp(tokens[8], "pir")) { 2142 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 2143 return; 2144 } 2145 2146 if (parser_read_uint64(¶ms.pir, tokens[9])) { 2147 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 2148 return; 2149 } 2150 2151 if (strcmp(tokens[10], "cbs")) { 2152 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 2153 return; 2154 } 2155 2156 if (parser_read_uint64(¶ms.cbs, tokens[11])) { 2157 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 2158 return; 2159 } 2160 2161 if (strcmp(tokens[12], "pbs")) { 2162 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 2163 return; 2164 } 2165 2166 if (parser_read_uint64(¶ms.pbs, tokens[13])) { 2167 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 2168 return; 2169 } 2170 2171 status = rte_swx_ctl_meter_profile_add(p->p, profile_name, ¶ms); 2172 if (status) { 2173 snprintf(out, out_size, "Command failed.\n"); 2174 return; 2175 } 2176 } 2177 2178 static const char cmd_pipeline_meter_profile_delete_help[] = 2179 "pipeline <pipeline_name> meter profile <profile_name> delete\n"; 2180 2181 static void 2182 cmd_pipeline_meter_profile_delete(char **tokens, 2183 uint32_t n_tokens, 2184 char *out, 2185 size_t out_size, 2186 void *obj) 2187 { 2188 struct pipeline *p; 2189 const char *profile_name; 2190 int status; 2191 2192 if (n_tokens != 6) { 2193 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2194 return; 2195 } 2196 2197 p = pipeline_find(obj, tokens[1]); 2198 if (!p || !p->ctl) { 2199 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2200 return; 2201 } 2202 2203 if (strcmp(tokens[2], "meter")) { 2204 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2205 return; 2206 } 2207 2208 if (strcmp(tokens[3], "profile")) { 2209 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2210 return; 2211 } 2212 2213 profile_name = tokens[4]; 2214 2215 if (strcmp(tokens[5], "delete")) { 2216 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 2217 return; 2218 } 2219 2220 status = rte_swx_ctl_meter_profile_delete(p->p, profile_name); 2221 if (status) { 2222 snprintf(out, out_size, "Command failed.\n"); 2223 return; 2224 } 2225 } 2226 2227 static const char cmd_pipeline_meter_reset_help[] = 2228 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2229 "reset\n"; 2230 2231 static void 2232 cmd_pipeline_meter_reset(char **tokens, 2233 uint32_t n_tokens, 2234 char *out, 2235 size_t out_size, 2236 void *obj) 2237 { 2238 struct pipeline *p; 2239 const char *name; 2240 uint32_t idx0 = 0, idx1 = 0; 2241 2242 if (n_tokens != 9) { 2243 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2244 return; 2245 } 2246 2247 p = pipeline_find(obj, tokens[1]); 2248 if (!p || !p->ctl) { 2249 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2250 return; 2251 } 2252 2253 if (strcmp(tokens[2], "meter")) { 2254 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2255 return; 2256 } 2257 2258 name = tokens[3]; 2259 2260 if (strcmp(tokens[4], "from")) { 2261 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2262 return; 2263 } 2264 2265 if (parser_read_uint32(&idx0, tokens[5])) { 2266 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2267 return; 2268 } 2269 2270 if (strcmp(tokens[6], "to")) { 2271 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2272 return; 2273 } 2274 2275 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2276 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2277 return; 2278 } 2279 2280 if (strcmp(tokens[8], "reset")) { 2281 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); 2282 return; 2283 } 2284 2285 for ( ; idx0 <= idx1; idx0++) { 2286 int status; 2287 2288 status = rte_swx_ctl_meter_reset(p->p, name, idx0); 2289 if (status) { 2290 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2291 return; 2292 } 2293 } 2294 } 2295 2296 static const char cmd_pipeline_meter_set_help[] = 2297 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2298 "set profile <profile_name>\n"; 2299 2300 static void 2301 cmd_pipeline_meter_set(char **tokens, 2302 uint32_t n_tokens, 2303 char *out, 2304 size_t out_size, 2305 void *obj) 2306 { 2307 struct pipeline *p; 2308 const char *name, *profile_name; 2309 uint32_t idx0 = 0, idx1 = 0; 2310 2311 if (n_tokens != 11) { 2312 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2313 return; 2314 } 2315 2316 p = pipeline_find(obj, tokens[1]); 2317 if (!p || !p->ctl) { 2318 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2319 return; 2320 } 2321 2322 if (strcmp(tokens[2], "meter")) { 2323 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2324 return; 2325 } 2326 2327 name = tokens[3]; 2328 2329 if (strcmp(tokens[4], "from")) { 2330 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2331 return; 2332 } 2333 2334 if (parser_read_uint32(&idx0, tokens[5])) { 2335 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2336 return; 2337 } 2338 2339 if (strcmp(tokens[6], "to")) { 2340 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2341 return; 2342 } 2343 2344 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2345 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2346 return; 2347 } 2348 2349 if (strcmp(tokens[8], "set")) { 2350 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); 2351 return; 2352 } 2353 2354 if (strcmp(tokens[9], "profile")) { 2355 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2356 return; 2357 } 2358 2359 profile_name = tokens[10]; 2360 2361 for ( ; idx0 <= idx1; idx0++) { 2362 int status; 2363 2364 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name); 2365 if (status) { 2366 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2367 return; 2368 } 2369 } 2370 } 2371 2372 static const char cmd_pipeline_meter_stats_help[] = 2373 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2374 "stats\n"; 2375 2376 static void 2377 cmd_pipeline_meter_stats(char **tokens, 2378 uint32_t n_tokens, 2379 char *out, 2380 size_t out_size, 2381 void *obj) 2382 { 2383 struct rte_swx_ctl_meter_stats stats; 2384 struct pipeline *p; 2385 const char *name; 2386 uint32_t idx0 = 0, idx1 = 0; 2387 2388 if (n_tokens != 9) { 2389 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2390 return; 2391 } 2392 2393 p = pipeline_find(obj, tokens[1]); 2394 if (!p || !p->ctl) { 2395 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2396 return; 2397 } 2398 2399 if (strcmp(tokens[2], "meter")) { 2400 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2401 return; 2402 } 2403 2404 name = tokens[3]; 2405 2406 if (strcmp(tokens[4], "from")) { 2407 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2408 return; 2409 } 2410 2411 if (parser_read_uint32(&idx0, tokens[5])) { 2412 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2413 return; 2414 } 2415 2416 if (strcmp(tokens[6], "to")) { 2417 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2418 return; 2419 } 2420 2421 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2422 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2423 return; 2424 } 2425 2426 if (strcmp(tokens[8], "stats")) { 2427 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2428 return; 2429 } 2430 2431 /* Table header. */ 2432 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2433 "-------", 2434 "----------------", "----------------", "----------------", 2435 "----------------", "----------------", "----------------"); 2436 out_size -= strlen(out); 2437 out += strlen(out); 2438 2439 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2440 "METER #", 2441 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2442 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2443 out_size -= strlen(out); 2444 out += strlen(out); 2445 2446 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2447 "-------", 2448 "----------------", "----------------", "----------------", 2449 "----------------", "----------------", "----------------"); 2450 out_size -= strlen(out); 2451 out += strlen(out); 2452 2453 /* Table rows. */ 2454 for ( ; idx0 <= idx1; idx0++) { 2455 int status; 2456 2457 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats); 2458 if (status) { 2459 snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0); 2460 out_size -= strlen(out); 2461 out += strlen(out); 2462 return; 2463 } 2464 2465 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2466 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2467 idx0, 2468 stats.n_pkts[RTE_COLOR_GREEN], 2469 stats.n_pkts[RTE_COLOR_YELLOW], 2470 stats.n_pkts[RTE_COLOR_RED], 2471 stats.n_bytes[RTE_COLOR_GREEN], 2472 stats.n_bytes[RTE_COLOR_YELLOW], 2473 stats.n_bytes[RTE_COLOR_RED]); 2474 out_size -= strlen(out); 2475 out += strlen(out); 2476 } 2477 } 2478 2479 static const char cmd_pipeline_stats_help[] = 2480 "pipeline <pipeline_name> stats\n"; 2481 2482 static void 2483 cmd_pipeline_stats(char **tokens, 2484 uint32_t n_tokens, 2485 char *out, 2486 size_t out_size, 2487 void *obj) 2488 { 2489 struct rte_swx_ctl_pipeline_info info; 2490 struct pipeline *p; 2491 uint32_t i; 2492 int status; 2493 2494 if (n_tokens != 3) { 2495 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2496 return; 2497 } 2498 2499 p = pipeline_find(obj, tokens[1]); 2500 if (!p || !p->ctl) { 2501 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2502 return; 2503 } 2504 2505 if (strcmp(tokens[2], "stats")) { 2506 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2507 return; 2508 } 2509 2510 status = rte_swx_ctl_pipeline_info_get(p->p, &info); 2511 if (status) { 2512 snprintf(out, out_size, "Pipeline info get error."); 2513 return; 2514 } 2515 2516 snprintf(out, out_size, "Input ports:\n"); 2517 out_size -= strlen(out); 2518 out += strlen(out); 2519 2520 for (i = 0; i < info.n_ports_in; i++) { 2521 struct rte_swx_port_in_stats stats; 2522 2523 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats); 2524 2525 snprintf(out, out_size, "\tPort %u:" 2526 " packets %" PRIu64 2527 " bytes %" PRIu64 2528 " empty %" PRIu64 "\n", 2529 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 2530 out_size -= strlen(out); 2531 out += strlen(out); 2532 } 2533 2534 snprintf(out, out_size, "\nOutput ports:\n"); 2535 out_size -= strlen(out); 2536 out += strlen(out); 2537 2538 for (i = 0; i < info.n_ports_out; i++) { 2539 struct rte_swx_port_out_stats stats; 2540 2541 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); 2542 2543 snprintf(out, out_size, "\tPort %u:" 2544 " packets %" PRIu64 2545 " bytes %" PRIu64 "\n", 2546 i, stats.n_pkts, stats.n_bytes); 2547 out_size -= strlen(out); 2548 out += strlen(out); 2549 } 2550 2551 snprintf(out, out_size, "\nTables:\n"); 2552 out_size -= strlen(out); 2553 out += strlen(out); 2554 2555 for (i = 0; i < info.n_tables; i++) { 2556 struct rte_swx_ctl_table_info table_info; 2557 uint64_t n_pkts_action[info.n_actions]; 2558 struct rte_swx_table_stats stats = { 2559 .n_pkts_hit = 0, 2560 .n_pkts_miss = 0, 2561 .n_pkts_action = n_pkts_action, 2562 }; 2563 uint32_t j; 2564 2565 status = rte_swx_ctl_table_info_get(p->p, i, &table_info); 2566 if (status) { 2567 snprintf(out, out_size, "Table info get error."); 2568 return; 2569 } 2570 2571 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats); 2572 if (status) { 2573 snprintf(out, out_size, "Table stats read error."); 2574 return; 2575 } 2576 2577 snprintf(out, out_size, "\tTable %s:\n" 2578 "\t\tHit (packets): %" PRIu64 "\n" 2579 "\t\tMiss (packets): %" PRIu64 "\n", 2580 table_info.name, 2581 stats.n_pkts_hit, 2582 stats.n_pkts_miss); 2583 out_size -= strlen(out); 2584 out += strlen(out); 2585 2586 for (j = 0; j < info.n_actions; j++) { 2587 struct rte_swx_ctl_action_info action_info; 2588 2589 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 2590 if (status) { 2591 snprintf(out, out_size, "Action info get error."); 2592 return; 2593 } 2594 2595 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2596 action_info.name, 2597 stats.n_pkts_action[j]); 2598 out_size -= strlen(out); 2599 out += strlen(out); 2600 } 2601 } 2602 2603 snprintf(out, out_size, "\nLearner tables:\n"); 2604 out_size -= strlen(out); 2605 out += strlen(out); 2606 2607 for (i = 0; i < info.n_learners; i++) { 2608 struct rte_swx_ctl_learner_info learner_info; 2609 uint64_t n_pkts_action[info.n_actions]; 2610 struct rte_swx_learner_stats stats = { 2611 .n_pkts_hit = 0, 2612 .n_pkts_miss = 0, 2613 .n_pkts_action = n_pkts_action, 2614 }; 2615 uint32_t j; 2616 2617 status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info); 2618 if (status) { 2619 snprintf(out, out_size, "Learner table info get error."); 2620 return; 2621 } 2622 2623 status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats); 2624 if (status) { 2625 snprintf(out, out_size, "Learner table stats read error."); 2626 return; 2627 } 2628 2629 snprintf(out, out_size, "\tLearner table %s:\n" 2630 "\t\tHit (packets): %" PRIu64 "\n" 2631 "\t\tMiss (packets): %" PRIu64 "\n" 2632 "\t\tLearn OK (packets): %" PRIu64 "\n" 2633 "\t\tLearn error (packets): %" PRIu64 "\n" 2634 "\t\tForget (packets): %" PRIu64 "\n", 2635 learner_info.name, 2636 stats.n_pkts_hit, 2637 stats.n_pkts_miss, 2638 stats.n_pkts_learn_ok, 2639 stats.n_pkts_learn_err, 2640 stats.n_pkts_forget); 2641 out_size -= strlen(out); 2642 out += strlen(out); 2643 2644 for (j = 0; j < info.n_actions; j++) { 2645 struct rte_swx_ctl_action_info action_info; 2646 2647 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 2648 if (status) { 2649 snprintf(out, out_size, "Action info get error."); 2650 return; 2651 } 2652 2653 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2654 action_info.name, 2655 stats.n_pkts_action[j]); 2656 out_size -= strlen(out); 2657 out += strlen(out); 2658 } 2659 } 2660 } 2661 2662 static const char cmd_thread_pipeline_enable_help[] = 2663 "thread <thread_id> pipeline <pipeline_name> enable\n"; 2664 2665 static void 2666 cmd_thread_pipeline_enable(char **tokens, 2667 uint32_t n_tokens, 2668 char *out, 2669 size_t out_size, 2670 void *obj) 2671 { 2672 char *pipeline_name; 2673 struct pipeline *p; 2674 uint32_t thread_id; 2675 int status; 2676 2677 if (n_tokens != 5) { 2678 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2679 return; 2680 } 2681 2682 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2683 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2684 return; 2685 } 2686 2687 if (strcmp(tokens[2], "pipeline") != 0) { 2688 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2689 return; 2690 } 2691 2692 pipeline_name = tokens[3]; 2693 p = pipeline_find(obj, pipeline_name); 2694 if (!p || !p->ctl) { 2695 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2696 return; 2697 } 2698 2699 if (strcmp(tokens[4], "enable") != 0) { 2700 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2701 return; 2702 } 2703 2704 status = thread_pipeline_enable(thread_id, obj, pipeline_name); 2705 if (status) { 2706 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 2707 return; 2708 } 2709 } 2710 2711 static const char cmd_thread_pipeline_disable_help[] = 2712 "thread <thread_id> pipeline <pipeline_name> disable\n"; 2713 2714 static void 2715 cmd_thread_pipeline_disable(char **tokens, 2716 uint32_t n_tokens, 2717 char *out, 2718 size_t out_size, 2719 void *obj) 2720 { 2721 struct pipeline *p; 2722 char *pipeline_name; 2723 uint32_t thread_id; 2724 int status; 2725 2726 if (n_tokens != 5) { 2727 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2728 return; 2729 } 2730 2731 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2732 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2733 return; 2734 } 2735 2736 if (strcmp(tokens[2], "pipeline") != 0) { 2737 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2738 return; 2739 } 2740 2741 pipeline_name = tokens[3]; 2742 p = pipeline_find(obj, pipeline_name); 2743 if (!p || !p->ctl) { 2744 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2745 return; 2746 } 2747 2748 if (strcmp(tokens[4], "disable") != 0) { 2749 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2750 return; 2751 } 2752 2753 status = thread_pipeline_disable(thread_id, obj, pipeline_name); 2754 if (status) { 2755 snprintf(out, out_size, MSG_CMD_FAIL, 2756 "thread pipeline disable"); 2757 return; 2758 } 2759 } 2760 2761 static void 2762 cmd_help(char **tokens, 2763 uint32_t n_tokens, 2764 char *out, 2765 size_t out_size, 2766 void *arg __rte_unused) 2767 { 2768 tokens++; 2769 n_tokens--; 2770 2771 if (n_tokens == 0) { 2772 snprintf(out, out_size, 2773 "Type 'help <command>' for command details.\n\n" 2774 "List of commands:\n" 2775 "\tmempool\n" 2776 "\tlink\n" 2777 "\ttap\n" 2778 "\tpipeline create\n" 2779 "\tpipeline port in\n" 2780 "\tpipeline port out\n" 2781 "\tpipeline build\n" 2782 "\tpipeline table add\n" 2783 "\tpipeline table delete\n" 2784 "\tpipeline table default\n" 2785 "\tpipeline table show\n" 2786 "\tpipeline selector group add\n" 2787 "\tpipeline selector group delete\n" 2788 "\tpipeline selector group member add\n" 2789 "\tpipeline selector group member delete\n" 2790 "\tpipeline selector show\n" 2791 "\tpipeline learner default\n" 2792 "\tpipeline commit\n" 2793 "\tpipeline abort\n" 2794 "\tpipeline regrd\n" 2795 "\tpipeline regwr\n" 2796 "\tpipeline meter profile add\n" 2797 "\tpipeline meter profile delete\n" 2798 "\tpipeline meter reset\n" 2799 "\tpipeline meter set\n" 2800 "\tpipeline meter stats\n" 2801 "\tpipeline stats\n" 2802 "\tthread pipeline enable\n" 2803 "\tthread pipeline disable\n\n"); 2804 return; 2805 } 2806 2807 if (strcmp(tokens[0], "mempool") == 0) { 2808 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 2809 return; 2810 } 2811 2812 if (strcmp(tokens[0], "link") == 0) { 2813 snprintf(out, out_size, "\n%s\n", cmd_link_help); 2814 return; 2815 } 2816 2817 if (strcmp(tokens[0], "ring") == 0) { 2818 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 2819 return; 2820 } 2821 2822 if (strcmp(tokens[0], "tap") == 0) { 2823 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 2824 return; 2825 } 2826 2827 if ((strcmp(tokens[0], "pipeline") == 0) && 2828 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { 2829 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); 2830 return; 2831 } 2832 2833 if ((strcmp(tokens[0], "pipeline") == 0) && 2834 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { 2835 if (strcmp(tokens[2], "in") == 0) { 2836 snprintf(out, out_size, "\n%s\n", 2837 cmd_pipeline_port_in_help); 2838 return; 2839 } 2840 2841 if (strcmp(tokens[2], "out") == 0) { 2842 snprintf(out, out_size, "\n%s\n", 2843 cmd_pipeline_port_out_help); 2844 return; 2845 } 2846 } 2847 2848 if ((strcmp(tokens[0], "pipeline") == 0) && 2849 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 2850 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 2851 return; 2852 } 2853 2854 if ((strcmp(tokens[0], "pipeline") == 0) && 2855 (n_tokens == 3) && 2856 (strcmp(tokens[1], "table") == 0) && 2857 (strcmp(tokens[2], "add") == 0)) { 2858 snprintf(out, out_size, "\n%s\n", 2859 cmd_pipeline_table_add_help); 2860 return; 2861 } 2862 2863 if ((strcmp(tokens[0], "pipeline") == 0) && 2864 (n_tokens == 3) && 2865 (strcmp(tokens[1], "table") == 0) && 2866 (strcmp(tokens[2], "delete") == 0)) { 2867 snprintf(out, out_size, "\n%s\n", 2868 cmd_pipeline_table_delete_help); 2869 return; 2870 } 2871 2872 if ((strcmp(tokens[0], "pipeline") == 0) && 2873 (n_tokens == 3) && 2874 (strcmp(tokens[1], "table") == 0) && 2875 (strcmp(tokens[2], "default") == 0)) { 2876 snprintf(out, out_size, "\n%s\n", 2877 cmd_pipeline_table_default_help); 2878 return; 2879 } 2880 2881 if ((strcmp(tokens[0], "pipeline") == 0) && 2882 (n_tokens == 3) && 2883 (strcmp(tokens[1], "table") == 0) && 2884 (strcmp(tokens[2], "show") == 0)) { 2885 snprintf(out, out_size, "\n%s\n", 2886 cmd_pipeline_table_show_help); 2887 return; 2888 } 2889 2890 if ((strcmp(tokens[0], "pipeline") == 0) && 2891 (n_tokens == 4) && 2892 (strcmp(tokens[1], "selector") == 0) && 2893 (strcmp(tokens[2], "group") == 0) && 2894 (strcmp(tokens[3], "add") == 0)) { 2895 snprintf(out, out_size, "\n%s\n", 2896 cmd_pipeline_selector_group_add_help); 2897 return; 2898 } 2899 2900 if ((strcmp(tokens[0], "pipeline") == 0) && 2901 (n_tokens == 4) && 2902 (strcmp(tokens[1], "selector") == 0) && 2903 (strcmp(tokens[2], "group") == 0) && 2904 (strcmp(tokens[3], "delete") == 0)) { 2905 snprintf(out, out_size, "\n%s\n", 2906 cmd_pipeline_selector_group_delete_help); 2907 return; 2908 } 2909 2910 if ((strcmp(tokens[0], "pipeline") == 0) && 2911 (n_tokens == 5) && 2912 (strcmp(tokens[1], "selector") == 0) && 2913 (strcmp(tokens[2], "group") == 0) && 2914 (strcmp(tokens[3], "member") == 0) && 2915 (strcmp(tokens[4], "add") == 0)) { 2916 snprintf(out, out_size, "\n%s\n", 2917 cmd_pipeline_selector_group_member_add_help); 2918 return; 2919 } 2920 2921 if ((strcmp(tokens[0], "pipeline") == 0) && 2922 (n_tokens == 5) && 2923 (strcmp(tokens[1], "selector") == 0) && 2924 (strcmp(tokens[2], "group") == 0) && 2925 (strcmp(tokens[3], "member") == 0) && 2926 (strcmp(tokens[4], "delete") == 0)) { 2927 snprintf(out, out_size, "\n%s\n", 2928 cmd_pipeline_selector_group_member_delete_help); 2929 return; 2930 } 2931 2932 if ((strcmp(tokens[0], "pipeline") == 0) && 2933 (n_tokens == 3) && 2934 (strcmp(tokens[1], "selector") == 0) && 2935 (strcmp(tokens[2], "show") == 0)) { 2936 snprintf(out, out_size, "\n%s\n", 2937 cmd_pipeline_selector_show_help); 2938 return; 2939 } 2940 2941 if ((strcmp(tokens[0], "pipeline") == 0) && 2942 (n_tokens == 3) && 2943 (strcmp(tokens[1], "learner") == 0) && 2944 (strcmp(tokens[2], "default") == 0)) { 2945 snprintf(out, out_size, "\n%s\n", 2946 cmd_pipeline_learner_default_help); 2947 return; 2948 } 2949 2950 if ((strcmp(tokens[0], "pipeline") == 0) && 2951 (n_tokens == 2) && 2952 (strcmp(tokens[1], "commit") == 0)) { 2953 snprintf(out, out_size, "\n%s\n", 2954 cmd_pipeline_commit_help); 2955 return; 2956 } 2957 2958 if ((strcmp(tokens[0], "pipeline") == 0) && 2959 (n_tokens == 2) && 2960 (strcmp(tokens[1], "abort") == 0)) { 2961 snprintf(out, out_size, "\n%s\n", 2962 cmd_pipeline_abort_help); 2963 return; 2964 } 2965 2966 if ((strcmp(tokens[0], "pipeline") == 0) && 2967 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 2968 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 2969 return; 2970 } 2971 2972 if ((strcmp(tokens[0], "pipeline") == 0) && 2973 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 2974 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 2975 return; 2976 } 2977 2978 if (!strcmp(tokens[0], "pipeline") && 2979 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2980 && !strcmp(tokens[2], "profile") 2981 && !strcmp(tokens[3], "add")) { 2982 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 2983 return; 2984 } 2985 2986 if (!strcmp(tokens[0], "pipeline") && 2987 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2988 && !strcmp(tokens[2], "profile") 2989 && !strcmp(tokens[3], "delete")) { 2990 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 2991 return; 2992 } 2993 2994 if (!strcmp(tokens[0], "pipeline") && 2995 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2996 && !strcmp(tokens[2], "reset")) { 2997 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 2998 return; 2999 } 3000 3001 if (!strcmp(tokens[0], "pipeline") && 3002 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3003 && !strcmp(tokens[2], "set")) { 3004 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 3005 return; 3006 } 3007 3008 if (!strcmp(tokens[0], "pipeline") && 3009 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3010 && !strcmp(tokens[2], "stats")) { 3011 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 3012 return; 3013 } 3014 3015 if ((strcmp(tokens[0], "pipeline") == 0) && 3016 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 3017 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 3018 return; 3019 } 3020 3021 if ((n_tokens == 3) && 3022 (strcmp(tokens[0], "thread") == 0) && 3023 (strcmp(tokens[1], "pipeline") == 0)) { 3024 if (strcmp(tokens[2], "enable") == 0) { 3025 snprintf(out, out_size, "\n%s\n", 3026 cmd_thread_pipeline_enable_help); 3027 return; 3028 } 3029 3030 if (strcmp(tokens[2], "disable") == 0) { 3031 snprintf(out, out_size, "\n%s\n", 3032 cmd_thread_pipeline_disable_help); 3033 return; 3034 } 3035 } 3036 3037 snprintf(out, out_size, "Invalid command\n"); 3038 } 3039 3040 void 3041 cli_process(char *in, char *out, size_t out_size, void *obj) 3042 { 3043 char *tokens[CMD_MAX_TOKENS]; 3044 uint32_t n_tokens = RTE_DIM(tokens); 3045 int status; 3046 3047 if (is_comment(in)) 3048 return; 3049 3050 status = parse_tokenize_string(in, tokens, &n_tokens); 3051 if (status) { 3052 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 3053 return; 3054 } 3055 3056 if (n_tokens == 0) 3057 return; 3058 3059 if (strcmp(tokens[0], "help") == 0) { 3060 cmd_help(tokens, n_tokens, out, out_size, obj); 3061 return; 3062 } 3063 3064 if (strcmp(tokens[0], "mempool") == 0) { 3065 cmd_mempool(tokens, n_tokens, out, out_size, obj); 3066 return; 3067 } 3068 3069 if (strcmp(tokens[0], "link") == 0) { 3070 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 3071 cmd_link_show(tokens, n_tokens, out, out_size, obj); 3072 return; 3073 } 3074 3075 cmd_link(tokens, n_tokens, out, out_size, obj); 3076 return; 3077 } 3078 3079 if (strcmp(tokens[0], "ring") == 0) { 3080 cmd_ring(tokens, n_tokens, out, out_size, obj); 3081 return; 3082 } 3083 3084 if (strcmp(tokens[0], "tap") == 0) { 3085 cmd_tap(tokens, n_tokens, out, out_size, obj); 3086 return; 3087 } 3088 3089 if (strcmp(tokens[0], "pipeline") == 0) { 3090 if ((n_tokens >= 3) && 3091 (strcmp(tokens[2], "create") == 0)) { 3092 cmd_pipeline_create(tokens, n_tokens, out, out_size, 3093 obj); 3094 return; 3095 } 3096 3097 if ((n_tokens >= 4) && 3098 (strcmp(tokens[2], "port") == 0) && 3099 (strcmp(tokens[3], "in") == 0)) { 3100 cmd_pipeline_port_in(tokens, n_tokens, out, out_size, 3101 obj); 3102 return; 3103 } 3104 3105 if ((n_tokens >= 4) && 3106 (strcmp(tokens[2], "port") == 0) && 3107 (strcmp(tokens[3], "out") == 0)) { 3108 cmd_pipeline_port_out(tokens, n_tokens, out, out_size, 3109 obj); 3110 return; 3111 } 3112 3113 if ((n_tokens >= 3) && 3114 (strcmp(tokens[2], "build") == 0)) { 3115 cmd_pipeline_build(tokens, n_tokens, out, out_size, 3116 obj); 3117 return; 3118 } 3119 3120 if ((n_tokens >= 5) && 3121 (strcmp(tokens[2], "table") == 0) && 3122 (strcmp(tokens[4], "add") == 0)) { 3123 cmd_pipeline_table_add(tokens, n_tokens, out, 3124 out_size, obj); 3125 return; 3126 } 3127 3128 if ((n_tokens >= 5) && 3129 (strcmp(tokens[2], "table") == 0) && 3130 (strcmp(tokens[4], "delete") == 0)) { 3131 cmd_pipeline_table_delete(tokens, n_tokens, out, 3132 out_size, obj); 3133 return; 3134 } 3135 3136 if ((n_tokens >= 5) && 3137 (strcmp(tokens[2], "table") == 0) && 3138 (strcmp(tokens[4], "default") == 0)) { 3139 cmd_pipeline_table_default(tokens, n_tokens, out, 3140 out_size, obj); 3141 return; 3142 } 3143 3144 if ((n_tokens >= 5) && 3145 (strcmp(tokens[2], "table") == 0) && 3146 (strcmp(tokens[4], "show") == 0)) { 3147 cmd_pipeline_table_show(tokens, n_tokens, out, 3148 out_size, obj); 3149 return; 3150 } 3151 3152 if ((n_tokens >= 6) && 3153 (strcmp(tokens[2], "selector") == 0) && 3154 (strcmp(tokens[4], "group") == 0) && 3155 (strcmp(tokens[5], "add") == 0)) { 3156 cmd_pipeline_selector_group_add(tokens, n_tokens, out, 3157 out_size, obj); 3158 return; 3159 } 3160 3161 if ((n_tokens >= 6) && 3162 (strcmp(tokens[2], "selector") == 0) && 3163 (strcmp(tokens[4], "group") == 0) && 3164 (strcmp(tokens[5], "delete") == 0)) { 3165 cmd_pipeline_selector_group_delete(tokens, n_tokens, out, 3166 out_size, obj); 3167 return; 3168 } 3169 3170 if ((n_tokens >= 7) && 3171 (strcmp(tokens[2], "selector") == 0) && 3172 (strcmp(tokens[4], "group") == 0) && 3173 (strcmp(tokens[5], "member") == 0) && 3174 (strcmp(tokens[6], "add") == 0)) { 3175 cmd_pipeline_selector_group_member_add(tokens, n_tokens, out, 3176 out_size, obj); 3177 return; 3178 } 3179 3180 if ((n_tokens >= 7) && 3181 (strcmp(tokens[2], "selector") == 0) && 3182 (strcmp(tokens[4], "group") == 0) && 3183 (strcmp(tokens[5], "member") == 0) && 3184 (strcmp(tokens[6], "delete") == 0)) { 3185 cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out, 3186 out_size, obj); 3187 return; 3188 } 3189 3190 if ((n_tokens >= 5) && 3191 (strcmp(tokens[2], "selector") == 0) && 3192 (strcmp(tokens[4], "show") == 0)) { 3193 cmd_pipeline_selector_show(tokens, n_tokens, out, 3194 out_size, obj); 3195 return; 3196 } 3197 3198 if ((n_tokens >= 5) && 3199 (strcmp(tokens[2], "learner") == 0) && 3200 (strcmp(tokens[4], "default") == 0)) { 3201 cmd_pipeline_learner_default(tokens, n_tokens, out, 3202 out_size, obj); 3203 return; 3204 } 3205 3206 if ((n_tokens >= 3) && 3207 (strcmp(tokens[2], "commit") == 0)) { 3208 cmd_pipeline_commit(tokens, n_tokens, out, 3209 out_size, obj); 3210 return; 3211 } 3212 3213 if ((n_tokens >= 3) && 3214 (strcmp(tokens[2], "abort") == 0)) { 3215 cmd_pipeline_abort(tokens, n_tokens, out, 3216 out_size, obj); 3217 return; 3218 } 3219 3220 if ((n_tokens >= 3) && 3221 (strcmp(tokens[2], "regrd") == 0)) { 3222 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 3223 return; 3224 } 3225 3226 if ((n_tokens >= 3) && 3227 (strcmp(tokens[2], "regwr") == 0)) { 3228 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 3229 return; 3230 } 3231 3232 if ((n_tokens >= 6) && 3233 (strcmp(tokens[2], "meter") == 0) && 3234 (strcmp(tokens[3], "profile") == 0) && 3235 (strcmp(tokens[5], "add") == 0)) { 3236 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 3237 return; 3238 } 3239 3240 if ((n_tokens >= 6) && 3241 (strcmp(tokens[2], "meter") == 0) && 3242 (strcmp(tokens[3], "profile") == 0) && 3243 (strcmp(tokens[5], "delete") == 0)) { 3244 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 3245 return; 3246 } 3247 3248 if ((n_tokens >= 9) && 3249 (strcmp(tokens[2], "meter") == 0) && 3250 (strcmp(tokens[8], "reset") == 0)) { 3251 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 3252 return; 3253 } 3254 3255 if ((n_tokens >= 9) && 3256 (strcmp(tokens[2], "meter") == 0) && 3257 (strcmp(tokens[8], "set") == 0)) { 3258 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 3259 return; 3260 } 3261 3262 if ((n_tokens >= 9) && 3263 (strcmp(tokens[2], "meter") == 0) && 3264 (strcmp(tokens[8], "stats") == 0)) { 3265 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 3266 return; 3267 } 3268 3269 if ((n_tokens >= 3) && 3270 (strcmp(tokens[2], "stats") == 0)) { 3271 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 3272 obj); 3273 return; 3274 } 3275 } 3276 3277 if (strcmp(tokens[0], "thread") == 0) { 3278 if ((n_tokens >= 5) && 3279 (strcmp(tokens[4], "enable") == 0)) { 3280 cmd_thread_pipeline_enable(tokens, n_tokens, 3281 out, out_size, obj); 3282 return; 3283 } 3284 3285 if ((n_tokens >= 5) && 3286 (strcmp(tokens[4], "disable") == 0)) { 3287 cmd_thread_pipeline_disable(tokens, n_tokens, 3288 out, out_size, obj); 3289 return; 3290 } 3291 } 3292 3293 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 3294 } 3295 3296 int 3297 cli_script_process(const char *file_name, 3298 size_t msg_in_len_max, 3299 size_t msg_out_len_max, 3300 void *obj) 3301 { 3302 char *msg_in = NULL, *msg_out = NULL; 3303 FILE *f = NULL; 3304 3305 /* Check input arguments */ 3306 if ((file_name == NULL) || 3307 (strlen(file_name) == 0) || 3308 (msg_in_len_max == 0) || 3309 (msg_out_len_max == 0)) 3310 return -EINVAL; 3311 3312 msg_in = malloc(msg_in_len_max + 1); 3313 msg_out = malloc(msg_out_len_max + 1); 3314 if ((msg_in == NULL) || 3315 (msg_out == NULL)) { 3316 free(msg_out); 3317 free(msg_in); 3318 return -ENOMEM; 3319 } 3320 3321 /* Open input file */ 3322 f = fopen(file_name, "r"); 3323 if (f == NULL) { 3324 free(msg_out); 3325 free(msg_in); 3326 return -EIO; 3327 } 3328 3329 /* Read file */ 3330 for ( ; ; ) { 3331 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 3332 break; 3333 3334 printf("%s", msg_in); 3335 msg_out[0] = 0; 3336 3337 cli_process(msg_in, 3338 msg_out, 3339 msg_out_len_max, 3340 obj); 3341 3342 if (strlen(msg_out)) 3343 printf("%s", msg_out); 3344 } 3345 3346 /* Close file */ 3347 fclose(f); 3348 free(msg_out); 3349 free(msg_in); 3350 return 0; 3351 } 3352