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\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 int status; 1361 1362 if (n_tokens != 5) { 1363 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1364 return; 1365 } 1366 1367 pipeline_name = tokens[1]; 1368 p = pipeline_find(obj, pipeline_name); 1369 if (!p || !p->ctl) { 1370 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1371 return; 1372 } 1373 1374 table_name = tokens[3]; 1375 status = rte_swx_ctl_pipeline_table_fprintf(stdout, p->ctl, table_name); 1376 if (status) 1377 snprintf(out, out_size, MSG_ARG_INVALID, "table_name"); 1378 } 1379 1380 static const char cmd_pipeline_selector_group_add_help[] = 1381 "pipeline <pipeline_name> selector <selector_name> group add\n"; 1382 1383 static void 1384 cmd_pipeline_selector_group_add(char **tokens, 1385 uint32_t n_tokens, 1386 char *out, 1387 size_t out_size, 1388 void *obj) 1389 { 1390 struct pipeline *p; 1391 char *pipeline_name, *selector_name; 1392 uint32_t group_id; 1393 int status; 1394 1395 if (n_tokens != 6) { 1396 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1397 return; 1398 } 1399 1400 pipeline_name = tokens[1]; 1401 p = pipeline_find(obj, pipeline_name); 1402 if (!p || !p->ctl) { 1403 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1404 return; 1405 } 1406 1407 if (strcmp(tokens[2], "selector") != 0) { 1408 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1409 return; 1410 } 1411 1412 selector_name = tokens[3]; 1413 1414 if (strcmp(tokens[4], "group") || 1415 strcmp(tokens[5], "add")) { 1416 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add"); 1417 return; 1418 } 1419 1420 status = rte_swx_ctl_pipeline_selector_group_add(p->ctl, 1421 selector_name, 1422 &group_id); 1423 if (status) 1424 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1425 else 1426 snprintf(out, out_size, "Group ID: %u\n", group_id); 1427 } 1428 1429 static const char cmd_pipeline_selector_group_delete_help[] = 1430 "pipeline <pipeline_name> selector <selector_name> group delete <group_id>\n"; 1431 1432 static void 1433 cmd_pipeline_selector_group_delete(char **tokens, 1434 uint32_t n_tokens, 1435 char *out, 1436 size_t out_size, 1437 void *obj) 1438 { 1439 struct pipeline *p; 1440 char *pipeline_name, *selector_name; 1441 uint32_t group_id; 1442 int status; 1443 1444 if (n_tokens != 7) { 1445 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1446 return; 1447 } 1448 1449 pipeline_name = tokens[1]; 1450 p = pipeline_find(obj, pipeline_name); 1451 if (!p || !p->ctl) { 1452 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1453 return; 1454 } 1455 1456 if (strcmp(tokens[2], "selector") != 0) { 1457 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1458 return; 1459 } 1460 1461 selector_name = tokens[3]; 1462 1463 if (strcmp(tokens[4], "group") || 1464 strcmp(tokens[5], "delete")) { 1465 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete"); 1466 return; 1467 } 1468 1469 if (parser_read_uint32(&group_id, tokens[6]) != 0) { 1470 snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); 1471 return; 1472 } 1473 1474 status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl, 1475 selector_name, 1476 group_id); 1477 if (status) 1478 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1479 } 1480 1481 #define GROUP_MEMBER_INFO_TOKENS_MAX 6 1482 1483 static int 1484 token_is_comment(const char *token) 1485 { 1486 if ((token[0] == '#') || 1487 (token[0] == ';') || 1488 ((token[0] == '/') && (token[1] == '/'))) 1489 return 1; /* TRUE. */ 1490 1491 return 0; /* FALSE. */ 1492 } 1493 1494 static int 1495 pipeline_selector_group_member_read(const char *string, 1496 uint32_t *group_id, 1497 uint32_t *member_id, 1498 uint32_t *weight, 1499 int *is_blank_or_comment) 1500 { 1501 char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens; 1502 char *s0 = NULL, *s; 1503 uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0; 1504 int blank_or_comment = 0; 1505 1506 /* Check input arguments. */ 1507 if (!string || !string[0]) 1508 goto error; 1509 1510 /* Memory allocation. */ 1511 s0 = strdup(string); 1512 if (!s0) 1513 goto error; 1514 1515 /* Parse the string into tokens. */ 1516 for (s = s0; ; ) { 1517 char *token; 1518 1519 token = strtok_r(s, " \f\n\r\t\v", &s); 1520 if (!token || token_is_comment(token)) 1521 break; 1522 1523 if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX) 1524 goto error; 1525 1526 token_array[n_tokens] = token; 1527 n_tokens++; 1528 } 1529 1530 if (!n_tokens) { 1531 blank_or_comment = 1; 1532 goto error; 1533 } 1534 1535 tokens = token_array; 1536 1537 if (n_tokens < 4 || 1538 strcmp(tokens[0], "group") || 1539 strcmp(tokens[2], "member")) 1540 goto error; 1541 1542 /* 1543 * Group ID. 1544 */ 1545 if (parser_read_uint32(&group_id_val, tokens[1]) != 0) 1546 goto error; 1547 *group_id = group_id_val; 1548 1549 /* 1550 * Member ID. 1551 */ 1552 if (parser_read_uint32(&member_id_val, tokens[3]) != 0) 1553 goto error; 1554 *member_id = member_id_val; 1555 1556 tokens += 4; 1557 n_tokens -= 4; 1558 1559 /* 1560 * Weight. 1561 */ 1562 if (n_tokens && !strcmp(tokens[0], "weight")) { 1563 if (n_tokens < 2) 1564 goto error; 1565 1566 if (parser_read_uint32(&weight_val, tokens[1]) != 0) 1567 goto error; 1568 *weight = weight_val; 1569 1570 tokens += 2; 1571 n_tokens -= 2; 1572 } 1573 1574 if (n_tokens) 1575 goto error; 1576 1577 free(s0); 1578 return 0; 1579 1580 error: 1581 free(s0); 1582 if (is_blank_or_comment) 1583 *is_blank_or_comment = blank_or_comment; 1584 return -EINVAL; 1585 } 1586 1587 static int 1588 pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p, 1589 const char *selector_name, 1590 FILE *file, 1591 uint32_t *file_line_number) 1592 { 1593 char *line = NULL; 1594 uint32_t line_id = 0; 1595 int status = 0; 1596 1597 /* Buffer allocation. */ 1598 line = malloc(MAX_LINE_SIZE); 1599 if (!line) 1600 return -ENOMEM; 1601 1602 /* File read. */ 1603 for (line_id = 1; ; line_id++) { 1604 uint32_t group_id, member_id, weight; 1605 int is_blank_or_comment; 1606 1607 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1608 break; 1609 1610 status = pipeline_selector_group_member_read(line, 1611 &group_id, 1612 &member_id, 1613 &weight, 1614 &is_blank_or_comment); 1615 if (status) { 1616 if (is_blank_or_comment) 1617 continue; 1618 1619 goto error; 1620 } 1621 1622 status = rte_swx_ctl_pipeline_selector_group_member_add(p, 1623 selector_name, 1624 group_id, 1625 member_id, 1626 weight); 1627 if (status) 1628 goto error; 1629 } 1630 1631 error: 1632 free(line); 1633 *file_line_number = line_id; 1634 return status; 1635 } 1636 1637 static const char cmd_pipeline_selector_group_member_add_help[] = 1638 "pipeline <pipeline_name> selector <selector_name> group member add <file_name>"; 1639 1640 static void 1641 cmd_pipeline_selector_group_member_add(char **tokens, 1642 uint32_t n_tokens, 1643 char *out, 1644 size_t out_size, 1645 void *obj) 1646 { 1647 struct pipeline *p; 1648 char *pipeline_name, *selector_name, *file_name; 1649 FILE *file = NULL; 1650 uint32_t file_line_number = 0; 1651 int status; 1652 1653 if (n_tokens != 8) { 1654 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1655 return; 1656 } 1657 1658 pipeline_name = tokens[1]; 1659 p = pipeline_find(obj, pipeline_name); 1660 if (!p || !p->ctl) { 1661 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1662 return; 1663 } 1664 1665 if (strcmp(tokens[2], "selector") != 0) { 1666 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1667 return; 1668 } 1669 1670 selector_name = tokens[3]; 1671 1672 if (strcmp(tokens[4], "group") || 1673 strcmp(tokens[5], "member") || 1674 strcmp(tokens[6], "add")) { 1675 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add"); 1676 return; 1677 } 1678 1679 file_name = tokens[7]; 1680 file = fopen(file_name, "r"); 1681 if (!file) { 1682 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1683 return; 1684 } 1685 1686 status = pipeline_selector_group_members_add(p->ctl, 1687 selector_name, 1688 file, 1689 &file_line_number); 1690 if (status) 1691 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1692 file_name, 1693 file_line_number); 1694 1695 fclose(file); 1696 } 1697 1698 static int 1699 pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p, 1700 const char *selector_name, 1701 FILE *file, 1702 uint32_t *file_line_number) 1703 { 1704 char *line = NULL; 1705 uint32_t line_id = 0; 1706 int status = 0; 1707 1708 /* Buffer allocation. */ 1709 line = malloc(MAX_LINE_SIZE); 1710 if (!line) 1711 return -ENOMEM; 1712 1713 /* File read. */ 1714 for (line_id = 1; ; line_id++) { 1715 uint32_t group_id, member_id, weight; 1716 int is_blank_or_comment; 1717 1718 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1719 break; 1720 1721 status = pipeline_selector_group_member_read(line, 1722 &group_id, 1723 &member_id, 1724 &weight, 1725 &is_blank_or_comment); 1726 if (status) { 1727 if (is_blank_or_comment) 1728 continue; 1729 1730 goto error; 1731 } 1732 1733 status = rte_swx_ctl_pipeline_selector_group_member_delete(p, 1734 selector_name, 1735 group_id, 1736 member_id); 1737 if (status) 1738 goto error; 1739 } 1740 1741 error: 1742 free(line); 1743 *file_line_number = line_id; 1744 return status; 1745 } 1746 1747 static const char cmd_pipeline_selector_group_member_delete_help[] = 1748 "pipeline <pipeline_name> selector <selector_name> group member delete <file_name>"; 1749 1750 static void 1751 cmd_pipeline_selector_group_member_delete(char **tokens, 1752 uint32_t n_tokens, 1753 char *out, 1754 size_t out_size, 1755 void *obj) 1756 { 1757 struct pipeline *p; 1758 char *pipeline_name, *selector_name, *file_name; 1759 FILE *file = NULL; 1760 uint32_t file_line_number = 0; 1761 int status; 1762 1763 if (n_tokens != 8) { 1764 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1765 return; 1766 } 1767 1768 pipeline_name = tokens[1]; 1769 p = pipeline_find(obj, pipeline_name); 1770 if (!p || !p->ctl) { 1771 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1772 return; 1773 } 1774 1775 if (strcmp(tokens[2], "selector") != 0) { 1776 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector"); 1777 return; 1778 } 1779 1780 selector_name = tokens[3]; 1781 1782 if (strcmp(tokens[4], "group") || 1783 strcmp(tokens[5], "member") || 1784 strcmp(tokens[6], "delete")) { 1785 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete"); 1786 return; 1787 } 1788 1789 file_name = tokens[7]; 1790 file = fopen(file_name, "r"); 1791 if (!file) { 1792 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1793 return; 1794 } 1795 1796 status = pipeline_selector_group_members_delete(p->ctl, 1797 selector_name, 1798 file, 1799 &file_line_number); 1800 if (status) 1801 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1802 file_name, 1803 file_line_number); 1804 1805 fclose(file); 1806 } 1807 1808 static const char cmd_pipeline_selector_show_help[] = 1809 "pipeline <pipeline_name> selector <selector_name> show\n"; 1810 1811 static void 1812 cmd_pipeline_selector_show(char **tokens, 1813 uint32_t n_tokens, 1814 char *out, 1815 size_t out_size, 1816 void *obj) 1817 { 1818 struct pipeline *p; 1819 char *pipeline_name, *selector_name; 1820 int status; 1821 1822 if (n_tokens != 5) { 1823 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1824 return; 1825 } 1826 1827 pipeline_name = tokens[1]; 1828 p = pipeline_find(obj, pipeline_name); 1829 if (!p || !p->ctl) { 1830 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1831 return; 1832 } 1833 1834 selector_name = tokens[3]; 1835 status = rte_swx_ctl_pipeline_selector_fprintf(stdout, 1836 p->ctl, selector_name); 1837 if (status) 1838 snprintf(out, out_size, MSG_ARG_INVALID, "selector_name"); 1839 } 1840 1841 static int 1842 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p, 1843 const char *learner_name, 1844 FILE *file, 1845 uint32_t *file_line_number) 1846 { 1847 char *line = NULL; 1848 uint32_t line_id = 0; 1849 int status = 0; 1850 1851 /* Buffer allocation. */ 1852 line = malloc(MAX_LINE_SIZE); 1853 if (!line) 1854 return -ENOMEM; 1855 1856 /* File read. */ 1857 for (line_id = 1; ; line_id++) { 1858 struct rte_swx_table_entry *entry; 1859 int is_blank_or_comment; 1860 1861 if (fgets(line, MAX_LINE_SIZE, file) == NULL) 1862 break; 1863 1864 entry = rte_swx_ctl_pipeline_learner_default_entry_read(p, 1865 learner_name, 1866 line, 1867 &is_blank_or_comment); 1868 if (!entry) { 1869 if (is_blank_or_comment) 1870 continue; 1871 1872 status = -EINVAL; 1873 goto error; 1874 } 1875 1876 status = rte_swx_ctl_pipeline_learner_default_entry_add(p, 1877 learner_name, 1878 entry); 1879 table_entry_free(entry); 1880 if (status) 1881 goto error; 1882 } 1883 1884 error: 1885 *file_line_number = line_id; 1886 free(line); 1887 return status; 1888 } 1889 1890 static const char cmd_pipeline_learner_default_help[] = 1891 "pipeline <pipeline_name> learner <learner_name> default <file_name>\n"; 1892 1893 static void 1894 cmd_pipeline_learner_default(char **tokens, 1895 uint32_t n_tokens, 1896 char *out, 1897 size_t out_size, 1898 void *obj) 1899 { 1900 struct pipeline *p; 1901 char *pipeline_name, *learner_name, *file_name; 1902 FILE *file = NULL; 1903 uint32_t file_line_number = 0; 1904 int status; 1905 1906 if (n_tokens != 6) { 1907 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1908 return; 1909 } 1910 1911 pipeline_name = tokens[1]; 1912 p = pipeline_find(obj, pipeline_name); 1913 if (!p || !p->ctl) { 1914 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1915 return; 1916 } 1917 1918 learner_name = tokens[3]; 1919 1920 file_name = tokens[5]; 1921 file = fopen(file_name, "r"); 1922 if (!file) { 1923 snprintf(out, out_size, "Cannot open file %s.\n", file_name); 1924 return; 1925 } 1926 1927 status = pipeline_learner_default_entry_add(p->ctl, 1928 learner_name, 1929 file, 1930 &file_line_number); 1931 if (status) 1932 snprintf(out, out_size, "Invalid entry in file %s at line %u\n", 1933 file_name, 1934 file_line_number); 1935 1936 fclose(file); 1937 } 1938 1939 static const char cmd_pipeline_commit_help[] = 1940 "pipeline <pipeline_name> commit\n"; 1941 1942 static void 1943 cmd_pipeline_commit(char **tokens, 1944 uint32_t n_tokens, 1945 char *out, 1946 size_t out_size, 1947 void *obj) 1948 { 1949 struct pipeline *p; 1950 char *pipeline_name; 1951 int status; 1952 1953 if (n_tokens != 3) { 1954 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1955 return; 1956 } 1957 1958 pipeline_name = tokens[1]; 1959 p = pipeline_find(obj, pipeline_name); 1960 if (!p || !p->ctl) { 1961 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1962 return; 1963 } 1964 1965 status = rte_swx_ctl_pipeline_commit(p->ctl, 1); 1966 if (status) 1967 snprintf(out, out_size, "Commit failed. " 1968 "Use \"commit\" to retry or \"abort\" to discard the pending work.\n"); 1969 } 1970 1971 static const char cmd_pipeline_abort_help[] = 1972 "pipeline <pipeline_name> abort\n"; 1973 1974 static void 1975 cmd_pipeline_abort(char **tokens, 1976 uint32_t n_tokens, 1977 char *out, 1978 size_t out_size, 1979 void *obj) 1980 { 1981 struct pipeline *p; 1982 char *pipeline_name; 1983 1984 if (n_tokens != 3) { 1985 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1986 return; 1987 } 1988 1989 pipeline_name = tokens[1]; 1990 p = pipeline_find(obj, pipeline_name); 1991 if (!p || !p->ctl) { 1992 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1993 return; 1994 } 1995 1996 rte_swx_ctl_pipeline_abort(p->ctl); 1997 } 1998 1999 static const char cmd_pipeline_regrd_help[] = 2000 "pipeline <pipeline_name> regrd <register_array_name> <index>\n"; 2001 2002 static void 2003 cmd_pipeline_regrd(char **tokens, 2004 uint32_t n_tokens, 2005 char *out, 2006 size_t out_size, 2007 void *obj) 2008 { 2009 struct pipeline *p; 2010 const char *name; 2011 uint64_t value; 2012 uint32_t idx; 2013 int status; 2014 2015 if (n_tokens != 5) { 2016 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2017 return; 2018 } 2019 2020 p = pipeline_find(obj, tokens[1]); 2021 if (!p || !p->ctl) { 2022 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2023 return; 2024 } 2025 2026 if (strcmp(tokens[2], "regrd")) { 2027 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd"); 2028 return; 2029 } 2030 2031 name = tokens[3]; 2032 2033 if (parser_read_uint32(&idx, tokens[4])) { 2034 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 2035 return; 2036 } 2037 2038 status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value); 2039 if (status) { 2040 snprintf(out, out_size, "Command failed.\n"); 2041 return; 2042 } 2043 2044 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 2045 } 2046 2047 static const char cmd_pipeline_regwr_help[] = 2048 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n"; 2049 2050 static void 2051 cmd_pipeline_regwr(char **tokens, 2052 uint32_t n_tokens, 2053 char *out, 2054 size_t out_size, 2055 void *obj) 2056 { 2057 struct pipeline *p; 2058 const char *name; 2059 uint64_t value; 2060 uint32_t idx; 2061 int status; 2062 2063 if (n_tokens != 6) { 2064 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2065 return; 2066 } 2067 2068 p = pipeline_find(obj, tokens[1]); 2069 if (!p || !p->ctl) { 2070 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2071 return; 2072 } 2073 2074 if (strcmp(tokens[2], "regwr")) { 2075 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr"); 2076 return; 2077 } 2078 2079 name = tokens[3]; 2080 2081 if (parser_read_uint32(&idx, tokens[4])) { 2082 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 2083 return; 2084 } 2085 2086 if (parser_read_uint64(&value, tokens[5])) { 2087 snprintf(out, out_size, MSG_ARG_INVALID, "value"); 2088 return; 2089 } 2090 2091 status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value); 2092 if (status) { 2093 snprintf(out, out_size, "Command failed.\n"); 2094 return; 2095 } 2096 } 2097 2098 static const char cmd_pipeline_meter_profile_add_help[] = 2099 "pipeline <pipeline_name> meter profile <profile_name> add " 2100 "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 2101 2102 static void 2103 cmd_pipeline_meter_profile_add(char **tokens, 2104 uint32_t n_tokens, 2105 char *out, 2106 size_t out_size, 2107 void *obj) 2108 { 2109 struct rte_meter_trtcm_params params; 2110 struct pipeline *p; 2111 const char *profile_name; 2112 int status; 2113 2114 if (n_tokens != 14) { 2115 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2116 return; 2117 } 2118 2119 p = pipeline_find(obj, tokens[1]); 2120 if (!p || !p->ctl) { 2121 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2122 return; 2123 } 2124 2125 if (strcmp(tokens[2], "meter")) { 2126 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2127 return; 2128 } 2129 2130 if (strcmp(tokens[3], "profile")) { 2131 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2132 return; 2133 } 2134 2135 profile_name = tokens[4]; 2136 2137 if (strcmp(tokens[5], "add")) { 2138 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 2139 return; 2140 } 2141 2142 if (strcmp(tokens[6], "cir")) { 2143 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 2144 return; 2145 } 2146 2147 if (parser_read_uint64(¶ms.cir, tokens[7])) { 2148 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 2149 return; 2150 } 2151 2152 if (strcmp(tokens[8], "pir")) { 2153 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 2154 return; 2155 } 2156 2157 if (parser_read_uint64(¶ms.pir, tokens[9])) { 2158 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 2159 return; 2160 } 2161 2162 if (strcmp(tokens[10], "cbs")) { 2163 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 2164 return; 2165 } 2166 2167 if (parser_read_uint64(¶ms.cbs, tokens[11])) { 2168 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 2169 return; 2170 } 2171 2172 if (strcmp(tokens[12], "pbs")) { 2173 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 2174 return; 2175 } 2176 2177 if (parser_read_uint64(¶ms.pbs, tokens[13])) { 2178 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 2179 return; 2180 } 2181 2182 status = rte_swx_ctl_meter_profile_add(p->p, profile_name, ¶ms); 2183 if (status) { 2184 snprintf(out, out_size, "Command failed.\n"); 2185 return; 2186 } 2187 } 2188 2189 static const char cmd_pipeline_meter_profile_delete_help[] = 2190 "pipeline <pipeline_name> meter profile <profile_name> delete\n"; 2191 2192 static void 2193 cmd_pipeline_meter_profile_delete(char **tokens, 2194 uint32_t n_tokens, 2195 char *out, 2196 size_t out_size, 2197 void *obj) 2198 { 2199 struct pipeline *p; 2200 const char *profile_name; 2201 int status; 2202 2203 if (n_tokens != 6) { 2204 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2205 return; 2206 } 2207 2208 p = pipeline_find(obj, tokens[1]); 2209 if (!p || !p->ctl) { 2210 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2211 return; 2212 } 2213 2214 if (strcmp(tokens[2], "meter")) { 2215 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2216 return; 2217 } 2218 2219 if (strcmp(tokens[3], "profile")) { 2220 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2221 return; 2222 } 2223 2224 profile_name = tokens[4]; 2225 2226 if (strcmp(tokens[5], "delete")) { 2227 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 2228 return; 2229 } 2230 2231 status = rte_swx_ctl_meter_profile_delete(p->p, profile_name); 2232 if (status) { 2233 snprintf(out, out_size, "Command failed.\n"); 2234 return; 2235 } 2236 } 2237 2238 static const char cmd_pipeline_meter_reset_help[] = 2239 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2240 "reset\n"; 2241 2242 static void 2243 cmd_pipeline_meter_reset(char **tokens, 2244 uint32_t n_tokens, 2245 char *out, 2246 size_t out_size, 2247 void *obj) 2248 { 2249 struct pipeline *p; 2250 const char *name; 2251 uint32_t idx0 = 0, idx1 = 0; 2252 2253 if (n_tokens != 9) { 2254 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2255 return; 2256 } 2257 2258 p = pipeline_find(obj, tokens[1]); 2259 if (!p || !p->ctl) { 2260 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2261 return; 2262 } 2263 2264 if (strcmp(tokens[2], "meter")) { 2265 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2266 return; 2267 } 2268 2269 name = tokens[3]; 2270 2271 if (strcmp(tokens[4], "from")) { 2272 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2273 return; 2274 } 2275 2276 if (parser_read_uint32(&idx0, tokens[5])) { 2277 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2278 return; 2279 } 2280 2281 if (strcmp(tokens[6], "to")) { 2282 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2283 return; 2284 } 2285 2286 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2287 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2288 return; 2289 } 2290 2291 if (strcmp(tokens[8], "reset")) { 2292 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); 2293 return; 2294 } 2295 2296 for ( ; idx0 <= idx1; idx0++) { 2297 int status; 2298 2299 status = rte_swx_ctl_meter_reset(p->p, name, idx0); 2300 if (status) { 2301 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2302 return; 2303 } 2304 } 2305 } 2306 2307 static const char cmd_pipeline_meter_set_help[] = 2308 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2309 "set profile <profile_name>\n"; 2310 2311 static void 2312 cmd_pipeline_meter_set(char **tokens, 2313 uint32_t n_tokens, 2314 char *out, 2315 size_t out_size, 2316 void *obj) 2317 { 2318 struct pipeline *p; 2319 const char *name, *profile_name; 2320 uint32_t idx0 = 0, idx1 = 0; 2321 2322 if (n_tokens != 11) { 2323 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2324 return; 2325 } 2326 2327 p = pipeline_find(obj, tokens[1]); 2328 if (!p || !p->ctl) { 2329 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2330 return; 2331 } 2332 2333 if (strcmp(tokens[2], "meter")) { 2334 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2335 return; 2336 } 2337 2338 name = tokens[3]; 2339 2340 if (strcmp(tokens[4], "from")) { 2341 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2342 return; 2343 } 2344 2345 if (parser_read_uint32(&idx0, tokens[5])) { 2346 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2347 return; 2348 } 2349 2350 if (strcmp(tokens[6], "to")) { 2351 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2352 return; 2353 } 2354 2355 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2356 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2357 return; 2358 } 2359 2360 if (strcmp(tokens[8], "set")) { 2361 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); 2362 return; 2363 } 2364 2365 if (strcmp(tokens[9], "profile")) { 2366 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 2367 return; 2368 } 2369 2370 profile_name = tokens[10]; 2371 2372 for ( ; idx0 <= idx1; idx0++) { 2373 int status; 2374 2375 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name); 2376 if (status) { 2377 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 2378 return; 2379 } 2380 } 2381 } 2382 2383 static const char cmd_pipeline_meter_stats_help[] = 2384 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 2385 "stats\n"; 2386 2387 static void 2388 cmd_pipeline_meter_stats(char **tokens, 2389 uint32_t n_tokens, 2390 char *out, 2391 size_t out_size, 2392 void *obj) 2393 { 2394 struct rte_swx_ctl_meter_stats stats; 2395 struct pipeline *p; 2396 const char *name; 2397 uint32_t idx0 = 0, idx1 = 0; 2398 2399 if (n_tokens != 9) { 2400 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2401 return; 2402 } 2403 2404 p = pipeline_find(obj, tokens[1]); 2405 if (!p || !p->ctl) { 2406 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2407 return; 2408 } 2409 2410 if (strcmp(tokens[2], "meter")) { 2411 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 2412 return; 2413 } 2414 2415 name = tokens[3]; 2416 2417 if (strcmp(tokens[4], "from")) { 2418 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 2419 return; 2420 } 2421 2422 if (parser_read_uint32(&idx0, tokens[5])) { 2423 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 2424 return; 2425 } 2426 2427 if (strcmp(tokens[6], "to")) { 2428 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 2429 return; 2430 } 2431 2432 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 2433 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 2434 return; 2435 } 2436 2437 if (strcmp(tokens[8], "stats")) { 2438 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2439 return; 2440 } 2441 2442 /* Table header. */ 2443 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2444 "-------", 2445 "----------------", "----------------", "----------------", 2446 "----------------", "----------------", "----------------"); 2447 out_size -= strlen(out); 2448 out += strlen(out); 2449 2450 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 2451 "METER #", 2452 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 2453 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 2454 out_size -= strlen(out); 2455 out += strlen(out); 2456 2457 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 2458 "-------", 2459 "----------------", "----------------", "----------------", 2460 "----------------", "----------------", "----------------"); 2461 out_size -= strlen(out); 2462 out += strlen(out); 2463 2464 /* Table rows. */ 2465 for ( ; idx0 <= idx1; idx0++) { 2466 int status; 2467 2468 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats); 2469 if (status) { 2470 snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0); 2471 out_size -= strlen(out); 2472 out += strlen(out); 2473 return; 2474 } 2475 2476 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 2477 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 2478 idx0, 2479 stats.n_pkts[RTE_COLOR_GREEN], 2480 stats.n_pkts[RTE_COLOR_YELLOW], 2481 stats.n_pkts[RTE_COLOR_RED], 2482 stats.n_bytes[RTE_COLOR_GREEN], 2483 stats.n_bytes[RTE_COLOR_YELLOW], 2484 stats.n_bytes[RTE_COLOR_RED]); 2485 out_size -= strlen(out); 2486 out += strlen(out); 2487 } 2488 } 2489 2490 static const char cmd_pipeline_stats_help[] = 2491 "pipeline <pipeline_name> stats\n"; 2492 2493 static void 2494 cmd_pipeline_stats(char **tokens, 2495 uint32_t n_tokens, 2496 char *out, 2497 size_t out_size, 2498 void *obj) 2499 { 2500 struct rte_swx_ctl_pipeline_info info; 2501 struct pipeline *p; 2502 uint32_t i; 2503 int status; 2504 2505 if (n_tokens != 3) { 2506 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2507 return; 2508 } 2509 2510 p = pipeline_find(obj, tokens[1]); 2511 if (!p || !p->ctl) { 2512 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2513 return; 2514 } 2515 2516 if (strcmp(tokens[2], "stats")) { 2517 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2518 return; 2519 } 2520 2521 status = rte_swx_ctl_pipeline_info_get(p->p, &info); 2522 if (status) { 2523 snprintf(out, out_size, "Pipeline info get error."); 2524 return; 2525 } 2526 2527 snprintf(out, out_size, "Input ports:\n"); 2528 out_size -= strlen(out); 2529 out += strlen(out); 2530 2531 for (i = 0; i < info.n_ports_in; i++) { 2532 struct rte_swx_port_in_stats stats; 2533 2534 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats); 2535 2536 snprintf(out, out_size, "\tPort %u:" 2537 " packets %" PRIu64 2538 " bytes %" PRIu64 2539 " empty %" PRIu64 "\n", 2540 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 2541 out_size -= strlen(out); 2542 out += strlen(out); 2543 } 2544 2545 snprintf(out, out_size, "\nOutput ports:\n"); 2546 out_size -= strlen(out); 2547 out += strlen(out); 2548 2549 for (i = 0; i < info.n_ports_out; i++) { 2550 struct rte_swx_port_out_stats stats; 2551 2552 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); 2553 2554 snprintf(out, out_size, "\tPort %u:" 2555 " packets %" PRIu64 2556 " bytes %" PRIu64 "\n", 2557 i, stats.n_pkts, stats.n_bytes); 2558 out_size -= strlen(out); 2559 out += strlen(out); 2560 } 2561 2562 snprintf(out, out_size, "\nTables:\n"); 2563 out_size -= strlen(out); 2564 out += strlen(out); 2565 2566 for (i = 0; i < info.n_tables; i++) { 2567 struct rte_swx_ctl_table_info table_info; 2568 uint64_t n_pkts_action[info.n_actions]; 2569 struct rte_swx_table_stats stats = { 2570 .n_pkts_hit = 0, 2571 .n_pkts_miss = 0, 2572 .n_pkts_action = n_pkts_action, 2573 }; 2574 uint32_t j; 2575 2576 status = rte_swx_ctl_table_info_get(p->p, i, &table_info); 2577 if (status) { 2578 snprintf(out, out_size, "Table info get error."); 2579 return; 2580 } 2581 2582 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats); 2583 if (status) { 2584 snprintf(out, out_size, "Table stats read error."); 2585 return; 2586 } 2587 2588 snprintf(out, out_size, "\tTable %s:\n" 2589 "\t\tHit (packets): %" PRIu64 "\n" 2590 "\t\tMiss (packets): %" PRIu64 "\n", 2591 table_info.name, 2592 stats.n_pkts_hit, 2593 stats.n_pkts_miss); 2594 out_size -= strlen(out); 2595 out += strlen(out); 2596 2597 for (j = 0; j < info.n_actions; j++) { 2598 struct rte_swx_ctl_action_info action_info; 2599 2600 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 2601 if (status) { 2602 snprintf(out, out_size, "Action info get error."); 2603 return; 2604 } 2605 2606 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2607 action_info.name, 2608 stats.n_pkts_action[j]); 2609 out_size -= strlen(out); 2610 out += strlen(out); 2611 } 2612 } 2613 2614 snprintf(out, out_size, "\nLearner tables:\n"); 2615 out_size -= strlen(out); 2616 out += strlen(out); 2617 2618 for (i = 0; i < info.n_learners; i++) { 2619 struct rte_swx_ctl_learner_info learner_info; 2620 uint64_t n_pkts_action[info.n_actions]; 2621 struct rte_swx_learner_stats stats = { 2622 .n_pkts_hit = 0, 2623 .n_pkts_miss = 0, 2624 .n_pkts_action = n_pkts_action, 2625 }; 2626 uint32_t j; 2627 2628 status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info); 2629 if (status) { 2630 snprintf(out, out_size, "Learner table info get error."); 2631 return; 2632 } 2633 2634 status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats); 2635 if (status) { 2636 snprintf(out, out_size, "Learner table stats read error."); 2637 return; 2638 } 2639 2640 snprintf(out, out_size, "\tLearner table %s:\n" 2641 "\t\tHit (packets): %" PRIu64 "\n" 2642 "\t\tMiss (packets): %" PRIu64 "\n" 2643 "\t\tLearn OK (packets): %" PRIu64 "\n" 2644 "\t\tLearn error (packets): %" PRIu64 "\n" 2645 "\t\tForget (packets): %" PRIu64 "\n", 2646 learner_info.name, 2647 stats.n_pkts_hit, 2648 stats.n_pkts_miss, 2649 stats.n_pkts_learn_ok, 2650 stats.n_pkts_learn_err, 2651 stats.n_pkts_forget); 2652 out_size -= strlen(out); 2653 out += strlen(out); 2654 2655 for (j = 0; j < info.n_actions; j++) { 2656 struct rte_swx_ctl_action_info action_info; 2657 2658 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 2659 if (status) { 2660 snprintf(out, out_size, "Action info get error."); 2661 return; 2662 } 2663 2664 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 2665 action_info.name, 2666 stats.n_pkts_action[j]); 2667 out_size -= strlen(out); 2668 out += strlen(out); 2669 } 2670 } 2671 } 2672 2673 static const char cmd_thread_pipeline_enable_help[] = 2674 "thread <thread_id> pipeline <pipeline_name> enable\n"; 2675 2676 static void 2677 cmd_thread_pipeline_enable(char **tokens, 2678 uint32_t n_tokens, 2679 char *out, 2680 size_t out_size, 2681 void *obj) 2682 { 2683 char *pipeline_name; 2684 struct pipeline *p; 2685 uint32_t thread_id; 2686 int status; 2687 2688 if (n_tokens != 5) { 2689 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2690 return; 2691 } 2692 2693 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2694 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2695 return; 2696 } 2697 2698 if (strcmp(tokens[2], "pipeline") != 0) { 2699 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2700 return; 2701 } 2702 2703 pipeline_name = tokens[3]; 2704 p = pipeline_find(obj, pipeline_name); 2705 if (!p || !p->ctl) { 2706 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2707 return; 2708 } 2709 2710 if (strcmp(tokens[4], "enable") != 0) { 2711 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2712 return; 2713 } 2714 2715 status = thread_pipeline_enable(thread_id, obj, pipeline_name); 2716 if (status) { 2717 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 2718 return; 2719 } 2720 } 2721 2722 static const char cmd_thread_pipeline_disable_help[] = 2723 "thread <thread_id> pipeline <pipeline_name> disable\n"; 2724 2725 static void 2726 cmd_thread_pipeline_disable(char **tokens, 2727 uint32_t n_tokens, 2728 char *out, 2729 size_t out_size, 2730 void *obj) 2731 { 2732 struct pipeline *p; 2733 char *pipeline_name; 2734 uint32_t thread_id; 2735 int status; 2736 2737 if (n_tokens != 5) { 2738 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2739 return; 2740 } 2741 2742 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 2743 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 2744 return; 2745 } 2746 2747 if (strcmp(tokens[2], "pipeline") != 0) { 2748 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 2749 return; 2750 } 2751 2752 pipeline_name = tokens[3]; 2753 p = pipeline_find(obj, pipeline_name); 2754 if (!p || !p->ctl) { 2755 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 2756 return; 2757 } 2758 2759 if (strcmp(tokens[4], "disable") != 0) { 2760 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2761 return; 2762 } 2763 2764 status = thread_pipeline_disable(thread_id, obj, pipeline_name); 2765 if (status) { 2766 snprintf(out, out_size, MSG_CMD_FAIL, 2767 "thread pipeline disable"); 2768 return; 2769 } 2770 } 2771 2772 static void 2773 cmd_help(char **tokens, 2774 uint32_t n_tokens, 2775 char *out, 2776 size_t out_size, 2777 void *arg __rte_unused) 2778 { 2779 tokens++; 2780 n_tokens--; 2781 2782 if (n_tokens == 0) { 2783 snprintf(out, out_size, 2784 "Type 'help <command>' for command details.\n\n" 2785 "List of commands:\n" 2786 "\tmempool\n" 2787 "\tlink\n" 2788 "\ttap\n" 2789 "\tpipeline create\n" 2790 "\tpipeline port in\n" 2791 "\tpipeline port out\n" 2792 "\tpipeline build\n" 2793 "\tpipeline table add\n" 2794 "\tpipeline table delete\n" 2795 "\tpipeline table default\n" 2796 "\tpipeline table show\n" 2797 "\tpipeline selector group add\n" 2798 "\tpipeline selector group delete\n" 2799 "\tpipeline selector group member add\n" 2800 "\tpipeline selector group member delete\n" 2801 "\tpipeline selector show\n" 2802 "\tpipeline learner default\n" 2803 "\tpipeline commit\n" 2804 "\tpipeline abort\n" 2805 "\tpipeline regrd\n" 2806 "\tpipeline regwr\n" 2807 "\tpipeline meter profile add\n" 2808 "\tpipeline meter profile delete\n" 2809 "\tpipeline meter reset\n" 2810 "\tpipeline meter set\n" 2811 "\tpipeline meter stats\n" 2812 "\tpipeline stats\n" 2813 "\tthread pipeline enable\n" 2814 "\tthread pipeline disable\n\n"); 2815 return; 2816 } 2817 2818 if (strcmp(tokens[0], "mempool") == 0) { 2819 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 2820 return; 2821 } 2822 2823 if (strcmp(tokens[0], "link") == 0) { 2824 snprintf(out, out_size, "\n%s\n", cmd_link_help); 2825 return; 2826 } 2827 2828 if (strcmp(tokens[0], "ring") == 0) { 2829 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 2830 return; 2831 } 2832 2833 if (strcmp(tokens[0], "tap") == 0) { 2834 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 2835 return; 2836 } 2837 2838 if ((strcmp(tokens[0], "pipeline") == 0) && 2839 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { 2840 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); 2841 return; 2842 } 2843 2844 if ((strcmp(tokens[0], "pipeline") == 0) && 2845 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { 2846 if (strcmp(tokens[2], "in") == 0) { 2847 snprintf(out, out_size, "\n%s\n", 2848 cmd_pipeline_port_in_help); 2849 return; 2850 } 2851 2852 if (strcmp(tokens[2], "out") == 0) { 2853 snprintf(out, out_size, "\n%s\n", 2854 cmd_pipeline_port_out_help); 2855 return; 2856 } 2857 } 2858 2859 if ((strcmp(tokens[0], "pipeline") == 0) && 2860 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 2861 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 2862 return; 2863 } 2864 2865 if ((strcmp(tokens[0], "pipeline") == 0) && 2866 (n_tokens == 3) && 2867 (strcmp(tokens[1], "table") == 0) && 2868 (strcmp(tokens[2], "add") == 0)) { 2869 snprintf(out, out_size, "\n%s\n", 2870 cmd_pipeline_table_add_help); 2871 return; 2872 } 2873 2874 if ((strcmp(tokens[0], "pipeline") == 0) && 2875 (n_tokens == 3) && 2876 (strcmp(tokens[1], "table") == 0) && 2877 (strcmp(tokens[2], "delete") == 0)) { 2878 snprintf(out, out_size, "\n%s\n", 2879 cmd_pipeline_table_delete_help); 2880 return; 2881 } 2882 2883 if ((strcmp(tokens[0], "pipeline") == 0) && 2884 (n_tokens == 3) && 2885 (strcmp(tokens[1], "table") == 0) && 2886 (strcmp(tokens[2], "default") == 0)) { 2887 snprintf(out, out_size, "\n%s\n", 2888 cmd_pipeline_table_default_help); 2889 return; 2890 } 2891 2892 if ((strcmp(tokens[0], "pipeline") == 0) && 2893 (n_tokens == 3) && 2894 (strcmp(tokens[1], "table") == 0) && 2895 (strcmp(tokens[2], "show") == 0)) { 2896 snprintf(out, out_size, "\n%s\n", 2897 cmd_pipeline_table_show_help); 2898 return; 2899 } 2900 2901 if ((strcmp(tokens[0], "pipeline") == 0) && 2902 (n_tokens == 4) && 2903 (strcmp(tokens[1], "selector") == 0) && 2904 (strcmp(tokens[2], "group") == 0) && 2905 (strcmp(tokens[3], "add") == 0)) { 2906 snprintf(out, out_size, "\n%s\n", 2907 cmd_pipeline_selector_group_add_help); 2908 return; 2909 } 2910 2911 if ((strcmp(tokens[0], "pipeline") == 0) && 2912 (n_tokens == 4) && 2913 (strcmp(tokens[1], "selector") == 0) && 2914 (strcmp(tokens[2], "group") == 0) && 2915 (strcmp(tokens[3], "delete") == 0)) { 2916 snprintf(out, out_size, "\n%s\n", 2917 cmd_pipeline_selector_group_delete_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], "add") == 0)) { 2927 snprintf(out, out_size, "\n%s\n", 2928 cmd_pipeline_selector_group_member_add_help); 2929 return; 2930 } 2931 2932 if ((strcmp(tokens[0], "pipeline") == 0) && 2933 (n_tokens == 5) && 2934 (strcmp(tokens[1], "selector") == 0) && 2935 (strcmp(tokens[2], "group") == 0) && 2936 (strcmp(tokens[3], "member") == 0) && 2937 (strcmp(tokens[4], "delete") == 0)) { 2938 snprintf(out, out_size, "\n%s\n", 2939 cmd_pipeline_selector_group_member_delete_help); 2940 return; 2941 } 2942 2943 if ((strcmp(tokens[0], "pipeline") == 0) && 2944 (n_tokens == 3) && 2945 (strcmp(tokens[1], "selector") == 0) && 2946 (strcmp(tokens[2], "show") == 0)) { 2947 snprintf(out, out_size, "\n%s\n", 2948 cmd_pipeline_selector_show_help); 2949 return; 2950 } 2951 2952 if ((strcmp(tokens[0], "pipeline") == 0) && 2953 (n_tokens == 3) && 2954 (strcmp(tokens[1], "learner") == 0) && 2955 (strcmp(tokens[2], "default") == 0)) { 2956 snprintf(out, out_size, "\n%s\n", 2957 cmd_pipeline_learner_default_help); 2958 return; 2959 } 2960 2961 if ((strcmp(tokens[0], "pipeline") == 0) && 2962 (n_tokens == 2) && 2963 (strcmp(tokens[1], "commit") == 0)) { 2964 snprintf(out, out_size, "\n%s\n", 2965 cmd_pipeline_commit_help); 2966 return; 2967 } 2968 2969 if ((strcmp(tokens[0], "pipeline") == 0) && 2970 (n_tokens == 2) && 2971 (strcmp(tokens[1], "abort") == 0)) { 2972 snprintf(out, out_size, "\n%s\n", 2973 cmd_pipeline_abort_help); 2974 return; 2975 } 2976 2977 if ((strcmp(tokens[0], "pipeline") == 0) && 2978 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 2979 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 2980 return; 2981 } 2982 2983 if ((strcmp(tokens[0], "pipeline") == 0) && 2984 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 2985 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 2986 return; 2987 } 2988 2989 if (!strcmp(tokens[0], "pipeline") && 2990 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2991 && !strcmp(tokens[2], "profile") 2992 && !strcmp(tokens[3], "add")) { 2993 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 2994 return; 2995 } 2996 2997 if (!strcmp(tokens[0], "pipeline") && 2998 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2999 && !strcmp(tokens[2], "profile") 3000 && !strcmp(tokens[3], "delete")) { 3001 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 3002 return; 3003 } 3004 3005 if (!strcmp(tokens[0], "pipeline") && 3006 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3007 && !strcmp(tokens[2], "reset")) { 3008 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 3009 return; 3010 } 3011 3012 if (!strcmp(tokens[0], "pipeline") && 3013 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3014 && !strcmp(tokens[2], "set")) { 3015 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 3016 return; 3017 } 3018 3019 if (!strcmp(tokens[0], "pipeline") && 3020 (n_tokens == 3) && !strcmp(tokens[1], "meter") 3021 && !strcmp(tokens[2], "stats")) { 3022 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 3023 return; 3024 } 3025 3026 if ((strcmp(tokens[0], "pipeline") == 0) && 3027 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 3028 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 3029 return; 3030 } 3031 3032 if ((n_tokens == 3) && 3033 (strcmp(tokens[0], "thread") == 0) && 3034 (strcmp(tokens[1], "pipeline") == 0)) { 3035 if (strcmp(tokens[2], "enable") == 0) { 3036 snprintf(out, out_size, "\n%s\n", 3037 cmd_thread_pipeline_enable_help); 3038 return; 3039 } 3040 3041 if (strcmp(tokens[2], "disable") == 0) { 3042 snprintf(out, out_size, "\n%s\n", 3043 cmd_thread_pipeline_disable_help); 3044 return; 3045 } 3046 } 3047 3048 snprintf(out, out_size, "Invalid command\n"); 3049 } 3050 3051 void 3052 cli_process(char *in, char *out, size_t out_size, void *obj) 3053 { 3054 char *tokens[CMD_MAX_TOKENS]; 3055 uint32_t n_tokens = RTE_DIM(tokens); 3056 int status; 3057 3058 if (is_comment(in)) 3059 return; 3060 3061 status = parse_tokenize_string(in, tokens, &n_tokens); 3062 if (status) { 3063 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 3064 return; 3065 } 3066 3067 if (n_tokens == 0) 3068 return; 3069 3070 if (strcmp(tokens[0], "help") == 0) { 3071 cmd_help(tokens, n_tokens, out, out_size, obj); 3072 return; 3073 } 3074 3075 if (strcmp(tokens[0], "mempool") == 0) { 3076 cmd_mempool(tokens, n_tokens, out, out_size, obj); 3077 return; 3078 } 3079 3080 if (strcmp(tokens[0], "link") == 0) { 3081 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 3082 cmd_link_show(tokens, n_tokens, out, out_size, obj); 3083 return; 3084 } 3085 3086 cmd_link(tokens, n_tokens, out, out_size, obj); 3087 return; 3088 } 3089 3090 if (strcmp(tokens[0], "ring") == 0) { 3091 cmd_ring(tokens, n_tokens, out, out_size, obj); 3092 return; 3093 } 3094 3095 if (strcmp(tokens[0], "tap") == 0) { 3096 cmd_tap(tokens, n_tokens, out, out_size, obj); 3097 return; 3098 } 3099 3100 if (strcmp(tokens[0], "pipeline") == 0) { 3101 if ((n_tokens >= 3) && 3102 (strcmp(tokens[2], "create") == 0)) { 3103 cmd_pipeline_create(tokens, n_tokens, out, out_size, 3104 obj); 3105 return; 3106 } 3107 3108 if ((n_tokens >= 4) && 3109 (strcmp(tokens[2], "port") == 0) && 3110 (strcmp(tokens[3], "in") == 0)) { 3111 cmd_pipeline_port_in(tokens, n_tokens, out, out_size, 3112 obj); 3113 return; 3114 } 3115 3116 if ((n_tokens >= 4) && 3117 (strcmp(tokens[2], "port") == 0) && 3118 (strcmp(tokens[3], "out") == 0)) { 3119 cmd_pipeline_port_out(tokens, n_tokens, out, out_size, 3120 obj); 3121 return; 3122 } 3123 3124 if ((n_tokens >= 3) && 3125 (strcmp(tokens[2], "build") == 0)) { 3126 cmd_pipeline_build(tokens, n_tokens, out, out_size, 3127 obj); 3128 return; 3129 } 3130 3131 if ((n_tokens >= 5) && 3132 (strcmp(tokens[2], "table") == 0) && 3133 (strcmp(tokens[4], "add") == 0)) { 3134 cmd_pipeline_table_add(tokens, n_tokens, out, 3135 out_size, obj); 3136 return; 3137 } 3138 3139 if ((n_tokens >= 5) && 3140 (strcmp(tokens[2], "table") == 0) && 3141 (strcmp(tokens[4], "delete") == 0)) { 3142 cmd_pipeline_table_delete(tokens, n_tokens, out, 3143 out_size, obj); 3144 return; 3145 } 3146 3147 if ((n_tokens >= 5) && 3148 (strcmp(tokens[2], "table") == 0) && 3149 (strcmp(tokens[4], "default") == 0)) { 3150 cmd_pipeline_table_default(tokens, n_tokens, out, 3151 out_size, obj); 3152 return; 3153 } 3154 3155 if ((n_tokens >= 5) && 3156 (strcmp(tokens[2], "table") == 0) && 3157 (strcmp(tokens[4], "show") == 0)) { 3158 cmd_pipeline_table_show(tokens, n_tokens, out, 3159 out_size, obj); 3160 return; 3161 } 3162 3163 if ((n_tokens >= 6) && 3164 (strcmp(tokens[2], "selector") == 0) && 3165 (strcmp(tokens[4], "group") == 0) && 3166 (strcmp(tokens[5], "add") == 0)) { 3167 cmd_pipeline_selector_group_add(tokens, n_tokens, out, 3168 out_size, obj); 3169 return; 3170 } 3171 3172 if ((n_tokens >= 6) && 3173 (strcmp(tokens[2], "selector") == 0) && 3174 (strcmp(tokens[4], "group") == 0) && 3175 (strcmp(tokens[5], "delete") == 0)) { 3176 cmd_pipeline_selector_group_delete(tokens, n_tokens, out, 3177 out_size, obj); 3178 return; 3179 } 3180 3181 if ((n_tokens >= 7) && 3182 (strcmp(tokens[2], "selector") == 0) && 3183 (strcmp(tokens[4], "group") == 0) && 3184 (strcmp(tokens[5], "member") == 0) && 3185 (strcmp(tokens[6], "add") == 0)) { 3186 cmd_pipeline_selector_group_member_add(tokens, n_tokens, out, 3187 out_size, obj); 3188 return; 3189 } 3190 3191 if ((n_tokens >= 7) && 3192 (strcmp(tokens[2], "selector") == 0) && 3193 (strcmp(tokens[4], "group") == 0) && 3194 (strcmp(tokens[5], "member") == 0) && 3195 (strcmp(tokens[6], "delete") == 0)) { 3196 cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out, 3197 out_size, obj); 3198 return; 3199 } 3200 3201 if ((n_tokens >= 5) && 3202 (strcmp(tokens[2], "selector") == 0) && 3203 (strcmp(tokens[4], "show") == 0)) { 3204 cmd_pipeline_selector_show(tokens, n_tokens, out, 3205 out_size, obj); 3206 return; 3207 } 3208 3209 if ((n_tokens >= 5) && 3210 (strcmp(tokens[2], "learner") == 0) && 3211 (strcmp(tokens[4], "default") == 0)) { 3212 cmd_pipeline_learner_default(tokens, n_tokens, out, 3213 out_size, obj); 3214 return; 3215 } 3216 3217 if ((n_tokens >= 3) && 3218 (strcmp(tokens[2], "commit") == 0)) { 3219 cmd_pipeline_commit(tokens, n_tokens, out, 3220 out_size, obj); 3221 return; 3222 } 3223 3224 if ((n_tokens >= 3) && 3225 (strcmp(tokens[2], "abort") == 0)) { 3226 cmd_pipeline_abort(tokens, n_tokens, out, 3227 out_size, obj); 3228 return; 3229 } 3230 3231 if ((n_tokens >= 3) && 3232 (strcmp(tokens[2], "regrd") == 0)) { 3233 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 3234 return; 3235 } 3236 3237 if ((n_tokens >= 3) && 3238 (strcmp(tokens[2], "regwr") == 0)) { 3239 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 3240 return; 3241 } 3242 3243 if ((n_tokens >= 6) && 3244 (strcmp(tokens[2], "meter") == 0) && 3245 (strcmp(tokens[3], "profile") == 0) && 3246 (strcmp(tokens[5], "add") == 0)) { 3247 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 3248 return; 3249 } 3250 3251 if ((n_tokens >= 6) && 3252 (strcmp(tokens[2], "meter") == 0) && 3253 (strcmp(tokens[3], "profile") == 0) && 3254 (strcmp(tokens[5], "delete") == 0)) { 3255 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 3256 return; 3257 } 3258 3259 if ((n_tokens >= 9) && 3260 (strcmp(tokens[2], "meter") == 0) && 3261 (strcmp(tokens[8], "reset") == 0)) { 3262 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 3263 return; 3264 } 3265 3266 if ((n_tokens >= 9) && 3267 (strcmp(tokens[2], "meter") == 0) && 3268 (strcmp(tokens[8], "set") == 0)) { 3269 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 3270 return; 3271 } 3272 3273 if ((n_tokens >= 9) && 3274 (strcmp(tokens[2], "meter") == 0) && 3275 (strcmp(tokens[8], "stats") == 0)) { 3276 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 3277 return; 3278 } 3279 3280 if ((n_tokens >= 3) && 3281 (strcmp(tokens[2], "stats") == 0)) { 3282 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 3283 obj); 3284 return; 3285 } 3286 } 3287 3288 if (strcmp(tokens[0], "thread") == 0) { 3289 if ((n_tokens >= 5) && 3290 (strcmp(tokens[4], "enable") == 0)) { 3291 cmd_thread_pipeline_enable(tokens, n_tokens, 3292 out, out_size, obj); 3293 return; 3294 } 3295 3296 if ((n_tokens >= 5) && 3297 (strcmp(tokens[4], "disable") == 0)) { 3298 cmd_thread_pipeline_disable(tokens, n_tokens, 3299 out, out_size, obj); 3300 return; 3301 } 3302 } 3303 3304 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 3305 } 3306 3307 int 3308 cli_script_process(const char *file_name, 3309 size_t msg_in_len_max, 3310 size_t msg_out_len_max, 3311 void *obj) 3312 { 3313 char *msg_in = NULL, *msg_out = NULL; 3314 FILE *f = NULL; 3315 3316 /* Check input arguments */ 3317 if ((file_name == NULL) || 3318 (strlen(file_name) == 0) || 3319 (msg_in_len_max == 0) || 3320 (msg_out_len_max == 0)) 3321 return -EINVAL; 3322 3323 msg_in = malloc(msg_in_len_max + 1); 3324 msg_out = malloc(msg_out_len_max + 1); 3325 if ((msg_in == NULL) || 3326 (msg_out == NULL)) { 3327 free(msg_out); 3328 free(msg_in); 3329 return -ENOMEM; 3330 } 3331 3332 /* Open input file */ 3333 f = fopen(file_name, "r"); 3334 if (f == NULL) { 3335 free(msg_out); 3336 free(msg_in); 3337 return -EIO; 3338 } 3339 3340 /* Read file */ 3341 for ( ; ; ) { 3342 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 3343 break; 3344 3345 printf("%s", msg_in); 3346 msg_out[0] = 0; 3347 3348 cli_process(msg_in, 3349 msg_out, 3350 msg_out_len_max, 3351 obj); 3352 3353 if (strlen(msg_out)) 3354 printf("%s", msg_out); 3355 } 3356 3357 /* Close file */ 3358 fclose(f); 3359 free(msg_out); 3360 free(msg_in); 3361 return 0; 3362 } 3363