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> loop <n_loops>\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 + 5) { 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 if (strcmp(tokens[t0 + 3], "loop") != 0) { 702 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop"); 703 return; 704 } 705 706 if (parser_read_uint64(¶ms.n_loops, tokens[t0 + 4])) { 707 snprintf(out, out_size, MSG_ARG_INVALID, 708 "n_loops"); 709 return; 710 } 711 712 t0 += 5; 713 714 status = rte_swx_pipeline_port_in_config(p->p, 715 port_id, 716 "source", 717 ¶ms); 718 } else if (strcmp(tokens[t0], "tap") == 0) { 719 struct rte_swx_port_fd_reader_params params; 720 struct tap *tap; 721 struct mempool *mp; 722 723 if (n_tokens < t0 + 8) { 724 snprintf(out, out_size, MSG_ARG_MISMATCH, 725 "pipeline port in tap"); 726 return; 727 } 728 729 tap = tap_find(obj, tokens[t0 + 1]); 730 if (!tap) { 731 snprintf(out, out_size, MSG_ARG_INVALID, 732 "tap_name"); 733 return; 734 } 735 params.fd = tap->fd; 736 737 if (strcmp(tokens[t0 + 2], "mempool") != 0) { 738 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 739 "mempool"); 740 return; 741 } 742 743 mp = mempool_find(obj, tokens[t0 + 3]); 744 if (!mp) { 745 snprintf(out, out_size, MSG_ARG_INVALID, 746 "mempool_name"); 747 return; 748 } 749 params.mempool = mp->m; 750 751 if (strcmp(tokens[t0 + 4], "mtu") != 0) { 752 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 753 "mtu"); 754 return; 755 } 756 757 if (parser_read_uint32(¶ms.mtu, tokens[t0 + 5]) != 0) { 758 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 759 return; 760 } 761 762 if (strcmp(tokens[t0 + 6], "bsz") != 0) { 763 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 764 return; 765 } 766 767 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 7])) { 768 snprintf(out, out_size, MSG_ARG_INVALID, 769 "burst_size"); 770 return; 771 } 772 773 t0 += 8; 774 775 status = rte_swx_pipeline_port_in_config(p->p, 776 port_id, 777 "fd", 778 ¶ms); 779 780 } else { 781 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 782 return; 783 } 784 785 if (status) { 786 snprintf(out, out_size, "port in error."); 787 return; 788 } 789 790 if (n_tokens != t0) { 791 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 792 return; 793 } 794 } 795 796 static const char cmd_pipeline_port_out_help[] = 797 "pipeline <pipeline_name> port out <port_id>\n" 798 " link <link_name> txq <txq_id> bsz <burst_size>\n" 799 " ring <ring_name> bsz <burst_size>\n" 800 " | sink <file_name> | none\n" 801 " | tap <tap_name> bsz <burst_size>\n"; 802 803 static void 804 cmd_pipeline_port_out(char **tokens, 805 uint32_t n_tokens, 806 char *out, 807 size_t out_size, 808 void *obj) 809 { 810 struct pipeline *p; 811 int status; 812 uint32_t port_id = 0, t0; 813 814 if (n_tokens < 6) { 815 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 816 return; 817 } 818 819 p = pipeline_find(obj, tokens[1]); 820 if (!p || p->ctl) { 821 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 822 return; 823 } 824 825 if (strcmp(tokens[2], "port") != 0) { 826 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 827 return; 828 } 829 830 if (strcmp(tokens[3], "out") != 0) { 831 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 832 return; 833 } 834 835 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 836 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 837 return; 838 } 839 840 t0 = 5; 841 842 if (strcmp(tokens[t0], "link") == 0) { 843 struct rte_swx_port_ethdev_writer_params params; 844 struct link *link; 845 846 if (n_tokens < t0 + 6) { 847 snprintf(out, out_size, MSG_ARG_MISMATCH, 848 "pipeline port out link"); 849 return; 850 } 851 852 link = link_find(obj, tokens[t0 + 1]); 853 if (!link) { 854 snprintf(out, out_size, MSG_ARG_INVALID, 855 "link_name"); 856 return; 857 } 858 params.dev_name = link->dev_name; 859 860 if (strcmp(tokens[t0 + 2], "txq") != 0) { 861 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 862 return; 863 } 864 865 if (parser_read_uint16(¶ms.queue_id, tokens[t0 + 3]) != 0) { 866 snprintf(out, out_size, MSG_ARG_INVALID, 867 "queue_id"); 868 return; 869 } 870 871 if (strcmp(tokens[t0 + 4], "bsz") != 0) { 872 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 873 return; 874 } 875 876 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 5])) { 877 snprintf(out, out_size, MSG_ARG_INVALID, 878 "burst_size"); 879 return; 880 } 881 882 t0 += 6; 883 884 status = rte_swx_pipeline_port_out_config(p->p, 885 port_id, 886 "ethdev", 887 ¶ms); 888 } else if (strcmp(tokens[t0], "ring") == 0) { 889 struct rte_swx_port_ring_writer_params params; 890 struct ring *ring; 891 892 if (n_tokens < t0 + 4) { 893 snprintf(out, out_size, MSG_ARG_MISMATCH, 894 "pipeline port out link"); 895 return; 896 } 897 898 ring = ring_find(obj, tokens[t0 + 1]); 899 if (!ring) { 900 snprintf(out, out_size, MSG_ARG_INVALID, 901 "ring_name"); 902 return; 903 } 904 params.name = ring->name; 905 906 if (strcmp(tokens[t0 + 2], "bsz") != 0) { 907 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 908 return; 909 } 910 911 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { 912 snprintf(out, out_size, MSG_ARG_INVALID, 913 "burst_size"); 914 return; 915 } 916 917 t0 += 4; 918 919 status = rte_swx_pipeline_port_out_config(p->p, 920 port_id, 921 "ring", 922 ¶ms); 923 } else if (strcmp(tokens[t0], "sink") == 0) { 924 struct rte_swx_port_sink_params params; 925 926 params.file_name = strcmp(tokens[t0 + 1], "none") ? 927 tokens[t0 + 1] : NULL; 928 929 t0 += 2; 930 931 status = rte_swx_pipeline_port_out_config(p->p, 932 port_id, 933 "sink", 934 ¶ms); 935 } else if (strcmp(tokens[t0], "tap") == 0) { 936 struct rte_swx_port_fd_writer_params params; 937 struct tap *tap; 938 939 if (n_tokens < t0 + 4) { 940 snprintf(out, out_size, MSG_ARG_MISMATCH, 941 "pipeline port out tap"); 942 return; 943 } 944 945 tap = tap_find(obj, tokens[t0 + 1]); 946 if (!tap) { 947 snprintf(out, out_size, MSG_ARG_INVALID, 948 "tap_name"); 949 return; 950 } 951 params.fd = tap->fd; 952 953 if (strcmp(tokens[t0 + 2], "bsz") != 0) { 954 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 955 return; 956 } 957 958 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { 959 snprintf(out, out_size, MSG_ARG_INVALID, 960 "burst_size"); 961 return; 962 } 963 964 t0 += 4; 965 966 status = rte_swx_pipeline_port_out_config(p->p, 967 port_id, 968 "fd", 969 ¶ms); 970 } else { 971 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 972 return; 973 } 974 975 if (status) { 976 snprintf(out, out_size, "port out error."); 977 return; 978 } 979 980 if (n_tokens != t0) { 981 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 982 return; 983 } 984 } 985 986 static const char cmd_pipeline_build_help[] = 987 "pipeline <pipeline_name> build <spec_file>\n"; 988 989 static void 990 cmd_pipeline_build(char **tokens, 991 uint32_t n_tokens, 992 char *out, 993 size_t out_size, 994 void *obj) 995 { 996 struct pipeline *p = NULL; 997 FILE *spec = NULL; 998 uint32_t err_line; 999 const char *err_msg; 1000 int status; 1001 1002 if (n_tokens != 4) { 1003 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1004 return; 1005 } 1006 1007 p = pipeline_find(obj, tokens[1]); 1008 if (!p || p->ctl) { 1009 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1010 return; 1011 } 1012 1013 spec = fopen(tokens[3], "r"); 1014 if (!spec) { 1015 snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]); 1016 return; 1017 } 1018 1019 status = rte_swx_pipeline_build_from_spec(p->p, 1020 spec, 1021 &err_line, 1022 &err_msg); 1023 fclose(spec); 1024 if (status) { 1025 snprintf(out, out_size, "Error %d at line %u: %s\n.", 1026 status, err_line, err_msg); 1027 return; 1028 } 1029 1030 p->ctl = rte_swx_ctl_pipeline_create(p->p); 1031 if (!p->ctl) { 1032 snprintf(out, out_size, "Pipeline control create failed."); 1033 rte_swx_pipeline_free(p->p); 1034 return; 1035 } 1036 } 1037 1038 static void 1039 table_entry_free(struct rte_swx_table_entry *entry) 1040 { 1041 if (!entry) 1042 return; 1043 1044 free(entry->key); 1045 free(entry->key_mask); 1046 free(entry->action_data); 1047 free(entry); 1048 } 1049 1050 #ifndef MAX_LINE_SIZE 1051 #define MAX_LINE_SIZE 2048 1052 #endif 1053 1054 static int 1055 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p, 1056 const char *table_name, 1057 FILE *file, 1058 uint32_t *file_line_number) 1059 { 1060 char *line = NULL; 1061 uint32_t line_id = 0; 1062 int status = 0; 1063 1064 /* Buffer allocation. */ 1065 line = malloc(MAX_LINE_SIZE); 1066 if (!line) 1067 return -ENOMEM; 1068 1069 /* File read. */ 1070 for (line_id = 1; ; line_id++) { 1071 struct rte_swx_table_entry *entry; 1072 int is_blank_or_comment; 1073 1074 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1075 break; 1076 1077 entry = rte_swx_ctl_pipeline_table_entry_read(p, 1078 table_name, 1079 line, 1080 &is_blank_or_comment); 1081 if (!entry) { 1082 if (is_blank_or_comment) 1083 continue; 1084 1085 status = -EINVAL; 1086 goto error; 1087 } 1088 1089 status = rte_swx_ctl_pipeline_table_entry_add(p, 1090 table_name, 1091 entry); 1092 table_entry_free(entry); 1093 if (status) 1094 goto error; 1095 } 1096 1097 error: 1098 free(line); 1099 *file_line_number = line_id; 1100 return status; 1101 } 1102 1103 static const char cmd_pipeline_table_add_help[] = 1104 "pipeline <pipeline_name> table <table_name> add <file_name>\n"; 1105 1106 static void 1107 cmd_pipeline_table_add(char **tokens, 1108 uint32_t n_tokens, 1109 char *out, 1110 size_t out_size, 1111 void *obj) 1112 { 1113 struct pipeline *p; 1114 char *pipeline_name, *table_name, *file_name; 1115 FILE *file = NULL; 1116 uint32_t file_line_number = 0; 1117 int status; 1118 1119 if (n_tokens != 6) { 1120 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1121 return; 1122 } 1123 1124 pipeline_name = tokens[1]; 1125 p = pipeline_find(obj, pipeline_name); 1126 if (!p || !p->ctl) { 1127 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1128 return; 1129 } 1130 1131 table_name = tokens[3]; 1132 1133 file_name = tokens[5]; 1134 file = fopen(file_name, "r"); 1135 if (!file) { 1136 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1137 return; 1138 } 1139 1140 status = pipeline_table_entries_add(p->ctl, 1141 table_name, 1142 file, 1143 &file_line_number); 1144 if (status) 1145 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1146 file_name, 1147 file_line_number); 1148 1149 fclose(file); 1150 } 1151 1152 static int 1153 pipeline_table_entries_delete(struct rte_swx_ctl_pipeline *p, 1154 const char *table_name, 1155 FILE *file, 1156 uint32_t *file_line_number) 1157 { 1158 char *line = NULL; 1159 uint32_t line_id = 0; 1160 int status = 0; 1161 1162 /* Buffer allocation. */ 1163 line = malloc(MAX_LINE_SIZE); 1164 if (!line) 1165 return -ENOMEM; 1166 1167 /* File read. */ 1168 for (line_id = 1; ; line_id++) { 1169 struct rte_swx_table_entry *entry; 1170 int is_blank_or_comment; 1171 1172 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1173 break; 1174 1175 entry = rte_swx_ctl_pipeline_table_entry_read(p, 1176 table_name, 1177 line, 1178 &is_blank_or_comment); 1179 if (!entry) { 1180 if (is_blank_or_comment) 1181 continue; 1182 1183 status = -EINVAL; 1184 goto error; 1185 } 1186 1187 status = rte_swx_ctl_pipeline_table_entry_delete(p, 1188 table_name, 1189 entry); 1190 table_entry_free(entry); 1191 if (status) 1192 goto error; 1193 } 1194 1195 error: 1196 *file_line_number = line_id; 1197 free(line); 1198 return status; 1199 } 1200 1201 static const char cmd_pipeline_table_delete_help[] = 1202 "pipeline <pipeline_name> table <table_name> delete <file_name>\n"; 1203 1204 static void 1205 cmd_pipeline_table_delete(char **tokens, 1206 uint32_t n_tokens, 1207 char *out, 1208 size_t out_size, 1209 void *obj) 1210 { 1211 struct pipeline *p; 1212 char *pipeline_name, *table_name, *file_name; 1213 FILE *file = NULL; 1214 uint32_t file_line_number = 0; 1215 int status; 1216 1217 if (n_tokens != 6) { 1218 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1219 return; 1220 } 1221 1222 pipeline_name = tokens[1]; 1223 p = pipeline_find(obj, pipeline_name); 1224 if (!p || !p->ctl) { 1225 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1226 return; 1227 } 1228 1229 table_name = tokens[3]; 1230 1231 file_name = tokens[5]; 1232 file = fopen(file_name, "r"); 1233 if (!file) { 1234 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1235 return; 1236 } 1237 1238 status = pipeline_table_entries_delete(p->ctl, 1239 table_name, 1240 file, 1241 &file_line_number); 1242 if (status) 1243 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1244 file_name, 1245 file_line_number); 1246 1247 fclose(file); 1248 } 1249 1250 static int 1251 pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *p, 1252 const char *table_name, 1253 FILE *file, 1254 uint32_t *file_line_number) 1255 { 1256 char *line = NULL; 1257 uint32_t line_id = 0; 1258 int status = 0; 1259 1260 /* Buffer allocation. */ 1261 line = malloc(MAX_LINE_SIZE); 1262 if (!line) 1263 return -ENOMEM; 1264 1265 /* File read. */ 1266 for (line_id = 1; ; line_id++) { 1267 struct rte_swx_table_entry *entry; 1268 int is_blank_or_comment; 1269 1270 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1271 break; 1272 1273 entry = rte_swx_ctl_pipeline_table_entry_read(p, 1274 table_name, 1275 line, 1276 &is_blank_or_comment); 1277 if (!entry) { 1278 if (is_blank_or_comment) 1279 continue; 1280 1281 status = -EINVAL; 1282 goto error; 1283 } 1284 1285 status = rte_swx_ctl_pipeline_table_default_entry_add(p, 1286 table_name, 1287 entry); 1288 table_entry_free(entry); 1289 if (status) 1290 goto error; 1291 } 1292 1293 error: 1294 *file_line_number = line_id; 1295 free(line); 1296 return status; 1297 } 1298 1299 static const char cmd_pipeline_table_default_help[] = 1300 "pipeline <pipeline_name> table <table_name> default <file_name>\n"; 1301 1302 static void 1303 cmd_pipeline_table_default(char **tokens, 1304 uint32_t n_tokens, 1305 char *out, 1306 size_t out_size, 1307 void *obj) 1308 { 1309 struct pipeline *p; 1310 char *pipeline_name, *table_name, *file_name; 1311 FILE *file = NULL; 1312 uint32_t file_line_number = 0; 1313 int status; 1314 1315 if (n_tokens != 6) { 1316 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1317 return; 1318 } 1319 1320 pipeline_name = tokens[1]; 1321 p = pipeline_find(obj, pipeline_name); 1322 if (!p || !p->ctl) { 1323 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1324 return; 1325 } 1326 1327 table_name = tokens[3]; 1328 1329 file_name = tokens[5]; 1330 file = fopen(file_name, "r"); 1331 if (!file) { 1332 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1333 return; 1334 } 1335 1336 status = pipeline_table_default_entry_add(p->ctl, 1337 table_name, 1338 file, 1339 &file_line_number); 1340 if (status) 1341 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1342 file_name, 1343 file_line_number); 1344 1345 fclose(file); 1346 } 1347 1348 static const char cmd_pipeline_table_show_help[] = 1349 "pipeline <pipeline_name> table <table_name> show [filename]\n"; 1350 1351 static void 1352 cmd_pipeline_table_show(char **tokens, 1353 uint32_t n_tokens, 1354 char *out, 1355 size_t out_size, 1356 void *obj) 1357 { 1358 struct pipeline *p; 1359 char *pipeline_name, *table_name; 1360 FILE *file = NULL; 1361 int status; 1362 1363 if (n_tokens != 5 && n_tokens != 6) { 1364 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1365 return; 1366 } 1367 1368 pipeline_name = tokens[1]; 1369 p = pipeline_find(obj, pipeline_name); 1370 if (!p || !p->ctl) { 1371 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1372 return; 1373 } 1374 1375 table_name = tokens[3]; 1376 file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout; 1377 if (!file) { 1378 snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]); 1379 return; 1380 } 1381 1382 status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name); 1383 if (status) 1384 snprintf(out, out_size, MSG_ARG_INVALID, "table_name"); 1385 1386 if (file) 1387 fclose(file); 1388 } 1389 1390 static const char cmd_pipeline_selector_group_add_help[] = 1391 "pipeline <pipeline_name> selector <selector_name> group add\n"; 1392 1393 static void 1394 cmd_pipeline_selector_group_add(char **tokens, 1395 uint32_t n_tokens, 1396 char *out, 1397 size_t out_size, 1398 void *obj) 1399 { 1400 struct pipeline *p; 1401 char *pipeline_name, *selector_name; 1402 uint32_t group_id; 1403 int status; 1404 1405 if (n_tokens != 6) { 1406 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1407 return; 1408 } 1409 1410 pipeline_name = tokens[1]; 1411 p = pipeline_find(obj, pipeline_name); 1412 if (!p || !p->ctl) { 1413 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1414 return; 1415 } 1416 1417 if (strcmp(tokens[2], "selector") != 0) { 1418 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1419 return; 1420 } 1421 1422 selector_name = tokens[3]; 1423 1424 if (strcmp(tokens[4], "group") || 1425 strcmp(tokens[5], "add")) { 1426 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add"); 1427 return; 1428 } 1429 1430 status = rte_swx_ctl_pipeline_selector_group_add(p->ctl, 1431 selector_name, 1432 &group_id); 1433 if (status) 1434 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1435 else 1436 snprintf(out, out_size, "Group ID: %u\n", group_id); 1437 } 1438 1439 static const char cmd_pipeline_selector_group_delete_help[] = 1440 "pipeline <pipeline_name> selector <selector_name> group delete <group_id>\n"; 1441 1442 static void 1443 cmd_pipeline_selector_group_delete(char **tokens, 1444 uint32_t n_tokens, 1445 char *out, 1446 size_t out_size, 1447 void *obj) 1448 { 1449 struct pipeline *p; 1450 char *pipeline_name, *selector_name; 1451 uint32_t group_id; 1452 int status; 1453 1454 if (n_tokens != 7) { 1455 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1456 return; 1457 } 1458 1459 pipeline_name = tokens[1]; 1460 p = pipeline_find(obj, pipeline_name); 1461 if (!p || !p->ctl) { 1462 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1463 return; 1464 } 1465 1466 if (strcmp(tokens[2], "selector") != 0) { 1467 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1468 return; 1469 } 1470 1471 selector_name = tokens[3]; 1472 1473 if (strcmp(tokens[4], "group") || 1474 strcmp(tokens[5], "delete")) { 1475 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete"); 1476 return; 1477 } 1478 1479 if (parser_read_uint32(&group_id, tokens[6]) != 0) { 1480 snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); 1481 return; 1482 } 1483 1484 status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl, 1485 selector_name, 1486 group_id); 1487 if (status) 1488 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1489 } 1490 1491 #define GROUP_MEMBER_INFO_TOKENS_MAX 6 1492 1493 static int 1494 token_is_comment(const char *token) 1495 { 1496 if ((token[0] == '#') || 1497 (token[0] == ';') || 1498 ((token[0] == '/') && (token[1] == '/'))) 1499 return 1; /* TRUE. */ 1500 1501 return 0; /* FALSE. */ 1502 } 1503 1504 static int 1505 pipeline_selector_group_member_read(const char *string, 1506 uint32_t *group_id, 1507 uint32_t *member_id, 1508 uint32_t *weight, 1509 int *is_blank_or_comment) 1510 { 1511 char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens; 1512 char *s0 = NULL, *s; 1513 uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0; 1514 int blank_or_comment = 0; 1515 1516 /* Check input arguments. */ 1517 if (!string || !string[0]) 1518 goto error; 1519 1520 /* Memory allocation. */ 1521 s0 = strdup(string); 1522 if (!s0) 1523 goto error; 1524 1525 /* Parse the string into tokens. */ 1526 for (s = s0; ; ) { 1527 char *token; 1528 1529 token = strtok_r(s, " \f\n\r\t\v", &s); 1530 if (!token || token_is_comment(token)) 1531 break; 1532 1533 if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX) 1534 goto error; 1535 1536 token_array[n_tokens] = token; 1537 n_tokens++; 1538 } 1539 1540 if (!n_tokens) { 1541 blank_or_comment = 1; 1542 goto error; 1543 } 1544 1545 tokens = token_array; 1546 1547 if (n_tokens < 4 || 1548 strcmp(tokens[0], "group") || 1549 strcmp(tokens[2], "member")) 1550 goto error; 1551 1552 /* 1553 * Group ID. 1554 */ 1555 if (parser_read_uint32(&group_id_val, tokens[1]) != 0) 1556 goto error; 1557 *group_id = group_id_val; 1558 1559 /* 1560 * Member ID. 1561 */ 1562 if (parser_read_uint32(&member_id_val, tokens[3]) != 0) 1563 goto error; 1564 *member_id = member_id_val; 1565 1566 tokens += 4; 1567 n_tokens -= 4; 1568 1569 /* 1570 * Weight. 1571 */ 1572 if (n_tokens && !strcmp(tokens[0], "weight")) { 1573 if (n_tokens < 2) 1574 goto error; 1575 1576 if (parser_read_uint32(&weight_val, tokens[1]) != 0) 1577 goto error; 1578 *weight = weight_val; 1579 1580 tokens += 2; 1581 n_tokens -= 2; 1582 } 1583 1584 if (n_tokens) 1585 goto error; 1586 1587 free(s0); 1588 return 0; 1589 1590 error: 1591 free(s0); 1592 if (is_blank_or_comment) 1593 *is_blank_or_comment = blank_or_comment; 1594 return -EINVAL; 1595 } 1596 1597 static int 1598 pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p, 1599 const char *selector_name, 1600 FILE *file, 1601 uint32_t *file_line_number) 1602 { 1603 char *line = NULL; 1604 uint32_t line_id = 0; 1605 int status = 0; 1606 1607 /* Buffer allocation. */ 1608 line = malloc(MAX_LINE_SIZE); 1609 if (!line) 1610 return -ENOMEM; 1611 1612 /* File read. */ 1613 for (line_id = 1; ; line_id++) { 1614 uint32_t group_id, member_id, weight; 1615 int is_blank_or_comment; 1616 1617 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1618 break; 1619 1620 status = pipeline_selector_group_member_read(line, 1621 &group_id, 1622 &member_id, 1623 &weight, 1624 &is_blank_or_comment); 1625 if (status) { 1626 if (is_blank_or_comment) 1627 continue; 1628 1629 goto error; 1630 } 1631 1632 status = rte_swx_ctl_pipeline_selector_group_member_add(p, 1633 selector_name, 1634 group_id, 1635 member_id, 1636 weight); 1637 if (status) 1638 goto error; 1639 } 1640 1641 error: 1642 free(line); 1643 *file_line_number = line_id; 1644 return status; 1645 } 1646 1647 static const char cmd_pipeline_selector_group_member_add_help[] = 1648 "pipeline <pipeline_name> selector <selector_name> group member add <file_name>"; 1649 1650 static void 1651 cmd_pipeline_selector_group_member_add(char **tokens, 1652 uint32_t n_tokens, 1653 char *out, 1654 size_t out_size, 1655 void *obj) 1656 { 1657 struct pipeline *p; 1658 char *pipeline_name, *selector_name, *file_name; 1659 FILE *file = NULL; 1660 uint32_t file_line_number = 0; 1661 int status; 1662 1663 if (n_tokens != 8) { 1664 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1665 return; 1666 } 1667 1668 pipeline_name = tokens[1]; 1669 p = pipeline_find(obj, pipeline_name); 1670 if (!p || !p->ctl) { 1671 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1672 return; 1673 } 1674 1675 if (strcmp(tokens[2], "selector") != 0) { 1676 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1677 return; 1678 } 1679 1680 selector_name = tokens[3]; 1681 1682 if (strcmp(tokens[4], "group") || 1683 strcmp(tokens[5], "member") || 1684 strcmp(tokens[6], "add")) { 1685 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add"); 1686 return; 1687 } 1688 1689 file_name = tokens[7]; 1690 file = fopen(file_name, "r"); 1691 if (!file) { 1692 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1693 return; 1694 } 1695 1696 status = pipeline_selector_group_members_add(p->ctl, 1697 selector_name, 1698 file, 1699 &file_line_number); 1700 if (status) 1701 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1702 file_name, 1703 file_line_number); 1704 1705 fclose(file); 1706 } 1707 1708 static int 1709 pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p, 1710 const char *selector_name, 1711 FILE *file, 1712 uint32_t *file_line_number) 1713 { 1714 char *line = NULL; 1715 uint32_t line_id = 0; 1716 int status = 0; 1717 1718 /* Buffer allocation. */ 1719 line = malloc(MAX_LINE_SIZE); 1720 if (!line) 1721 return -ENOMEM; 1722 1723 /* File read. */ 1724 for (line_id = 1; ; line_id++) { 1725 uint32_t group_id, member_id, weight; 1726 int is_blank_or_comment; 1727 1728 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1729 break; 1730 1731 status = pipeline_selector_group_member_read(line, 1732 &group_id, 1733 &member_id, 1734 &weight, 1735 &is_blank_or_comment); 1736 if (status) { 1737 if (is_blank_or_comment) 1738 continue; 1739 1740 goto error; 1741 } 1742 1743 status = rte_swx_ctl_pipeline_selector_group_member_delete(p, 1744 selector_name, 1745 group_id, 1746 member_id); 1747 if (status) 1748 goto error; 1749 } 1750 1751 error: 1752 free(line); 1753 *file_line_number = line_id; 1754 return status; 1755 } 1756 1757 static const char cmd_pipeline_selector_group_member_delete_help[] = 1758 "pipeline <pipeline_name> selector <selector_name> group member delete <file_name>"; 1759 1760 static void 1761 cmd_pipeline_selector_group_member_delete(char **tokens, 1762 uint32_t n_tokens, 1763 char *out, 1764 size_t out_size, 1765 void *obj) 1766 { 1767 struct pipeline *p; 1768 char *pipeline_name, *selector_name, *file_name; 1769 FILE *file = NULL; 1770 uint32_t file_line_number = 0; 1771 int status; 1772 1773 if (n_tokens != 8) { 1774 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1775 return; 1776 } 1777 1778 pipeline_name = tokens[1]; 1779 p = pipeline_find(obj, pipeline_name); 1780 if (!p || !p->ctl) { 1781 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1782 return; 1783 } 1784 1785 if (strcmp(tokens[2], "selector") != 0) { 1786 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1787 return; 1788 } 1789 1790 selector_name = tokens[3]; 1791 1792 if (strcmp(tokens[4], "group") || 1793 strcmp(tokens[5], "member") || 1794 strcmp(tokens[6], "delete")) { 1795 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete"); 1796 return; 1797 } 1798 1799 file_name = tokens[7]; 1800 file = fopen(file_name, "r"); 1801 if (!file) { 1802 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1803 return; 1804 } 1805 1806 status = pipeline_selector_group_members_delete(p->ctl, 1807 selector_name, 1808 file, 1809 &file_line_number); 1810 if (status) 1811 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1812 file_name, 1813 file_line_number); 1814 1815 fclose(file); 1816 } 1817 1818 static const char cmd_pipeline_selector_show_help[] = 1819 "pipeline <pipeline_name> selector <selector_name> show [filename]\n"; 1820 1821 static void 1822 cmd_pipeline_selector_show(char **tokens, 1823 uint32_t n_tokens, 1824 char *out, 1825 size_t out_size, 1826 void *obj) 1827 { 1828 struct pipeline *p; 1829 char *pipeline_name, *selector_name; 1830 FILE *file = NULL; 1831 int status; 1832 1833 if (n_tokens != 5 && n_tokens != 6) { 1834 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1835 return; 1836 } 1837 1838 pipeline_name = tokens[1]; 1839 p = pipeline_find(obj, pipeline_name); 1840 if (!p || !p->ctl) { 1841 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1842 return; 1843 } 1844 1845 selector_name = tokens[3]; 1846 1847 file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout; 1848 if (!file) { 1849 snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]); 1850 return; 1851 } 1852 1853 status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name); 1854 if (status) 1855 snprintf(out, out_size, MSG_ARG_INVALID, "selector_name"); 1856 1857 if (file) 1858 fclose(file); 1859 } 1860 1861 static int 1862 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p, 1863 const char *learner_name, 1864 FILE *file, 1865 uint32_t *file_line_number) 1866 { 1867 char *line = NULL; 1868 uint32_t line_id = 0; 1869 int status = 0; 1870 1871 /* Buffer allocation. */ 1872 line = malloc(MAX_LINE_SIZE); 1873 if (!line) 1874 return -ENOMEM; 1875 1876 /* File read. */ 1877 for (line_id = 1; ; line_id++) { 1878 struct rte_swx_table_entry *entry; 1879 int is_blank_or_comment; 1880 1881 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1882 break; 1883 1884 entry = rte_swx_ctl_pipeline_learner_default_entry_read(p, 1885 learner_name, 1886 line, 1887 &is_blank_or_comment); 1888 if (!entry) { 1889 if (is_blank_or_comment) 1890 continue; 1891 1892 status = -EINVAL; 1893 goto error; 1894 } 1895 1896 status = rte_swx_ctl_pipeline_learner_default_entry_add(p, 1897 learner_name, 1898 entry); 1899 table_entry_free(entry); 1900 if (status) 1901 goto error; 1902 } 1903 1904 error: 1905 *file_line_number = line_id; 1906 free(line); 1907 return status; 1908 } 1909 1910 static const char cmd_pipeline_learner_default_help[] = 1911 "pipeline <pipeline_name> learner <learner_name> default <file_name>\n"; 1912 1913 static void 1914 cmd_pipeline_learner_default(char **tokens, 1915 uint32_t n_tokens, 1916 char *out, 1917 size_t out_size, 1918 void *obj) 1919 { 1920 struct pipeline *p; 1921 char *pipeline_name, *learner_name, *file_name; 1922 FILE *file = NULL; 1923 uint32_t file_line_number = 0; 1924 int status; 1925 1926 if (n_tokens != 6) { 1927 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1928 return; 1929 } 1930 1931 pipeline_name = tokens[1]; 1932 p = pipeline_find(obj, pipeline_name); 1933 if (!p || !p->ctl) { 1934 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1935 return; 1936 } 1937 1938 learner_name = tokens[3]; 1939 1940 file_name = tokens[5]; 1941 file = fopen(file_name, "r"); 1942 if (!file) { 1943 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1944 return; 1945 } 1946 1947 status = pipeline_learner_default_entry_add(p->ctl, 1948 learner_name, 1949 file, 1950 &file_line_number); 1951 if (status) 1952 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1953 file_name, 1954 file_line_number); 1955 1956 fclose(file); 1957 } 1958 1959 static const char cmd_pipeline_commit_help[] = 1960 "pipeline <pipeline_name> commit\n"; 1961 1962 static void 1963 cmd_pipeline_commit(char **tokens, 1964 uint32_t n_tokens, 1965 char *out, 1966 size_t out_size, 1967 void *obj) 1968 { 1969 struct pipeline *p; 1970 char *pipeline_name; 1971 int status; 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 status = rte_swx_ctl_pipeline_commit(p->ctl, 1); 1986 if (status) 1987 snprintf(out, out_size, "Commit failed. " 1988 "Use \"commit\" to retry or \"abort\" to discard the pending work.\n"); 1989 } 1990 1991 static const char cmd_pipeline_abort_help[] = 1992 "pipeline <pipeline_name> abort\n"; 1993 1994 static void 1995 cmd_pipeline_abort(char **tokens, 1996 uint32_t n_tokens, 1997 char *out, 1998 size_t out_size, 1999 void *obj) 2000 { 2001 struct pipeline *p; 2002 char *pipeline_name; 2003 2004 if (n_tokens != 3) { 2005 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2006 return; 2007 } 2008 2009 pipeline_name = tokens[1]; 2010 p = pipeline_find(obj, pipeline_name); 2011 if (!p || !p->ctl) { 2012 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2013 return; 2014 } 2015 2016 rte_swx_ctl_pipeline_abort(p->ctl); 2017 } 2018 2019 static const char cmd_pipeline_regrd_help[] = 2020 "pipeline <pipeline_name> regrd <register_array_name> <index>\n"; 2021 2022 static void 2023 cmd_pipeline_regrd(char **tokens, 2024 uint32_t n_tokens, 2025 char *out, 2026 size_t out_size, 2027 void *obj) 2028 { 2029 struct pipeline *p; 2030 const char *name; 2031 uint64_t value; 2032 uint32_t idx; 2033 int status; 2034 2035 if (n_tokens != 5) { 2036 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2037 return; 2038 } 2039 2040 p = pipeline_find(obj, tokens[1]); 2041 if (!p || !p->ctl) { 2042 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2043 return; 2044 } 2045 2046 if (strcmp(tokens[2], "regrd")) { 2047 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd"); 2048 return; 2049 } 2050 2051 name = tokens[3]; 2052 2053 if (parser_read_uint32(&idx, tokens[4])) { 2054 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 2055 return; 2056 } 2057 2058 status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value); 2059 if (status) { 2060 snprintf(out, out_size, "Command failed.\n"); 2061 return; 2062 } 2063 2064 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 2065 } 2066 2067 static const char cmd_pipeline_regwr_help[] = 2068 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n"; 2069 2070 static void 2071 cmd_pipeline_regwr(char **tokens, 2072 uint32_t n_tokens, 2073 char *out, 2074 size_t out_size, 2075 void *obj) 2076 { 2077 struct pipeline *p; 2078 const char *name; 2079 uint64_t value; 2080 uint32_t idx; 2081 int status; 2082 2083 if (n_tokens != 6) { 2084 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2085 return; 2086 } 2087 2088 p = pipeline_find(obj, tokens[1]); 2089 if (!p || !p->ctl) { 2090 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2091 return; 2092 } 2093 2094 if (strcmp(tokens[2], "regwr")) { 2095 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr"); 2096 return; 2097 } 2098 2099 name = tokens[3]; 2100 2101 if (parser_read_uint32(&idx, tokens[4])) { 2102 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 2103 return; 2104 } 2105 2106 if (parser_read_uint64(&value, tokens[5])) { 2107 snprintf(out, out_size, MSG_ARG_INVALID, "value"); 2108 return; 2109 } 2110 2111 status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value); 2112 if (status) { 2113 snprintf(out, out_size, "Command failed.\n"); 2114 return; 2115 } 2116 } 2117 2118 static const char cmd_pipeline_meter_profile_add_help[] = 2119 "pipeline <pipeline_name> meter profile <profile_name> add " 2120 "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 2121 2122 static void 2123 cmd_pipeline_meter_profile_add(char **tokens, 2124 uint32_t n_tokens, 2125 char *out, 2126 size_t out_size, 2127 void *obj) 2128 { 2129 struct rte_meter_trtcm_params params; 2130 struct pipeline *p; 2131 const char *profile_name; 2132 int status; 2133 2134 if (n_tokens != 14) { 2135 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2136 return; 2137 } 2138 2139 p = pipeline_find(obj, tokens[1]); 2140 if (!p || !p->ctl) { 2141 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2142 return; 2143 } 2144 2145 if (strcmp(tokens[2], "meter")) { 2146 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2147 return; 2148 } 2149 2150 if (strcmp(tokens[3], "profile")) { 2151 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2152 return; 2153 } 2154 2155 profile_name = tokens[4]; 2156 2157 if (strcmp(tokens[5], "add")) { 2158 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 2159 return; 2160 } 2161 2162 if (strcmp(tokens[6], "cir")) { 2163 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 2164 return; 2165 } 2166 2167 if (parser_read_uint64(¶ms.cir, tokens[7])) { 2168 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 2169 return; 2170 } 2171 2172 if (strcmp(tokens[8], "pir")) { 2173 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 2174 return; 2175 } 2176 2177 if (parser_read_uint64(¶ms.pir, tokens[9])) { 2178 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 2179 return; 2180 } 2181 2182 if (strcmp(tokens[10], "cbs")) { 2183 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 2184 return; 2185 } 2186 2187 if (parser_read_uint64(¶ms.cbs, tokens[11])) { 2188 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 2189 return; 2190 } 2191 2192 if (strcmp(tokens[12], "pbs")) { 2193 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 2194 return; 2195 } 2196 2197 if (parser_read_uint64(¶ms.pbs, tokens[13])) { 2198 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 2199 return; 2200 } 2201 2202 status = rte_swx_ctl_meter_profile_add(p->p, profile_name, ¶ms); 2203 if (status) { 2204 snprintf(out, out_size, "Command failed.\n"); 2205 return; 2206 } 2207 } 2208 2209 static const char cmd_pipeline_meter_profile_delete_help[] = 2210 "pipeline <pipeline_name> meter profile <profile_name> delete\n"; 2211 2212 static void 2213 cmd_pipeline_meter_profile_delete(char **tokens, 2214 uint32_t n_tokens, 2215 char *out, 2216 size_t out_size, 2217 void *obj) 2218 { 2219 struct pipeline *p; 2220 const char *profile_name; 2221 int status; 2222 2223 if (n_tokens != 6) { 2224 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2225 return; 2226 } 2227 2228 p = pipeline_find(obj, tokens[1]); 2229 if (!p || !p->ctl) { 2230 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2231 return; 2232 } 2233 2234 if (strcmp(tokens[2], "meter")) { 2235 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2236 return; 2237 } 2238 2239 if (strcmp(tokens[3], "profile")) { 2240 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2241 return; 2242 } 2243 2244 profile_name = tokens[4]; 2245 2246 if (strcmp(tokens[5], "delete")) { 2247 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 2248 return; 2249 } 2250 2251 status = rte_swx_ctl_meter_profile_delete(p->p, profile_name); 2252 if (status) { 2253 snprintf(out, out_size, "Command failed.\n"); 2254 return; 2255 } 2256 } 2257 2258 static const char cmd_pipeline_meter_reset_help[] = 2259 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2260 "reset\n"; 2261 2262 static void 2263 cmd_pipeline_meter_reset(char **tokens, 2264 uint32_t n_tokens, 2265 char *out, 2266 size_t out_size, 2267 void *obj) 2268 { 2269 struct pipeline *p; 2270 const char *name; 2271 uint32_t idx0 = 0, idx1 = 0; 2272 2273 if (n_tokens != 9) { 2274 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2275 return; 2276 } 2277 2278 p = pipeline_find(obj, tokens[1]); 2279 if (!p || !p->ctl) { 2280 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2281 return; 2282 } 2283 2284 if (strcmp(tokens[2], "meter")) { 2285 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2286 return; 2287 } 2288 2289 name = tokens[3]; 2290 2291 if (strcmp(tokens[4], "from")) { 2292 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2293 return; 2294 } 2295 2296 if (parser_read_uint32(&idx0, tokens[5])) { 2297 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2298 return; 2299 } 2300 2301 if (strcmp(tokens[6], "to")) { 2302 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2303 return; 2304 } 2305 2306 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2307 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2308 return; 2309 } 2310 2311 if (strcmp(tokens[8], "reset")) { 2312 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); 2313 return; 2314 } 2315 2316 for ( ; idx0 <= idx1; idx0++) { 2317 int status; 2318 2319 status = rte_swx_ctl_meter_reset(p->p, name, idx0); 2320 if (status) { 2321 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2322 return; 2323 } 2324 } 2325 } 2326 2327 static const char cmd_pipeline_meter_set_help[] = 2328 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2329 "set profile <profile_name>\n"; 2330 2331 static void 2332 cmd_pipeline_meter_set(char **tokens, 2333 uint32_t n_tokens, 2334 char *out, 2335 size_t out_size, 2336 void *obj) 2337 { 2338 struct pipeline *p; 2339 const char *name, *profile_name; 2340 uint32_t idx0 = 0, idx1 = 0; 2341 2342 if (n_tokens != 11) { 2343 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2344 return; 2345 } 2346 2347 p = pipeline_find(obj, tokens[1]); 2348 if (!p || !p->ctl) { 2349 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2350 return; 2351 } 2352 2353 if (strcmp(tokens[2], "meter")) { 2354 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2355 return; 2356 } 2357 2358 name = tokens[3]; 2359 2360 if (strcmp(tokens[4], "from")) { 2361 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2362 return; 2363 } 2364 2365 if (parser_read_uint32(&idx0, tokens[5])) { 2366 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2367 return; 2368 } 2369 2370 if (strcmp(tokens[6], "to")) { 2371 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2372 return; 2373 } 2374 2375 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2376 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2377 return; 2378 } 2379 2380 if (strcmp(tokens[8], "set")) { 2381 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); 2382 return; 2383 } 2384 2385 if (strcmp(tokens[9], "profile")) { 2386 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2387 return; 2388 } 2389 2390 profile_name = tokens[10]; 2391 2392 for ( ; idx0 <= idx1; idx0++) { 2393 int status; 2394 2395 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name); 2396 if (status) { 2397 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2398 return; 2399 } 2400 } 2401 } 2402 2403 static const char cmd_pipeline_meter_stats_help[] = 2404 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2405 "stats\n"; 2406 2407 static void 2408 cmd_pipeline_meter_stats(char **tokens, 2409 uint32_t n_tokens, 2410 char *out, 2411 size_t out_size, 2412 void *obj) 2413 { 2414 struct rte_swx_ctl_meter_stats stats; 2415 struct pipeline *p; 2416 const char *name; 2417 uint32_t idx0 = 0, idx1 = 0; 2418 2419 if (n_tokens != 9) { 2420 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2421 return; 2422 } 2423 2424 p = pipeline_find(obj, tokens[1]); 2425 if (!p || !p->ctl) { 2426 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2427 return; 2428 } 2429 2430 if (strcmp(tokens[2], "meter")) { 2431 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2432 return; 2433 } 2434 2435 name = tokens[3]; 2436 2437 if (strcmp(tokens[4], "from")) { 2438 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2439 return; 2440 } 2441 2442 if (parser_read_uint32(&idx0, tokens[5])) { 2443 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2444 return; 2445 } 2446 2447 if (strcmp(tokens[6], "to")) { 2448 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2449 return; 2450 } 2451 2452 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2453 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2454 return; 2455 } 2456 2457 if (strcmp(tokens[8], "stats")) { 2458 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2459 return; 2460 } 2461 2462 /* Table header. */ 2463 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2464 "-------", 2465 "----------------", "----------------", "----------------", 2466 "----------------", "----------------", "----------------"); 2467 out_size -= strlen(out); 2468 out += strlen(out); 2469 2470 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2471 "METER #", 2472 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2473 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2474 out_size -= strlen(out); 2475 out += strlen(out); 2476 2477 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2478 "-------", 2479 "----------------", "----------------", "----------------", 2480 "----------------", "----------------", "----------------"); 2481 out_size -= strlen(out); 2482 out += strlen(out); 2483 2484 /* Table rows. */ 2485 for ( ; idx0 <= idx1; idx0++) { 2486 int status; 2487 2488 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats); 2489 if (status) { 2490 snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0); 2491 out_size -= strlen(out); 2492 out += strlen(out); 2493 return; 2494 } 2495 2496 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2497 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2498 idx0, 2499 stats.n_pkts[RTE_COLOR_GREEN], 2500 stats.n_pkts[RTE_COLOR_YELLOW], 2501 stats.n_pkts[RTE_COLOR_RED], 2502 stats.n_bytes[RTE_COLOR_GREEN], 2503 stats.n_bytes[RTE_COLOR_YELLOW], 2504 stats.n_bytes[RTE_COLOR_RED]); 2505 out_size -= strlen(out); 2506 out += strlen(out); 2507 } 2508 } 2509 2510 static const char cmd_pipeline_stats_help[] = 2511 "pipeline <pipeline_name> stats\n"; 2512 2513 static void 2514 cmd_pipeline_stats(char **tokens, 2515 uint32_t n_tokens, 2516 char *out, 2517 size_t out_size, 2518 void *obj) 2519 { 2520 struct rte_swx_ctl_pipeline_info info; 2521 struct pipeline *p; 2522 uint32_t i; 2523 int status; 2524 2525 if (n_tokens != 3) { 2526 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2527 return; 2528 } 2529 2530 p = pipeline_find(obj, tokens[1]); 2531 if (!p || !p->ctl) { 2532 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2533 return; 2534 } 2535 2536 if (strcmp(tokens[2], "stats")) { 2537 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2538 return; 2539 } 2540 2541 status = rte_swx_ctl_pipeline_info_get(p->p, &info); 2542 if (status) { 2543 snprintf(out, out_size, "Pipeline info get error."); 2544 return; 2545 } 2546 2547 snprintf(out, out_size, "Input ports:\n"); 2548 out_size -= strlen(out); 2549 out += strlen(out); 2550 2551 for (i = 0; i < info.n_ports_in; i++) { 2552 struct rte_swx_port_in_stats stats; 2553 2554 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats); 2555 2556 snprintf(out, out_size, "\tPort %u:" 2557 " packets %" PRIu64 2558 " bytes %" PRIu64 2559 " empty %" PRIu64 "\n", 2560 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 2561 out_size -= strlen(out); 2562 out += strlen(out); 2563 } 2564 2565 snprintf(out, out_size, "\nOutput ports:\n"); 2566 out_size -= strlen(out); 2567 out += strlen(out); 2568 2569 for (i = 0; i < info.n_ports_out; i++) { 2570 struct rte_swx_port_out_stats stats; 2571 2572 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); 2573 2574 if (i != info.n_ports_out - 1) 2575 snprintf(out, out_size, "\tPort %u:", i); 2576 else 2577 snprintf(out, out_size, "\tDROP:"); 2578 2579 out_size -= strlen(out); 2580 out += strlen(out); 2581 2582 snprintf(out, 2583 out_size, 2584 " packets %" PRIu64 2585 " bytes %" PRIu64 2586 " clone %" PRIu64 2587 " clonerr %" PRIu64 "\n", 2588 stats.n_pkts, 2589 stats.n_bytes, 2590 stats.n_pkts_clone, 2591 stats.n_pkts_clone_err); 2592 2593 out_size -= strlen(out); 2594 out += strlen(out); 2595 } 2596 2597 snprintf(out, out_size, "\nTables:\n"); 2598 out_size -= strlen(out); 2599 out += strlen(out); 2600 2601 for (i = 0; i < info.n_tables; i++) { 2602 struct rte_swx_ctl_table_info table_info; 2603 uint64_t n_pkts_action[info.n_actions]; 2604 struct rte_swx_table_stats stats = { 2605 .n_pkts_hit = 0, 2606 .n_pkts_miss = 0, 2607 .n_pkts_action = n_pkts_action, 2608 }; 2609 uint32_t j; 2610 2611 status = rte_swx_ctl_table_info_get(p->p, i, &table_info); 2612 if (status) { 2613 snprintf(out, out_size, "Table info get error."); 2614 return; 2615 } 2616 2617 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats); 2618 if (status) { 2619 snprintf(out, out_size, "Table stats read error."); 2620 return; 2621 } 2622 2623 snprintf(out, out_size, "\tTable %s:\n" 2624 "\t\tHit (packets): %" PRIu64 "\n" 2625 "\t\tMiss (packets): %" PRIu64 "\n", 2626 table_info.name, 2627 stats.n_pkts_hit, 2628 stats.n_pkts_miss); 2629 out_size -= strlen(out); 2630 out += strlen(out); 2631 2632 for (j = 0; j < info.n_actions; j++) { 2633 struct rte_swx_ctl_action_info action_info; 2634 2635 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 2636 if (status) { 2637 snprintf(out, out_size, "Action info get error."); 2638 return; 2639 } 2640 2641 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2642 action_info.name, 2643 stats.n_pkts_action[j]); 2644 out_size -= strlen(out); 2645 out += strlen(out); 2646 } 2647 } 2648 2649 snprintf(out, out_size, "\nLearner tables:\n"); 2650 out_size -= strlen(out); 2651 out += strlen(out); 2652 2653 for (i = 0; i < info.n_learners; i++) { 2654 struct rte_swx_ctl_learner_info learner_info; 2655 uint64_t n_pkts_action[info.n_actions]; 2656 struct rte_swx_learner_stats stats = { 2657 .n_pkts_hit = 0, 2658 .n_pkts_miss = 0, 2659 .n_pkts_action = n_pkts_action, 2660 }; 2661 uint32_t j; 2662 2663 status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info); 2664 if (status) { 2665 snprintf(out, out_size, "Learner table info get error."); 2666 return; 2667 } 2668 2669 status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats); 2670 if (status) { 2671 snprintf(out, out_size, "Learner table stats read error."); 2672 return; 2673 } 2674 2675 snprintf(out, out_size, "\tLearner table %s:\n" 2676 "\t\tHit (packets): %" PRIu64 "\n" 2677 "\t\tMiss (packets): %" PRIu64 "\n" 2678 "\t\tLearn OK (packets): %" PRIu64 "\n" 2679 "\t\tLearn error (packets): %" PRIu64 "\n" 2680 "\t\tRearm (packets): %" PRIu64 "\n" 2681 "\t\tForget (packets): %" PRIu64 "\n", 2682 learner_info.name, 2683 stats.n_pkts_hit, 2684 stats.n_pkts_miss, 2685 stats.n_pkts_learn_ok, 2686 stats.n_pkts_learn_err, 2687 stats.n_pkts_rearm, 2688 stats.n_pkts_forget); 2689 out_size -= strlen(out); 2690 out += strlen(out); 2691 2692 for (j = 0; j < info.n_actions; j++) { 2693 struct rte_swx_ctl_action_info action_info; 2694 2695 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 2696 if (status) { 2697 snprintf(out, out_size, "Action info get error."); 2698 return; 2699 } 2700 2701 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2702 action_info.name, 2703 stats.n_pkts_action[j]); 2704 out_size -= strlen(out); 2705 out += strlen(out); 2706 } 2707 } 2708 } 2709 2710 static const char cmd_pipeline_mirror_help[] = 2711 "pipeline <pipeline_name> mirror slots <n_slots> sessions <n_sessions>\n"; 2712 2713 static void 2714 cmd_pipeline_mirror(char **tokens, 2715 uint32_t n_tokens, 2716 char *out, 2717 size_t out_size, 2718 void *obj) 2719 { 2720 struct rte_swx_pipeline_mirroring_params params; 2721 struct pipeline *p; 2722 int status; 2723 2724 if (n_tokens != 7) { 2725 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2726 return; 2727 } 2728 2729 if (strcmp(tokens[0], "pipeline")) { 2730 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2731 return; 2732 } 2733 2734 p = pipeline_find(obj, tokens[1]); 2735 if (!p) { 2736 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2737 return; 2738 } 2739 2740 if (strcmp(tokens[2], "mirror")) { 2741 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror"); 2742 return; 2743 } 2744 2745 if (strcmp(tokens[3], "slots")) { 2746 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots"); 2747 return; 2748 } 2749 2750 if (parser_read_uint32(¶ms.n_slots, tokens[4])) { 2751 snprintf(out, out_size, MSG_ARG_INVALID, "n_slots"); 2752 return; 2753 } 2754 2755 if (strcmp(tokens[5], "sessions")) { 2756 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions"); 2757 return; 2758 } 2759 2760 if (parser_read_uint32(¶ms.n_sessions, tokens[6])) { 2761 snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions"); 2762 return; 2763 } 2764 2765 status = rte_swx_pipeline_mirroring_config(p->p, ¶ms); 2766 if (status) { 2767 snprintf(out, out_size, "Command failed!\n"); 2768 return; 2769 } 2770 } 2771 2772 static const char cmd_pipeline_mirror_session_help[] = 2773 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow " 2774 "truncate <truncation_length>\n"; 2775 2776 static void 2777 cmd_pipeline_mirror_session(char **tokens, 2778 uint32_t n_tokens, 2779 char *out, 2780 size_t out_size, 2781 void *obj) 2782 { 2783 struct rte_swx_pipeline_mirroring_session_params params; 2784 struct pipeline *p; 2785 uint32_t session_id = 0; 2786 int status; 2787 2788 if (n_tokens != 11) { 2789 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2790 return; 2791 } 2792 2793 if (strcmp(tokens[0], "pipeline")) { 2794 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2795 return; 2796 } 2797 2798 p = pipeline_find(obj, tokens[1]); 2799 if (!p || !p->ctl) { 2800 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2801 return; 2802 } 2803 2804 if (strcmp(tokens[2], "mirror")) { 2805 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror"); 2806 return; 2807 } 2808 2809 if (strcmp(tokens[3], "session")) { 2810 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "session"); 2811 return; 2812 } 2813 2814 if (parser_read_uint32(&session_id, tokens[4])) { 2815 snprintf(out, out_size, MSG_ARG_INVALID, "session_id"); 2816 return; 2817 } 2818 2819 if (strcmp(tokens[5], "port")) { 2820 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2821 return; 2822 } 2823 2824 if (parser_read_uint32(¶ms.port_id, tokens[6])) { 2825 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2826 return; 2827 } 2828 2829 if (strcmp(tokens[7], "clone")) { 2830 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "clone"); 2831 return; 2832 } 2833 2834 if (!strcmp(tokens[8], "fast")) 2835 params.fast_clone = 1; 2836 else if (!strcmp(tokens[8], "slow")) 2837 params.fast_clone = 0; 2838 else { 2839 snprintf(out, out_size, MSG_ARG_INVALID, "clone"); 2840 return; 2841 } 2842 2843 if (strcmp(tokens[9], "truncate")) { 2844 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "truncate"); 2845 return; 2846 } 2847 2848 if (parser_read_uint32(¶ms.truncation_length, tokens[10])) { 2849 snprintf(out, out_size, MSG_ARG_INVALID, "truncation_length"); 2850 return; 2851 } 2852 2853 status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, ¶ms); 2854 if (status) { 2855 snprintf(out, out_size, "Command failed!\n"); 2856 return; 2857 } 2858 } 2859 2860 static const char cmd_thread_pipeline_enable_help[] = 2861 "thread <thread_id> pipeline <pipeline_name> enable\n"; 2862 2863 static void 2864 cmd_thread_pipeline_enable(char **tokens, 2865 uint32_t n_tokens, 2866 char *out, 2867 size_t out_size, 2868 void *obj) 2869 { 2870 char *pipeline_name; 2871 struct pipeline *p; 2872 uint32_t thread_id; 2873 int status; 2874 2875 if (n_tokens != 5) { 2876 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2877 return; 2878 } 2879 2880 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2881 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2882 return; 2883 } 2884 2885 if (strcmp(tokens[2], "pipeline") != 0) { 2886 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2887 return; 2888 } 2889 2890 pipeline_name = tokens[3]; 2891 p = pipeline_find(obj, pipeline_name); 2892 if (!p || !p->ctl) { 2893 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2894 return; 2895 } 2896 2897 if (strcmp(tokens[4], "enable") != 0) { 2898 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2899 return; 2900 } 2901 2902 status = thread_pipeline_enable(thread_id, obj, pipeline_name); 2903 if (status) { 2904 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 2905 return; 2906 } 2907 } 2908 2909 static const char cmd_thread_pipeline_disable_help[] = 2910 "thread <thread_id> pipeline <pipeline_name> disable\n"; 2911 2912 static void 2913 cmd_thread_pipeline_disable(char **tokens, 2914 uint32_t n_tokens, 2915 char *out, 2916 size_t out_size, 2917 void *obj) 2918 { 2919 struct pipeline *p; 2920 char *pipeline_name; 2921 uint32_t thread_id; 2922 int status; 2923 2924 if (n_tokens != 5) { 2925 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2926 return; 2927 } 2928 2929 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2930 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2931 return; 2932 } 2933 2934 if (strcmp(tokens[2], "pipeline") != 0) { 2935 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2936 return; 2937 } 2938 2939 pipeline_name = tokens[3]; 2940 p = pipeline_find(obj, pipeline_name); 2941 if (!p || !p->ctl) { 2942 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2943 return; 2944 } 2945 2946 if (strcmp(tokens[4], "disable") != 0) { 2947 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2948 return; 2949 } 2950 2951 status = thread_pipeline_disable(thread_id, obj, pipeline_name); 2952 if (status) { 2953 snprintf(out, out_size, MSG_CMD_FAIL, 2954 "thread pipeline disable"); 2955 return; 2956 } 2957 } 2958 2959 static void 2960 cmd_help(char **tokens, 2961 uint32_t n_tokens, 2962 char *out, 2963 size_t out_size, 2964 void *arg __rte_unused) 2965 { 2966 tokens++; 2967 n_tokens--; 2968 2969 if (n_tokens == 0) { 2970 snprintf(out, out_size, 2971 "Type 'help <command>' for command details.\n\n" 2972 "List of commands:\n" 2973 "\tmempool\n" 2974 "\tlink\n" 2975 "\ttap\n" 2976 "\tpipeline create\n" 2977 "\tpipeline port in\n" 2978 "\tpipeline port out\n" 2979 "\tpipeline build\n" 2980 "\tpipeline table add\n" 2981 "\tpipeline table delete\n" 2982 "\tpipeline table default\n" 2983 "\tpipeline table show\n" 2984 "\tpipeline selector group add\n" 2985 "\tpipeline selector group delete\n" 2986 "\tpipeline selector group member add\n" 2987 "\tpipeline selector group member delete\n" 2988 "\tpipeline selector show\n" 2989 "\tpipeline learner default\n" 2990 "\tpipeline commit\n" 2991 "\tpipeline abort\n" 2992 "\tpipeline regrd\n" 2993 "\tpipeline regwr\n" 2994 "\tpipeline meter profile add\n" 2995 "\tpipeline meter profile delete\n" 2996 "\tpipeline meter reset\n" 2997 "\tpipeline meter set\n" 2998 "\tpipeline meter stats\n" 2999 "\tpipeline stats\n" 3000 "\tpipeline mirror\n" 3001 "\tpipeline mirror session\n" 3002 "\tthread pipeline enable\n" 3003 "\tthread pipeline disable\n\n"); 3004 return; 3005 } 3006 3007 if (strcmp(tokens[0], "mempool") == 0) { 3008 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 3009 return; 3010 } 3011 3012 if (strcmp(tokens[0], "link") == 0) { 3013 snprintf(out, out_size, "\n%s\n", cmd_link_help); 3014 return; 3015 } 3016 3017 if (strcmp(tokens[0], "ring") == 0) { 3018 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 3019 return; 3020 } 3021 3022 if (strcmp(tokens[0], "tap") == 0) { 3023 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 3024 return; 3025 } 3026 3027 if ((strcmp(tokens[0], "pipeline") == 0) && 3028 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { 3029 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); 3030 return; 3031 } 3032 3033 if ((strcmp(tokens[0], "pipeline") == 0) && 3034 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { 3035 if (strcmp(tokens[2], "in") == 0) { 3036 snprintf(out, out_size, "\n%s\n", 3037 cmd_pipeline_port_in_help); 3038 return; 3039 } 3040 3041 if (strcmp(tokens[2], "out") == 0) { 3042 snprintf(out, out_size, "\n%s\n", 3043 cmd_pipeline_port_out_help); 3044 return; 3045 } 3046 } 3047 3048 if ((strcmp(tokens[0], "pipeline") == 0) && 3049 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 3050 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 3051 return; 3052 } 3053 3054 if ((strcmp(tokens[0], "pipeline") == 0) && 3055 (n_tokens == 3) && 3056 (strcmp(tokens[1], "table") == 0) && 3057 (strcmp(tokens[2], "add") == 0)) { 3058 snprintf(out, out_size, "\n%s\n", 3059 cmd_pipeline_table_add_help); 3060 return; 3061 } 3062 3063 if ((strcmp(tokens[0], "pipeline") == 0) && 3064 (n_tokens == 3) && 3065 (strcmp(tokens[1], "table") == 0) && 3066 (strcmp(tokens[2], "delete") == 0)) { 3067 snprintf(out, out_size, "\n%s\n", 3068 cmd_pipeline_table_delete_help); 3069 return; 3070 } 3071 3072 if ((strcmp(tokens[0], "pipeline") == 0) && 3073 (n_tokens == 3) && 3074 (strcmp(tokens[1], "table") == 0) && 3075 (strcmp(tokens[2], "default") == 0)) { 3076 snprintf(out, out_size, "\n%s\n", 3077 cmd_pipeline_table_default_help); 3078 return; 3079 } 3080 3081 if ((strcmp(tokens[0], "pipeline") == 0) && 3082 (n_tokens == 3) && 3083 (strcmp(tokens[1], "table") == 0) && 3084 (strcmp(tokens[2], "show") == 0)) { 3085 snprintf(out, out_size, "\n%s\n", 3086 cmd_pipeline_table_show_help); 3087 return; 3088 } 3089 3090 if ((strcmp(tokens[0], "pipeline") == 0) && 3091 (n_tokens == 4) && 3092 (strcmp(tokens[1], "selector") == 0) && 3093 (strcmp(tokens[2], "group") == 0) && 3094 (strcmp(tokens[3], "add") == 0)) { 3095 snprintf(out, out_size, "\n%s\n", 3096 cmd_pipeline_selector_group_add_help); 3097 return; 3098 } 3099 3100 if ((strcmp(tokens[0], "pipeline") == 0) && 3101 (n_tokens == 4) && 3102 (strcmp(tokens[1], "selector") == 0) && 3103 (strcmp(tokens[2], "group") == 0) && 3104 (strcmp(tokens[3], "delete") == 0)) { 3105 snprintf(out, out_size, "\n%s\n", 3106 cmd_pipeline_selector_group_delete_help); 3107 return; 3108 } 3109 3110 if ((strcmp(tokens[0], "pipeline") == 0) && 3111 (n_tokens == 5) && 3112 (strcmp(tokens[1], "selector") == 0) && 3113 (strcmp(tokens[2], "group") == 0) && 3114 (strcmp(tokens[3], "member") == 0) && 3115 (strcmp(tokens[4], "add") == 0)) { 3116 snprintf(out, out_size, "\n%s\n", 3117 cmd_pipeline_selector_group_member_add_help); 3118 return; 3119 } 3120 3121 if ((strcmp(tokens[0], "pipeline") == 0) && 3122 (n_tokens == 5) && 3123 (strcmp(tokens[1], "selector") == 0) && 3124 (strcmp(tokens[2], "group") == 0) && 3125 (strcmp(tokens[3], "member") == 0) && 3126 (strcmp(tokens[4], "delete") == 0)) { 3127 snprintf(out, out_size, "\n%s\n", 3128 cmd_pipeline_selector_group_member_delete_help); 3129 return; 3130 } 3131 3132 if ((strcmp(tokens[0], "pipeline") == 0) && 3133 (n_tokens == 3) && 3134 (strcmp(tokens[1], "selector") == 0) && 3135 (strcmp(tokens[2], "show") == 0)) { 3136 snprintf(out, out_size, "\n%s\n", 3137 cmd_pipeline_selector_show_help); 3138 return; 3139 } 3140 3141 if ((strcmp(tokens[0], "pipeline") == 0) && 3142 (n_tokens == 3) && 3143 (strcmp(tokens[1], "learner") == 0) && 3144 (strcmp(tokens[2], "default") == 0)) { 3145 snprintf(out, out_size, "\n%s\n", 3146 cmd_pipeline_learner_default_help); 3147 return; 3148 } 3149 3150 if ((strcmp(tokens[0], "pipeline") == 0) && 3151 (n_tokens == 2) && 3152 (strcmp(tokens[1], "commit") == 0)) { 3153 snprintf(out, out_size, "\n%s\n", 3154 cmd_pipeline_commit_help); 3155 return; 3156 } 3157 3158 if ((strcmp(tokens[0], "pipeline") == 0) && 3159 (n_tokens == 2) && 3160 (strcmp(tokens[1], "abort") == 0)) { 3161 snprintf(out, out_size, "\n%s\n", 3162 cmd_pipeline_abort_help); 3163 return; 3164 } 3165 3166 if ((strcmp(tokens[0], "pipeline") == 0) && 3167 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 3168 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 3169 return; 3170 } 3171 3172 if ((strcmp(tokens[0], "pipeline") == 0) && 3173 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 3174 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 3175 return; 3176 } 3177 3178 if (!strcmp(tokens[0], "pipeline") && 3179 (n_tokens == 4) && !strcmp(tokens[1], "meter") 3180 && !strcmp(tokens[2], "profile") 3181 && !strcmp(tokens[3], "add")) { 3182 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 3183 return; 3184 } 3185 3186 if (!strcmp(tokens[0], "pipeline") && 3187 (n_tokens == 4) && !strcmp(tokens[1], "meter") 3188 && !strcmp(tokens[2], "profile") 3189 && !strcmp(tokens[3], "delete")) { 3190 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 3191 return; 3192 } 3193 3194 if (!strcmp(tokens[0], "pipeline") && 3195 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3196 && !strcmp(tokens[2], "reset")) { 3197 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 3198 return; 3199 } 3200 3201 if (!strcmp(tokens[0], "pipeline") && 3202 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3203 && !strcmp(tokens[2], "set")) { 3204 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 3205 return; 3206 } 3207 3208 if (!strcmp(tokens[0], "pipeline") && 3209 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3210 && !strcmp(tokens[2], "stats")) { 3211 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 3212 return; 3213 } 3214 3215 if ((strcmp(tokens[0], "pipeline") == 0) && 3216 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 3217 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 3218 return; 3219 } 3220 3221 if (!strcmp(tokens[0], "pipeline") && 3222 (n_tokens == 2) && !strcmp(tokens[1], "mirror")) { 3223 snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help); 3224 return; 3225 } 3226 3227 if (!strcmp(tokens[0], "pipeline") && 3228 (n_tokens == 3) && !strcmp(tokens[1], "mirror") 3229 && !strcmp(tokens[2], "session")) { 3230 snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_session_help); 3231 return; 3232 } 3233 3234 if ((n_tokens == 3) && 3235 (strcmp(tokens[0], "thread") == 0) && 3236 (strcmp(tokens[1], "pipeline") == 0)) { 3237 if (strcmp(tokens[2], "enable") == 0) { 3238 snprintf(out, out_size, "\n%s\n", 3239 cmd_thread_pipeline_enable_help); 3240 return; 3241 } 3242 3243 if (strcmp(tokens[2], "disable") == 0) { 3244 snprintf(out, out_size, "\n%s\n", 3245 cmd_thread_pipeline_disable_help); 3246 return; 3247 } 3248 } 3249 3250 snprintf(out, out_size, "Invalid command\n"); 3251 } 3252 3253 void 3254 cli_process(char *in, char *out, size_t out_size, void *obj) 3255 { 3256 char *tokens[CMD_MAX_TOKENS]; 3257 uint32_t n_tokens = RTE_DIM(tokens); 3258 int status; 3259 3260 if (is_comment(in)) 3261 return; 3262 3263 status = parse_tokenize_string(in, tokens, &n_tokens); 3264 if (status) { 3265 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 3266 return; 3267 } 3268 3269 if (n_tokens == 0) 3270 return; 3271 3272 if (strcmp(tokens[0], "help") == 0) { 3273 cmd_help(tokens, n_tokens, out, out_size, obj); 3274 return; 3275 } 3276 3277 if (strcmp(tokens[0], "mempool") == 0) { 3278 cmd_mempool(tokens, n_tokens, out, out_size, obj); 3279 return; 3280 } 3281 3282 if (strcmp(tokens[0], "link") == 0) { 3283 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 3284 cmd_link_show(tokens, n_tokens, out, out_size, obj); 3285 return; 3286 } 3287 3288 cmd_link(tokens, n_tokens, out, out_size, obj); 3289 return; 3290 } 3291 3292 if (strcmp(tokens[0], "ring") == 0) { 3293 cmd_ring(tokens, n_tokens, out, out_size, obj); 3294 return; 3295 } 3296 3297 if (strcmp(tokens[0], "tap") == 0) { 3298 cmd_tap(tokens, n_tokens, out, out_size, obj); 3299 return; 3300 } 3301 3302 if (strcmp(tokens[0], "pipeline") == 0) { 3303 if ((n_tokens >= 3) && 3304 (strcmp(tokens[2], "create") == 0)) { 3305 cmd_pipeline_create(tokens, n_tokens, out, out_size, 3306 obj); 3307 return; 3308 } 3309 3310 if ((n_tokens >= 4) && 3311 (strcmp(tokens[2], "port") == 0) && 3312 (strcmp(tokens[3], "in") == 0)) { 3313 cmd_pipeline_port_in(tokens, n_tokens, out, out_size, 3314 obj); 3315 return; 3316 } 3317 3318 if ((n_tokens >= 4) && 3319 (strcmp(tokens[2], "port") == 0) && 3320 (strcmp(tokens[3], "out") == 0)) { 3321 cmd_pipeline_port_out(tokens, n_tokens, out, out_size, 3322 obj); 3323 return; 3324 } 3325 3326 if ((n_tokens >= 3) && 3327 (strcmp(tokens[2], "build") == 0)) { 3328 cmd_pipeline_build(tokens, n_tokens, out, out_size, 3329 obj); 3330 return; 3331 } 3332 3333 if ((n_tokens >= 5) && 3334 (strcmp(tokens[2], "table") == 0) && 3335 (strcmp(tokens[4], "add") == 0)) { 3336 cmd_pipeline_table_add(tokens, n_tokens, out, 3337 out_size, obj); 3338 return; 3339 } 3340 3341 if ((n_tokens >= 5) && 3342 (strcmp(tokens[2], "table") == 0) && 3343 (strcmp(tokens[4], "delete") == 0)) { 3344 cmd_pipeline_table_delete(tokens, n_tokens, out, 3345 out_size, obj); 3346 return; 3347 } 3348 3349 if ((n_tokens >= 5) && 3350 (strcmp(tokens[2], "table") == 0) && 3351 (strcmp(tokens[4], "default") == 0)) { 3352 cmd_pipeline_table_default(tokens, n_tokens, out, 3353 out_size, obj); 3354 return; 3355 } 3356 3357 if ((n_tokens >= 5) && 3358 (strcmp(tokens[2], "table") == 0) && 3359 (strcmp(tokens[4], "show") == 0)) { 3360 cmd_pipeline_table_show(tokens, n_tokens, out, 3361 out_size, obj); 3362 return; 3363 } 3364 3365 if ((n_tokens >= 6) && 3366 (strcmp(tokens[2], "selector") == 0) && 3367 (strcmp(tokens[4], "group") == 0) && 3368 (strcmp(tokens[5], "add") == 0)) { 3369 cmd_pipeline_selector_group_add(tokens, n_tokens, out, 3370 out_size, obj); 3371 return; 3372 } 3373 3374 if ((n_tokens >= 6) && 3375 (strcmp(tokens[2], "selector") == 0) && 3376 (strcmp(tokens[4], "group") == 0) && 3377 (strcmp(tokens[5], "delete") == 0)) { 3378 cmd_pipeline_selector_group_delete(tokens, n_tokens, out, 3379 out_size, obj); 3380 return; 3381 } 3382 3383 if ((n_tokens >= 7) && 3384 (strcmp(tokens[2], "selector") == 0) && 3385 (strcmp(tokens[4], "group") == 0) && 3386 (strcmp(tokens[5], "member") == 0) && 3387 (strcmp(tokens[6], "add") == 0)) { 3388 cmd_pipeline_selector_group_member_add(tokens, n_tokens, out, 3389 out_size, obj); 3390 return; 3391 } 3392 3393 if ((n_tokens >= 7) && 3394 (strcmp(tokens[2], "selector") == 0) && 3395 (strcmp(tokens[4], "group") == 0) && 3396 (strcmp(tokens[5], "member") == 0) && 3397 (strcmp(tokens[6], "delete") == 0)) { 3398 cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out, 3399 out_size, obj); 3400 return; 3401 } 3402 3403 if ((n_tokens >= 5) && 3404 (strcmp(tokens[2], "selector") == 0) && 3405 (strcmp(tokens[4], "show") == 0)) { 3406 cmd_pipeline_selector_show(tokens, n_tokens, out, 3407 out_size, obj); 3408 return; 3409 } 3410 3411 if ((n_tokens >= 5) && 3412 (strcmp(tokens[2], "learner") == 0) && 3413 (strcmp(tokens[4], "default") == 0)) { 3414 cmd_pipeline_learner_default(tokens, n_tokens, out, 3415 out_size, obj); 3416 return; 3417 } 3418 3419 if ((n_tokens >= 3) && 3420 (strcmp(tokens[2], "commit") == 0)) { 3421 cmd_pipeline_commit(tokens, n_tokens, out, 3422 out_size, obj); 3423 return; 3424 } 3425 3426 if ((n_tokens >= 3) && 3427 (strcmp(tokens[2], "abort") == 0)) { 3428 cmd_pipeline_abort(tokens, n_tokens, out, 3429 out_size, obj); 3430 return; 3431 } 3432 3433 if ((n_tokens >= 3) && 3434 (strcmp(tokens[2], "regrd") == 0)) { 3435 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 3436 return; 3437 } 3438 3439 if ((n_tokens >= 3) && 3440 (strcmp(tokens[2], "regwr") == 0)) { 3441 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 3442 return; 3443 } 3444 3445 if ((n_tokens >= 6) && 3446 (strcmp(tokens[2], "meter") == 0) && 3447 (strcmp(tokens[3], "profile") == 0) && 3448 (strcmp(tokens[5], "add") == 0)) { 3449 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 3450 return; 3451 } 3452 3453 if ((n_tokens >= 6) && 3454 (strcmp(tokens[2], "meter") == 0) && 3455 (strcmp(tokens[3], "profile") == 0) && 3456 (strcmp(tokens[5], "delete") == 0)) { 3457 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 3458 return; 3459 } 3460 3461 if ((n_tokens >= 9) && 3462 (strcmp(tokens[2], "meter") == 0) && 3463 (strcmp(tokens[8], "reset") == 0)) { 3464 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 3465 return; 3466 } 3467 3468 if ((n_tokens >= 9) && 3469 (strcmp(tokens[2], "meter") == 0) && 3470 (strcmp(tokens[8], "set") == 0)) { 3471 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 3472 return; 3473 } 3474 3475 if ((n_tokens >= 9) && 3476 (strcmp(tokens[2], "meter") == 0) && 3477 (strcmp(tokens[8], "stats") == 0)) { 3478 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 3479 return; 3480 } 3481 3482 if ((n_tokens >= 3) && 3483 (strcmp(tokens[2], "stats") == 0)) { 3484 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 3485 obj); 3486 return; 3487 } 3488 3489 if ((n_tokens >= 4) && 3490 (strcmp(tokens[2], "mirror") == 0) && 3491 (strcmp(tokens[3], "slots") == 0)) { 3492 cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj); 3493 return; 3494 } 3495 3496 if ((n_tokens >= 4) && 3497 (strcmp(tokens[2], "mirror") == 0) && 3498 (strcmp(tokens[3], "session") == 0)) { 3499 cmd_pipeline_mirror_session(tokens, n_tokens, out, out_size, obj); 3500 return; 3501 } 3502 } 3503 3504 if (strcmp(tokens[0], "thread") == 0) { 3505 if ((n_tokens >= 5) && 3506 (strcmp(tokens[4], "enable") == 0)) { 3507 cmd_thread_pipeline_enable(tokens, n_tokens, 3508 out, out_size, obj); 3509 return; 3510 } 3511 3512 if ((n_tokens >= 5) && 3513 (strcmp(tokens[4], "disable") == 0)) { 3514 cmd_thread_pipeline_disable(tokens, n_tokens, 3515 out, out_size, obj); 3516 return; 3517 } 3518 } 3519 3520 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 3521 } 3522 3523 int 3524 cli_script_process(const char *file_name, 3525 size_t msg_in_len_max, 3526 size_t msg_out_len_max, 3527 void *obj) 3528 { 3529 char *msg_in = NULL, *msg_out = NULL; 3530 FILE *f = NULL; 3531 3532 /* Check input arguments */ 3533 if ((file_name == NULL) || 3534 (strlen(file_name) == 0) || 3535 (msg_in_len_max == 0) || 3536 (msg_out_len_max == 0)) 3537 return -EINVAL; 3538 3539 msg_in = malloc(msg_in_len_max + 1); 3540 msg_out = malloc(msg_out_len_max + 1); 3541 if ((msg_in == NULL) || 3542 (msg_out == NULL)) { 3543 free(msg_out); 3544 free(msg_in); 3545 return -ENOMEM; 3546 } 3547 3548 /* Open input file */ 3549 f = fopen(file_name, "r"); 3550 if (f == NULL) { 3551 free(msg_out); 3552 free(msg_in); 3553 return -EIO; 3554 } 3555 3556 /* Read file */ 3557 for ( ; ; ) { 3558 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 3559 break; 3560 3561 printf("%s", msg_in); 3562 msg_out[0] = 0; 3563 3564 cli_process(msg_in, 3565 msg_out, 3566 msg_out_len_max, 3567 obj); 3568 3569 if (strlen(msg_out)) 3570 printf("%s", msg_out); 3571 } 3572 3573 /* Close file */ 3574 fclose(f); 3575 free(msg_out); 3576 free(msg_in); 3577 return 0; 3578 } 3579