1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include <rte_common.h> 11 #include <rte_ethdev.h> 12 #include <rte_swx_port_ethdev.h> 13 #include <rte_swx_port_ring.h> 14 #include <rte_swx_port_source_sink.h> 15 #include <rte_swx_port_fd.h> 16 #include <rte_swx_pipeline.h> 17 #include <rte_swx_ctl.h> 18 19 #include "cli.h" 20 21 #include "obj.h" 22 #include "thread.h" 23 24 #ifndef CMD_MAX_TOKENS 25 #define CMD_MAX_TOKENS 256 26 #endif 27 28 #define MSG_OUT_OF_MEMORY "Not enough memory.\n" 29 #define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n" 30 #define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n" 31 #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n" 32 #define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n" 33 #define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\".\n" 34 #define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n" 35 #define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n" 36 #define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n" 37 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n" 38 #define MSG_CMD_FAIL "Command \"%s\" failed.\n" 39 40 #define skip_white_spaces(pos) \ 41 ({ \ 42 __typeof__(pos) _p = (pos); \ 43 for ( ; isspace(*_p); _p++) \ 44 ; \ 45 _p; \ 46 }) 47 48 static int 49 parser_read_uint64(uint64_t *value, const char *p) 50 { 51 char *next; 52 uint64_t val; 53 54 p = skip_white_spaces(p); 55 if (!isdigit(*p)) 56 return -EINVAL; 57 58 val = strtoul(p, &next, 0); 59 if (p == next) 60 return -EINVAL; 61 62 p = next; 63 switch (*p) { 64 case 'T': 65 val *= 1024ULL; 66 /* fall through */ 67 case 'G': 68 val *= 1024ULL; 69 /* fall through */ 70 case 'M': 71 val *= 1024ULL; 72 /* fall through */ 73 case 'k': 74 case 'K': 75 val *= 1024ULL; 76 p++; 77 break; 78 } 79 80 p = skip_white_spaces(p); 81 if (*p != '\0') 82 return -EINVAL; 83 84 *value = val; 85 return 0; 86 } 87 88 static int 89 parser_read_uint32(uint32_t *value, const char *p) 90 { 91 uint64_t val = 0; 92 int ret = parser_read_uint64(&val, p); 93 94 if (ret < 0) 95 return ret; 96 97 if (val > UINT32_MAX) 98 return -ERANGE; 99 100 *value = val; 101 return 0; 102 } 103 104 static int 105 parser_read_uint16(uint16_t *value, const char *p) 106 { 107 uint64_t val = 0; 108 int ret = parser_read_uint64(&val, p); 109 110 if (ret < 0) 111 return ret; 112 113 if (val > UINT16_MAX) 114 return -ERANGE; 115 116 *value = val; 117 return 0; 118 } 119 120 #define PARSE_DELIMITER " \f\n\r\t\v" 121 122 static int 123 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens) 124 { 125 uint32_t i; 126 127 if ((string == NULL) || 128 (tokens == NULL) || 129 (*n_tokens < 1)) 130 return -EINVAL; 131 132 for (i = 0; i < *n_tokens; i++) { 133 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string); 134 if (tokens[i] == NULL) 135 break; 136 } 137 138 if ((i == *n_tokens) && strtok_r(string, PARSE_DELIMITER, &string)) 139 return -E2BIG; 140 141 *n_tokens = i; 142 return 0; 143 } 144 145 static int 146 is_comment(char *in) 147 { 148 if ((strlen(in) && index("!#%;", in[0])) || 149 (strncmp(in, "//", 2) == 0) || 150 (strncmp(in, "--", 2) == 0)) 151 return 1; 152 153 return 0; 154 } 155 156 static const char cmd_mempool_help[] = 157 "mempool <mempool_name>\n" 158 " buffer <buffer_size>\n" 159 " pool <pool_size>\n" 160 " cache <cache_size>\n" 161 " cpu <cpu_id>\n"; 162 163 static void 164 cmd_mempool(char **tokens, 165 uint32_t n_tokens, 166 char *out, 167 size_t out_size, 168 void *obj) 169 { 170 struct mempool_params p; 171 char *name; 172 struct mempool *mempool; 173 174 if (n_tokens != 10) { 175 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 176 return; 177 } 178 179 name = tokens[1]; 180 181 if (strcmp(tokens[2], "buffer") != 0) { 182 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer"); 183 return; 184 } 185 186 if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) { 187 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size"); 188 return; 189 } 190 191 if (strcmp(tokens[4], "pool") != 0) { 192 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool"); 193 return; 194 } 195 196 if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) { 197 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size"); 198 return; 199 } 200 201 if (strcmp(tokens[6], "cache") != 0) { 202 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); 203 return; 204 } 205 206 if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) { 207 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); 208 return; 209 } 210 211 if (strcmp(tokens[8], "cpu") != 0) { 212 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 213 return; 214 } 215 216 if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) { 217 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 218 return; 219 } 220 221 mempool = mempool_create(obj, name, &p); 222 if (mempool == NULL) { 223 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 224 return; 225 } 226 } 227 228 static const char cmd_link_help[] = 229 "link <link_name>\n" 230 " dev <device_name> | port <port_id>\n" 231 " rxq <n_queues> <queue_size> <mempool_name>\n" 232 " txq <n_queues> <queue_size>\n" 233 " promiscuous on | off\n" 234 " [rss <qid_0> ... <qid_n>]\n"; 235 236 static void 237 cmd_link(char **tokens, 238 uint32_t n_tokens, 239 char *out, 240 size_t out_size, 241 void *obj) 242 { 243 struct link_params p; 244 struct link_params_rss rss; 245 struct link *link; 246 char *name; 247 248 memset(&p, 0, sizeof(p)); 249 250 if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) { 251 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 252 return; 253 } 254 name = tokens[1]; 255 256 if (strcmp(tokens[2], "dev") == 0) 257 p.dev_name = tokens[3]; 258 else if (strcmp(tokens[2], "port") == 0) { 259 p.dev_name = NULL; 260 261 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) { 262 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 263 return; 264 } 265 } else { 266 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port"); 267 return; 268 } 269 270 if (strcmp(tokens[4], "rxq") != 0) { 271 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 272 return; 273 } 274 275 if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) { 276 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 277 return; 278 } 279 if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) { 280 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 281 return; 282 } 283 284 p.rx.mempool_name = tokens[7]; 285 286 if (strcmp(tokens[8], "txq") != 0) { 287 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 288 return; 289 } 290 291 if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) { 292 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 293 return; 294 } 295 296 if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) { 297 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 298 return; 299 } 300 301 if (strcmp(tokens[11], "promiscuous") != 0) { 302 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous"); 303 return; 304 } 305 306 if (strcmp(tokens[12], "on") == 0) 307 p.promiscuous = 1; 308 else if (strcmp(tokens[12], "off") == 0) 309 p.promiscuous = 0; 310 else { 311 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off"); 312 return; 313 } 314 315 /* RSS */ 316 p.rx.rss = NULL; 317 if (n_tokens > 13) { 318 uint32_t queue_id, i; 319 320 if (strcmp(tokens[13], "rss") != 0) { 321 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss"); 322 return; 323 } 324 325 p.rx.rss = &rss; 326 327 rss.n_queues = 0; 328 for (i = 14; i < n_tokens; i++) { 329 if (parser_read_uint32(&queue_id, tokens[i]) != 0) { 330 snprintf(out, out_size, MSG_ARG_INVALID, 331 "queue_id"); 332 return; 333 } 334 335 rss.queue_id[rss.n_queues] = queue_id; 336 rss.n_queues++; 337 } 338 } 339 340 link = link_create(obj, name, &p); 341 if (link == NULL) { 342 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 343 return; 344 } 345 } 346 347 /* Print the link stats and info */ 348 static void 349 print_link_info(struct link *link, char *out, size_t out_size) 350 { 351 struct rte_eth_stats stats; 352 struct rte_ether_addr mac_addr; 353 struct rte_eth_link eth_link; 354 uint16_t mtu; 355 int ret; 356 357 memset(&stats, 0, sizeof(stats)); 358 rte_eth_stats_get(link->port_id, &stats); 359 360 ret = rte_eth_macaddr_get(link->port_id, &mac_addr); 361 if (ret != 0) { 362 snprintf(out, out_size, "\n%s: MAC address get failed: %s", 363 link->name, rte_strerror(-ret)); 364 return; 365 } 366 367 ret = rte_eth_link_get(link->port_id, ð_link); 368 if (ret < 0) { 369 snprintf(out, out_size, "\n%s: link get failed: %s", 370 link->name, rte_strerror(-ret)); 371 return; 372 } 373 374 rte_eth_dev_get_mtu(link->port_id, &mtu); 375 376 snprintf(out, out_size, 377 "\n" 378 "%s: flags=<%s> mtu %u\n" 379 "\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n" 380 "\tport# %u speed %s\n" 381 "\tRX packets %" PRIu64" bytes %" PRIu64"\n" 382 "\tRX errors %" PRIu64" missed %" PRIu64" no-mbuf %" PRIu64"\n" 383 "\tTX packets %" PRIu64" bytes %" PRIu64"\n" 384 "\tTX errors %" PRIu64"\n", 385 link->name, 386 eth_link.link_status == 0 ? "DOWN" : "UP", 387 mtu, 388 mac_addr.addr_bytes[0], mac_addr.addr_bytes[1], 389 mac_addr.addr_bytes[2], mac_addr.addr_bytes[3], 390 mac_addr.addr_bytes[4], mac_addr.addr_bytes[5], 391 link->n_rxq, 392 link->n_txq, 393 link->port_id, 394 rte_eth_link_speed_to_str(eth_link.link_speed), 395 stats.ipackets, 396 stats.ibytes, 397 stats.ierrors, 398 stats.imissed, 399 stats.rx_nombuf, 400 stats.opackets, 401 stats.obytes, 402 stats.oerrors); 403 } 404 405 /* 406 * link show [<link_name>] 407 */ 408 static void 409 cmd_link_show(char **tokens, 410 uint32_t n_tokens, 411 char *out, 412 size_t out_size, 413 void *obj) 414 { 415 struct link *link; 416 char *link_name; 417 418 if (n_tokens != 2 && n_tokens != 3) { 419 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 420 return; 421 } 422 423 if (n_tokens == 2) { 424 link = link_next(obj, NULL); 425 426 while (link != NULL) { 427 out_size = out_size - strlen(out); 428 out = &out[strlen(out)]; 429 430 print_link_info(link, out, out_size); 431 link = link_next(obj, link); 432 } 433 } else { 434 out_size = out_size - strlen(out); 435 out = &out[strlen(out)]; 436 437 link_name = tokens[2]; 438 link = link_find(obj, link_name); 439 440 if (link == NULL) { 441 snprintf(out, out_size, MSG_ARG_INVALID, 442 "Link does not exist"); 443 return; 444 } 445 print_link_info(link, out, out_size); 446 } 447 } 448 449 static const char cmd_ring_help[] = 450 "ring <ring_name> size <size> numa <numa_node>\n"; 451 452 static void 453 cmd_ring(char **tokens, 454 uint32_t n_tokens, 455 char *out, 456 size_t out_size, 457 void *obj) 458 { 459 struct ring_params p; 460 char *name; 461 struct ring *ring; 462 463 if (n_tokens != 6) { 464 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 465 return; 466 } 467 468 name = tokens[1]; 469 470 if (strcmp(tokens[2], "size") != 0) { 471 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 472 return; 473 } 474 475 if (parser_read_uint32(&p.size, tokens[3]) != 0) { 476 snprintf(out, out_size, MSG_ARG_INVALID, "size"); 477 return; 478 } 479 480 if (strcmp(tokens[4], "numa") != 0) { 481 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa"); 482 return; 483 } 484 485 if (parser_read_uint32(&p.numa_node, tokens[5]) != 0) { 486 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node"); 487 return; 488 } 489 490 ring = ring_create(obj, name, &p); 491 if (!ring) { 492 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 493 return; 494 } 495 } 496 497 static const char cmd_tap_help[] = 498 "tap <tap_name>\n"; 499 500 static void 501 cmd_tap(char **tokens, 502 uint32_t n_tokens, 503 char *out, 504 size_t out_size, 505 void *obj) 506 { 507 struct tap *tap; 508 char *name; 509 510 if (n_tokens < 2) { 511 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 512 return; 513 } 514 name = tokens[1]; 515 516 tap = tap_create(obj, name); 517 if (tap == NULL) { 518 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 519 return; 520 } 521 } 522 523 static const char cmd_pipeline_create_help[] = 524 "pipeline <pipeline_name> create <numa_node>\n"; 525 526 static void 527 cmd_pipeline_create(char **tokens, 528 uint32_t n_tokens, 529 char *out, 530 size_t out_size, 531 void *obj) 532 { 533 struct pipeline *p; 534 char *name; 535 uint32_t numa_node; 536 537 if (n_tokens != 4) { 538 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 539 return; 540 } 541 542 name = tokens[1]; 543 544 if (parser_read_uint32(&numa_node, tokens[3]) != 0) { 545 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node"); 546 return; 547 } 548 549 p = pipeline_create(obj, name, (int)numa_node); 550 if (!p) { 551 snprintf(out, out_size, "pipeline create error."); 552 return; 553 } 554 } 555 556 static const char cmd_pipeline_port_in_help[] = 557 "pipeline <pipeline_name> port in <port_id>\n" 558 " link <link_name> rxq <queue_id> bsz <burst_size>\n" 559 " ring <ring_name> bsz <burst_size>\n" 560 " | source <mempool_name> <file_name>\n" 561 " | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n"; 562 563 static void 564 cmd_pipeline_port_in(char **tokens, 565 uint32_t n_tokens, 566 char *out, 567 size_t out_size, 568 void *obj) 569 { 570 struct pipeline *p; 571 int status; 572 uint32_t port_id = 0, t0; 573 574 if (n_tokens < 6) { 575 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 576 return; 577 } 578 579 p = pipeline_find(obj, tokens[1]); 580 if (!p || p->ctl) { 581 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 582 return; 583 } 584 585 if (strcmp(tokens[2], "port") != 0) { 586 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 587 return; 588 } 589 590 if (strcmp(tokens[3], "in") != 0) { 591 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 592 return; 593 } 594 595 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 596 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 597 return; 598 } 599 600 t0 = 5; 601 602 if (strcmp(tokens[t0], "link") == 0) { 603 struct rte_swx_port_ethdev_reader_params params; 604 struct link *link; 605 606 if (n_tokens < t0 + 6) { 607 snprintf(out, out_size, MSG_ARG_MISMATCH, 608 "pipeline port in link"); 609 return; 610 } 611 612 link = link_find(obj, tokens[t0 + 1]); 613 if (!link) { 614 snprintf(out, out_size, MSG_ARG_INVALID, 615 "link_name"); 616 return; 617 } 618 params.dev_name = link->dev_name; 619 620 if (strcmp(tokens[t0 + 2], "rxq") != 0) { 621 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 622 return; 623 } 624 625 if (parser_read_uint16(¶ms.queue_id, tokens[t0 + 3]) != 0) { 626 snprintf(out, out_size, MSG_ARG_INVALID, 627 "queue_id"); 628 return; 629 } 630 631 if (strcmp(tokens[t0 + 4], "bsz") != 0) { 632 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 633 return; 634 } 635 636 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 5])) { 637 snprintf(out, out_size, MSG_ARG_INVALID, 638 "burst_size"); 639 return; 640 } 641 642 t0 += 6; 643 644 status = rte_swx_pipeline_port_in_config(p->p, 645 port_id, 646 "ethdev", 647 ¶ms); 648 } else if (strcmp(tokens[t0], "ring") == 0) { 649 struct rte_swx_port_ring_reader_params params; 650 struct ring *ring; 651 652 if (n_tokens < t0 + 4) { 653 snprintf(out, out_size, MSG_ARG_MISMATCH, 654 "pipeline port in ring"); 655 return; 656 } 657 658 ring = ring_find(obj, tokens[t0 + 1]); 659 if (!ring) { 660 snprintf(out, out_size, MSG_ARG_INVALID, 661 "ring_name"); 662 return; 663 } 664 params.name = ring->name; 665 666 if (strcmp(tokens[t0 + 2], "bsz") != 0) { 667 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 668 return; 669 } 670 671 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { 672 snprintf(out, out_size, MSG_ARG_INVALID, 673 "burst_size"); 674 return; 675 } 676 677 t0 += 4; 678 679 status = rte_swx_pipeline_port_in_config(p->p, 680 port_id, 681 "ring", 682 ¶ms); 683 } else if (strcmp(tokens[t0], "source") == 0) { 684 struct rte_swx_port_source_params params; 685 struct mempool *mp; 686 687 if (n_tokens < t0 + 3) { 688 snprintf(out, out_size, MSG_ARG_MISMATCH, 689 "pipeline port in source"); 690 return; 691 } 692 693 mp = mempool_find(obj, tokens[t0 + 1]); 694 if (!mp) { 695 snprintf(out, out_size, MSG_ARG_INVALID, 696 "mempool_name"); 697 return; 698 } 699 params.pool = mp->m; 700 701 params.file_name = tokens[t0 + 2]; 702 703 t0 += 3; 704 705 status = rte_swx_pipeline_port_in_config(p->p, 706 port_id, 707 "source", 708 ¶ms); 709 } else if (strcmp(tokens[t0], "tap") == 0) { 710 struct rte_swx_port_fd_reader_params params; 711 struct tap *tap; 712 struct mempool *mp; 713 714 if (n_tokens < t0 + 8) { 715 snprintf(out, out_size, MSG_ARG_MISMATCH, 716 "pipeline port in tap"); 717 return; 718 } 719 720 tap = tap_find(obj, tokens[t0 + 1]); 721 if (!tap) { 722 snprintf(out, out_size, MSG_ARG_INVALID, 723 "tap_name"); 724 return; 725 } 726 params.fd = tap->fd; 727 728 if (strcmp(tokens[t0 + 2], "mempool") != 0) { 729 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 730 "mempool"); 731 return; 732 } 733 734 mp = mempool_find(obj, tokens[t0 + 3]); 735 if (!mp) { 736 snprintf(out, out_size, MSG_ARG_INVALID, 737 "mempool_name"); 738 return; 739 } 740 params.mempool = mp->m; 741 742 if (strcmp(tokens[t0 + 4], "mtu") != 0) { 743 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 744 "mtu"); 745 return; 746 } 747 748 if (parser_read_uint32(¶ms.mtu, tokens[t0 + 5]) != 0) { 749 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 750 return; 751 } 752 753 if (strcmp(tokens[t0 + 6], "bsz") != 0) { 754 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 755 return; 756 } 757 758 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 7])) { 759 snprintf(out, out_size, MSG_ARG_INVALID, 760 "burst_size"); 761 return; 762 } 763 764 t0 += 8; 765 766 status = rte_swx_pipeline_port_in_config(p->p, 767 port_id, 768 "fd", 769 ¶ms); 770 771 } else { 772 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 773 return; 774 } 775 776 if (status) { 777 snprintf(out, out_size, "port in error."); 778 return; 779 } 780 781 if (n_tokens != t0) { 782 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 783 return; 784 } 785 } 786 787 static const char cmd_pipeline_port_out_help[] = 788 "pipeline <pipeline_name> port out <port_id>\n" 789 " link <link_name> txq <txq_id> bsz <burst_size>\n" 790 " ring <ring_name> bsz <burst_size>\n" 791 " | sink <file_name> | none\n" 792 " | tap <tap_name> bsz <burst_size>\n"; 793 794 static void 795 cmd_pipeline_port_out(char **tokens, 796 uint32_t n_tokens, 797 char *out, 798 size_t out_size, 799 void *obj) 800 { 801 struct pipeline *p; 802 int status; 803 uint32_t port_id = 0, t0; 804 805 if (n_tokens < 6) { 806 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 807 return; 808 } 809 810 p = pipeline_find(obj, tokens[1]); 811 if (!p || p->ctl) { 812 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 813 return; 814 } 815 816 if (strcmp(tokens[2], "port") != 0) { 817 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 818 return; 819 } 820 821 if (strcmp(tokens[3], "out") != 0) { 822 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 823 return; 824 } 825 826 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 827 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 828 return; 829 } 830 831 t0 = 5; 832 833 if (strcmp(tokens[t0], "link") == 0) { 834 struct rte_swx_port_ethdev_writer_params params; 835 struct link *link; 836 837 if (n_tokens < t0 + 6) { 838 snprintf(out, out_size, MSG_ARG_MISMATCH, 839 "pipeline port out link"); 840 return; 841 } 842 843 link = link_find(obj, tokens[t0 + 1]); 844 if (!link) { 845 snprintf(out, out_size, MSG_ARG_INVALID, 846 "link_name"); 847 return; 848 } 849 params.dev_name = link->dev_name; 850 851 if (strcmp(tokens[t0 + 2], "txq") != 0) { 852 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 853 return; 854 } 855 856 if (parser_read_uint16(¶ms.queue_id, tokens[t0 + 3]) != 0) { 857 snprintf(out, out_size, MSG_ARG_INVALID, 858 "queue_id"); 859 return; 860 } 861 862 if (strcmp(tokens[t0 + 4], "bsz") != 0) { 863 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 864 return; 865 } 866 867 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 5])) { 868 snprintf(out, out_size, MSG_ARG_INVALID, 869 "burst_size"); 870 return; 871 } 872 873 t0 += 6; 874 875 status = rte_swx_pipeline_port_out_config(p->p, 876 port_id, 877 "ethdev", 878 ¶ms); 879 } else if (strcmp(tokens[t0], "ring") == 0) { 880 struct rte_swx_port_ring_writer_params params; 881 struct ring *ring; 882 883 if (n_tokens < t0 + 4) { 884 snprintf(out, out_size, MSG_ARG_MISMATCH, 885 "pipeline port out link"); 886 return; 887 } 888 889 ring = ring_find(obj, tokens[t0 + 1]); 890 if (!ring) { 891 snprintf(out, out_size, MSG_ARG_INVALID, 892 "ring_name"); 893 return; 894 } 895 params.name = ring->name; 896 897 if (strcmp(tokens[t0 + 2], "bsz") != 0) { 898 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 899 return; 900 } 901 902 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { 903 snprintf(out, out_size, MSG_ARG_INVALID, 904 "burst_size"); 905 return; 906 } 907 908 t0 += 4; 909 910 status = rte_swx_pipeline_port_out_config(p->p, 911 port_id, 912 "ring", 913 ¶ms); 914 } else if (strcmp(tokens[t0], "sink") == 0) { 915 struct rte_swx_port_sink_params params; 916 917 params.file_name = strcmp(tokens[t0 + 1], "none") ? 918 tokens[t0 + 1] : NULL; 919 920 t0 += 2; 921 922 status = rte_swx_pipeline_port_out_config(p->p, 923 port_id, 924 "sink", 925 ¶ms); 926 } else if (strcmp(tokens[t0], "tap") == 0) { 927 struct rte_swx_port_fd_writer_params params; 928 struct tap *tap; 929 930 if (n_tokens < t0 + 4) { 931 snprintf(out, out_size, MSG_ARG_MISMATCH, 932 "pipeline port out tap"); 933 return; 934 } 935 936 tap = tap_find(obj, tokens[t0 + 1]); 937 if (!tap) { 938 snprintf(out, out_size, MSG_ARG_INVALID, 939 "tap_name"); 940 return; 941 } 942 params.fd = tap->fd; 943 944 if (strcmp(tokens[t0 + 2], "bsz") != 0) { 945 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 946 return; 947 } 948 949 if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { 950 snprintf(out, out_size, MSG_ARG_INVALID, 951 "burst_size"); 952 return; 953 } 954 955 t0 += 4; 956 957 status = rte_swx_pipeline_port_out_config(p->p, 958 port_id, 959 "fd", 960 ¶ms); 961 } else { 962 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 963 return; 964 } 965 966 if (status) { 967 snprintf(out, out_size, "port out error."); 968 return; 969 } 970 971 if (n_tokens != t0) { 972 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 973 return; 974 } 975 } 976 977 static const char cmd_pipeline_build_help[] = 978 "pipeline <pipeline_name> build <spec_file>\n"; 979 980 static void 981 cmd_pipeline_build(char **tokens, 982 uint32_t n_tokens, 983 char *out, 984 size_t out_size, 985 void *obj) 986 { 987 struct pipeline *p = NULL; 988 FILE *spec = NULL; 989 uint32_t err_line; 990 const char *err_msg; 991 int status; 992 993 if (n_tokens != 4) { 994 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 995 return; 996 } 997 998 p = pipeline_find(obj, tokens[1]); 999 if (!p || p->ctl) { 1000 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1001 return; 1002 } 1003 1004 spec = fopen(tokens[3], "r"); 1005 if (!spec) { 1006 snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]); 1007 return; 1008 } 1009 1010 status = rte_swx_pipeline_build_from_spec(p->p, 1011 spec, 1012 &err_line, 1013 &err_msg); 1014 fclose(spec); 1015 if (status) { 1016 snprintf(out, out_size, "Error %d at line %u: %s\n.", 1017 status, err_line, err_msg); 1018 return; 1019 } 1020 1021 p->ctl = rte_swx_ctl_pipeline_create(p->p); 1022 if (!p->ctl) { 1023 snprintf(out, out_size, "Pipeline control create failed."); 1024 rte_swx_pipeline_free(p->p); 1025 return; 1026 } 1027 } 1028 1029 static void 1030 table_entry_free(struct rte_swx_table_entry *entry) 1031 { 1032 if (!entry) 1033 return; 1034 1035 free(entry->key); 1036 free(entry->key_mask); 1037 free(entry->action_data); 1038 free(entry); 1039 } 1040 1041 static const char cmd_pipeline_table_update_help[] = 1042 "pipeline <pipeline_name> table <table_name> update <file_name_add> " 1043 "<file_name_delete> <file_name_default>"; 1044 1045 static void 1046 cmd_pipeline_table_update(char **tokens, 1047 uint32_t n_tokens, 1048 char *out, 1049 size_t out_size, 1050 void *obj) 1051 { 1052 struct pipeline *p; 1053 char *pipeline_name, *table_name, *line = NULL; 1054 char *file_name_add, *file_name_delete, *file_name_default; 1055 FILE *file_add = NULL, *file_delete = NULL, *file_default = NULL; 1056 uint32_t line_id; 1057 int status; 1058 1059 if (n_tokens != 8) { 1060 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1061 return; 1062 } 1063 1064 pipeline_name = tokens[1]; 1065 p = pipeline_find(obj, pipeline_name); 1066 if (!p || !p->ctl) { 1067 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1068 return; 1069 } 1070 1071 if (strcmp(tokens[2], "table") != 0) { 1072 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 1073 return; 1074 } 1075 1076 table_name = tokens[3]; 1077 1078 if (strcmp(tokens[4], "update") != 0) { 1079 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "update"); 1080 return; 1081 } 1082 1083 file_name_add = tokens[5]; 1084 file_name_delete = tokens[6]; 1085 file_name_default = tokens[7]; 1086 1087 /* File open. */ 1088 if (strcmp(file_name_add, "none")) { 1089 file_add = fopen(file_name_add, "r"); 1090 if (!file_add) { 1091 snprintf(out, out_size, "Cannot open file %s.\n", 1092 file_name_add); 1093 goto error; 1094 } 1095 } 1096 1097 if (strcmp(file_name_delete, "none")) { 1098 file_delete = fopen(file_name_delete, "r"); 1099 if (!file_delete) { 1100 snprintf(out, out_size, "Cannot open file %s.\n", 1101 file_name_delete); 1102 goto error; 1103 } 1104 } 1105 1106 if (strcmp(file_name_default, "none")) { 1107 file_default = fopen(file_name_default, "r"); 1108 if (!file_default) { 1109 snprintf(out, out_size, "Cannot open file %s.\n", 1110 file_name_default); 1111 goto error; 1112 } 1113 } 1114 1115 if (!file_add && !file_delete && !file_default) { 1116 snprintf(out, out_size, "Nothing to be done."); 1117 return; 1118 } 1119 1120 /* Buffer allocation. */ 1121 line = malloc(2048); 1122 if (!line) { 1123 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 1124 goto error; 1125 } 1126 1127 /* Add. */ 1128 if (file_add) 1129 for (line_id = 1; ; line_id++) { 1130 struct rte_swx_table_entry *entry; 1131 int is_blank_or_comment; 1132 1133 if (fgets(line, 2048, file_add) == NULL) 1134 break; 1135 1136 entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl, 1137 table_name, 1138 line, 1139 &is_blank_or_comment); 1140 if (!entry) { 1141 if (is_blank_or_comment) 1142 continue; 1143 1144 snprintf(out, out_size, MSG_FILE_ERR, 1145 file_name_add, line_id); 1146 goto error; 1147 } 1148 1149 status = rte_swx_ctl_pipeline_table_entry_add(p->ctl, 1150 table_name, 1151 entry); 1152 table_entry_free(entry); 1153 if (status) { 1154 snprintf(out, out_size, 1155 "Invalid entry in file %s at line %u", 1156 file_name_add, line_id); 1157 goto error; 1158 } 1159 } 1160 1161 1162 /* Delete. */ 1163 if (file_delete) 1164 for (line_id = 1; ; line_id++) { 1165 struct rte_swx_table_entry *entry; 1166 int is_blank_or_comment; 1167 1168 if (fgets(line, 2048, file_delete) == NULL) 1169 break; 1170 1171 entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl, 1172 table_name, 1173 line, 1174 &is_blank_or_comment); 1175 if (!entry) { 1176 if (is_blank_or_comment) 1177 continue; 1178 1179 snprintf(out, out_size, MSG_FILE_ERR, 1180 file_name_delete, line_id); 1181 goto error; 1182 } 1183 1184 status = rte_swx_ctl_pipeline_table_entry_delete(p->ctl, 1185 table_name, 1186 entry); 1187 table_entry_free(entry); 1188 if (status) { 1189 snprintf(out, out_size, 1190 "Invalid entry in file %s at line %u", 1191 file_name_delete, line_id); 1192 goto error; 1193 } 1194 } 1195 1196 /* Default. */ 1197 if (file_default) 1198 for (line_id = 1; ; line_id++) { 1199 struct rte_swx_table_entry *entry; 1200 int is_blank_or_comment; 1201 1202 if (fgets(line, 2048, file_default) == NULL) 1203 break; 1204 1205 entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl, 1206 table_name, 1207 line, 1208 &is_blank_or_comment); 1209 if (!entry) { 1210 if (is_blank_or_comment) 1211 continue; 1212 1213 snprintf(out, out_size, MSG_FILE_ERR, 1214 file_name_default, line_id); 1215 goto error; 1216 } 1217 1218 status = rte_swx_ctl_pipeline_table_default_entry_add(p->ctl, 1219 table_name, 1220 entry); 1221 table_entry_free(entry); 1222 if (status) { 1223 snprintf(out, out_size, 1224 "Invalid entry in file %s at line %u", 1225 file_name_default, line_id); 1226 goto error; 1227 } 1228 } 1229 1230 status = rte_swx_ctl_pipeline_commit(p->ctl, 1); 1231 if (status) { 1232 snprintf(out, out_size, "Commit failed."); 1233 goto error; 1234 } 1235 1236 1237 rte_swx_ctl_pipeline_table_fprintf(stdout, p->ctl, table_name); 1238 1239 free(line); 1240 if (file_add) 1241 fclose(file_add); 1242 if (file_delete) 1243 fclose(file_delete); 1244 if (file_default) 1245 fclose(file_default); 1246 return; 1247 1248 error: 1249 rte_swx_ctl_pipeline_abort(p->ctl); 1250 free(line); 1251 if (file_add) 1252 fclose(file_add); 1253 if (file_delete) 1254 fclose(file_delete); 1255 if (file_default) 1256 fclose(file_default); 1257 } 1258 1259 static const char cmd_pipeline_regrd_help[] = 1260 "pipeline <pipeline_name> regrd <register_array_name> <index>\n"; 1261 1262 static void 1263 cmd_pipeline_regrd(char **tokens, 1264 uint32_t n_tokens, 1265 char *out, 1266 size_t out_size, 1267 void *obj) 1268 { 1269 struct pipeline *p; 1270 const char *name; 1271 uint64_t value; 1272 uint32_t idx; 1273 int status; 1274 1275 if (n_tokens != 5) { 1276 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1277 return; 1278 } 1279 1280 p = pipeline_find(obj, tokens[1]); 1281 if (!p || !p->ctl) { 1282 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1283 return; 1284 } 1285 1286 if (strcmp(tokens[2], "regrd")) { 1287 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd"); 1288 return; 1289 } 1290 1291 name = tokens[3]; 1292 1293 if (parser_read_uint32(&idx, tokens[4])) { 1294 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 1295 return; 1296 } 1297 1298 status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value); 1299 if (status) { 1300 snprintf(out, out_size, "Command failed.\n"); 1301 return; 1302 } 1303 1304 snprintf(out, out_size, "0x%" PRIx64 "\n", value); 1305 } 1306 1307 static const char cmd_pipeline_regwr_help[] = 1308 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n"; 1309 1310 static void 1311 cmd_pipeline_regwr(char **tokens, 1312 uint32_t n_tokens, 1313 char *out, 1314 size_t out_size, 1315 void *obj) 1316 { 1317 struct pipeline *p; 1318 const char *name; 1319 uint64_t value; 1320 uint32_t idx; 1321 int status; 1322 1323 if (n_tokens != 6) { 1324 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1325 return; 1326 } 1327 1328 p = pipeline_find(obj, tokens[1]); 1329 if (!p || !p->ctl) { 1330 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1331 return; 1332 } 1333 1334 if (strcmp(tokens[2], "regwr")) { 1335 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr"); 1336 return; 1337 } 1338 1339 name = tokens[3]; 1340 1341 if (parser_read_uint32(&idx, tokens[4])) { 1342 snprintf(out, out_size, MSG_ARG_INVALID, "index"); 1343 return; 1344 } 1345 1346 if (parser_read_uint64(&value, tokens[5])) { 1347 snprintf(out, out_size, MSG_ARG_INVALID, "value"); 1348 return; 1349 } 1350 1351 status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value); 1352 if (status) { 1353 snprintf(out, out_size, "Command failed.\n"); 1354 return; 1355 } 1356 } 1357 1358 static const char cmd_pipeline_meter_profile_add_help[] = 1359 "pipeline <pipeline_name> meter profile <profile_name> add " 1360 "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 1361 1362 static void 1363 cmd_pipeline_meter_profile_add(char **tokens, 1364 uint32_t n_tokens, 1365 char *out, 1366 size_t out_size, 1367 void *obj) 1368 { 1369 struct rte_meter_trtcm_params params; 1370 struct pipeline *p; 1371 const char *profile_name; 1372 int status; 1373 1374 if (n_tokens != 14) { 1375 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1376 return; 1377 } 1378 1379 p = pipeline_find(obj, tokens[1]); 1380 if (!p || !p->ctl) { 1381 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1382 return; 1383 } 1384 1385 if (strcmp(tokens[2], "meter")) { 1386 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 1387 return; 1388 } 1389 1390 if (strcmp(tokens[3], "profile")) { 1391 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 1392 return; 1393 } 1394 1395 profile_name = tokens[4]; 1396 1397 if (strcmp(tokens[5], "add")) { 1398 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 1399 return; 1400 } 1401 1402 if (strcmp(tokens[6], "cir")) { 1403 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 1404 return; 1405 } 1406 1407 if (parser_read_uint64(¶ms.cir, tokens[7])) { 1408 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 1409 return; 1410 } 1411 1412 if (strcmp(tokens[8], "pir")) { 1413 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 1414 return; 1415 } 1416 1417 if (parser_read_uint64(¶ms.pir, tokens[9])) { 1418 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 1419 return; 1420 } 1421 1422 if (strcmp(tokens[10], "cbs")) { 1423 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 1424 return; 1425 } 1426 1427 if (parser_read_uint64(¶ms.cbs, tokens[11])) { 1428 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 1429 return; 1430 } 1431 1432 if (strcmp(tokens[12], "pbs")) { 1433 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 1434 return; 1435 } 1436 1437 if (parser_read_uint64(¶ms.pbs, tokens[13])) { 1438 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 1439 return; 1440 } 1441 1442 status = rte_swx_ctl_meter_profile_add(p->p, profile_name, ¶ms); 1443 if (status) { 1444 snprintf(out, out_size, "Command failed.\n"); 1445 return; 1446 } 1447 } 1448 1449 static const char cmd_pipeline_meter_profile_delete_help[] = 1450 "pipeline <pipeline_name> meter profile <profile_name> delete\n"; 1451 1452 static void 1453 cmd_pipeline_meter_profile_delete(char **tokens, 1454 uint32_t n_tokens, 1455 char *out, 1456 size_t out_size, 1457 void *obj) 1458 { 1459 struct pipeline *p; 1460 const char *profile_name; 1461 int status; 1462 1463 if (n_tokens != 6) { 1464 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1465 return; 1466 } 1467 1468 p = pipeline_find(obj, tokens[1]); 1469 if (!p || !p->ctl) { 1470 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1471 return; 1472 } 1473 1474 if (strcmp(tokens[2], "meter")) { 1475 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 1476 return; 1477 } 1478 1479 if (strcmp(tokens[3], "profile")) { 1480 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 1481 return; 1482 } 1483 1484 profile_name = tokens[4]; 1485 1486 if (strcmp(tokens[5], "delete")) { 1487 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 1488 return; 1489 } 1490 1491 status = rte_swx_ctl_meter_profile_delete(p->p, profile_name); 1492 if (status) { 1493 snprintf(out, out_size, "Command failed.\n"); 1494 return; 1495 } 1496 } 1497 1498 static const char cmd_pipeline_meter_reset_help[] = 1499 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 1500 "reset\n"; 1501 1502 static void 1503 cmd_pipeline_meter_reset(char **tokens, 1504 uint32_t n_tokens, 1505 char *out, 1506 size_t out_size, 1507 void *obj) 1508 { 1509 struct pipeline *p; 1510 const char *name; 1511 uint32_t idx0, idx1; 1512 1513 if (n_tokens != 9) { 1514 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1515 return; 1516 } 1517 1518 p = pipeline_find(obj, tokens[1]); 1519 if (!p || !p->ctl) { 1520 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1521 return; 1522 } 1523 1524 if (strcmp(tokens[2], "meter")) { 1525 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 1526 return; 1527 } 1528 1529 name = tokens[3]; 1530 1531 if (strcmp(tokens[4], "from")) { 1532 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 1533 return; 1534 } 1535 1536 if (parser_read_uint32(&idx0, tokens[5])) { 1537 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 1538 return; 1539 } 1540 1541 if (strcmp(tokens[6], "to")) { 1542 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 1543 return; 1544 } 1545 1546 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 1547 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 1548 return; 1549 } 1550 1551 if (strcmp(tokens[8], "reset")) { 1552 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset"); 1553 return; 1554 } 1555 1556 for ( ; idx0 <= idx1; idx0++) { 1557 int status; 1558 1559 status = rte_swx_ctl_meter_reset(p->p, name, idx0); 1560 if (status) { 1561 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 1562 return; 1563 } 1564 } 1565 } 1566 1567 static const char cmd_pipeline_meter_set_help[] = 1568 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 1569 "set profile <profile_name>\n"; 1570 1571 static void 1572 cmd_pipeline_meter_set(char **tokens, 1573 uint32_t n_tokens, 1574 char *out, 1575 size_t out_size, 1576 void *obj) 1577 { 1578 struct pipeline *p; 1579 const char *name, *profile_name; 1580 uint32_t idx0, idx1; 1581 1582 if (n_tokens != 11) { 1583 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1584 return; 1585 } 1586 1587 p = pipeline_find(obj, tokens[1]); 1588 if (!p || !p->ctl) { 1589 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1590 return; 1591 } 1592 1593 if (strcmp(tokens[2], "meter")) { 1594 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 1595 return; 1596 } 1597 1598 name = tokens[3]; 1599 1600 if (strcmp(tokens[4], "from")) { 1601 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 1602 return; 1603 } 1604 1605 if (parser_read_uint32(&idx0, tokens[5])) { 1606 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 1607 return; 1608 } 1609 1610 if (strcmp(tokens[6], "to")) { 1611 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 1612 return; 1613 } 1614 1615 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 1616 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 1617 return; 1618 } 1619 1620 if (strcmp(tokens[8], "set")) { 1621 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set"); 1622 return; 1623 } 1624 1625 if (strcmp(tokens[9], "profile")) { 1626 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 1627 return; 1628 } 1629 1630 profile_name = tokens[10]; 1631 1632 for ( ; idx0 <= idx1; idx0++) { 1633 int status; 1634 1635 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name); 1636 if (status) { 1637 snprintf(out, out_size, "Command failed for index %u.\n", idx0); 1638 return; 1639 } 1640 } 1641 } 1642 1643 static const char cmd_pipeline_meter_stats_help[] = 1644 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> " 1645 "stats\n"; 1646 1647 static void 1648 cmd_pipeline_meter_stats(char **tokens, 1649 uint32_t n_tokens, 1650 char *out, 1651 size_t out_size, 1652 void *obj) 1653 { 1654 struct rte_swx_ctl_meter_stats stats; 1655 struct pipeline *p; 1656 const char *name; 1657 uint32_t idx0, idx1; 1658 1659 if (n_tokens != 9) { 1660 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1661 return; 1662 } 1663 1664 p = pipeline_find(obj, tokens[1]); 1665 if (!p || !p->ctl) { 1666 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1667 return; 1668 } 1669 1670 if (strcmp(tokens[2], "meter")) { 1671 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 1672 return; 1673 } 1674 1675 name = tokens[3]; 1676 1677 if (strcmp(tokens[4], "from")) { 1678 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 1679 return; 1680 } 1681 1682 if (parser_read_uint32(&idx0, tokens[5])) { 1683 snprintf(out, out_size, MSG_ARG_INVALID, "index0"); 1684 return; 1685 } 1686 1687 if (strcmp(tokens[6], "to")) { 1688 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 1689 return; 1690 } 1691 1692 if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) { 1693 snprintf(out, out_size, MSG_ARG_INVALID, "index1"); 1694 return; 1695 } 1696 1697 if (strcmp(tokens[8], "stats")) { 1698 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1699 return; 1700 } 1701 1702 /* Table header. */ 1703 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 1704 "-------", 1705 "----------------", "----------------", "----------------", 1706 "----------------", "----------------", "----------------"); 1707 out_size -= strlen(out); 1708 out += strlen(out); 1709 1710 snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n", 1711 "METER #", 1712 "GREEN (packets)", "YELLOW (packets)", "RED (packets)", 1713 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)"); 1714 out_size -= strlen(out); 1715 out += strlen(out); 1716 1717 snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n", 1718 "-------", 1719 "----------------", "----------------", "----------------", 1720 "----------------", "----------------", "----------------"); 1721 out_size -= strlen(out); 1722 out += strlen(out); 1723 1724 /* Table rows. */ 1725 for ( ; idx0 <= idx1; idx0++) { 1726 int status; 1727 1728 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats); 1729 if (status) { 1730 snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0); 1731 out_size -= strlen(out); 1732 out += strlen(out); 1733 return; 1734 } 1735 1736 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 1737 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n", 1738 idx0, 1739 stats.n_pkts[RTE_COLOR_GREEN], 1740 stats.n_pkts[RTE_COLOR_YELLOW], 1741 stats.n_pkts[RTE_COLOR_RED], 1742 stats.n_bytes[RTE_COLOR_GREEN], 1743 stats.n_bytes[RTE_COLOR_YELLOW], 1744 stats.n_bytes[RTE_COLOR_RED]); 1745 out_size -= strlen(out); 1746 out += strlen(out); 1747 } 1748 } 1749 1750 static const char cmd_pipeline_stats_help[] = 1751 "pipeline <pipeline_name> stats\n"; 1752 1753 static void 1754 cmd_pipeline_stats(char **tokens, 1755 uint32_t n_tokens, 1756 char *out, 1757 size_t out_size, 1758 void *obj) 1759 { 1760 struct rte_swx_ctl_pipeline_info info; 1761 struct pipeline *p; 1762 uint32_t i; 1763 int status; 1764 1765 if (n_tokens != 3) { 1766 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1767 return; 1768 } 1769 1770 p = pipeline_find(obj, tokens[1]); 1771 if (!p || !p->ctl) { 1772 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1773 return; 1774 } 1775 1776 if (strcmp(tokens[2], "stats")) { 1777 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1778 return; 1779 } 1780 1781 status = rte_swx_ctl_pipeline_info_get(p->p, &info); 1782 if (status) { 1783 snprintf(out, out_size, "Pipeline info get error."); 1784 return; 1785 } 1786 1787 snprintf(out, out_size, "Input ports:\n"); 1788 out_size -= strlen(out); 1789 out += strlen(out); 1790 1791 for (i = 0; i < info.n_ports_in; i++) { 1792 struct rte_swx_port_in_stats stats; 1793 1794 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats); 1795 1796 snprintf(out, out_size, "\tPort %u:" 1797 " packets %" PRIu64 1798 " bytes %" PRIu64 1799 " empty %" PRIu64 "\n", 1800 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 1801 out_size -= strlen(out); 1802 out += strlen(out); 1803 } 1804 1805 snprintf(out, out_size, "\nOutput ports:\n"); 1806 out_size -= strlen(out); 1807 out += strlen(out); 1808 1809 for (i = 0; i < info.n_ports_out; i++) { 1810 struct rte_swx_port_out_stats stats; 1811 1812 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); 1813 1814 snprintf(out, out_size, "\tPort %u:" 1815 " packets %" PRIu64 1816 " bytes %" PRIu64 "\n", 1817 i, stats.n_pkts, stats.n_bytes); 1818 out_size -= strlen(out); 1819 out += strlen(out); 1820 } 1821 1822 snprintf(out, out_size, "\nTables:\n"); 1823 out_size -= strlen(out); 1824 out += strlen(out); 1825 1826 for (i = 0; i < info.n_tables; i++) { 1827 struct rte_swx_ctl_table_info table_info; 1828 uint64_t n_pkts_action[info.n_actions]; 1829 struct rte_swx_table_stats stats = { 1830 .n_pkts_hit = 0, 1831 .n_pkts_miss = 0, 1832 .n_pkts_action = n_pkts_action, 1833 }; 1834 uint32_t j; 1835 1836 status = rte_swx_ctl_table_info_get(p->p, i, &table_info); 1837 if (status) { 1838 snprintf(out, out_size, "Table info get error."); 1839 return; 1840 } 1841 1842 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats); 1843 if (status) { 1844 snprintf(out, out_size, "Table stats read error."); 1845 return; 1846 } 1847 1848 snprintf(out, out_size, "\tTable %s:\n" 1849 "\t\tHit (packets): %" PRIu64 "\n" 1850 "\t\tMiss (packets): %" PRIu64 "\n", 1851 table_info.name, 1852 stats.n_pkts_hit, 1853 stats.n_pkts_miss); 1854 out_size -= strlen(out); 1855 out += strlen(out); 1856 1857 for (j = 0; j < info.n_actions; j++) { 1858 struct rte_swx_ctl_action_info action_info; 1859 1860 status = rte_swx_ctl_action_info_get(p->p, j, &action_info); 1861 if (status) { 1862 snprintf(out, out_size, "Action info get error."); 1863 return; 1864 } 1865 1866 snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n", 1867 action_info.name, 1868 stats.n_pkts_action[j]); 1869 out_size -= strlen(out); 1870 out += strlen(out); 1871 } 1872 } 1873 } 1874 1875 static const char cmd_thread_pipeline_enable_help[] = 1876 "thread <thread_id> pipeline <pipeline_name> enable\n"; 1877 1878 static void 1879 cmd_thread_pipeline_enable(char **tokens, 1880 uint32_t n_tokens, 1881 char *out, 1882 size_t out_size, 1883 void *obj) 1884 { 1885 char *pipeline_name; 1886 struct pipeline *p; 1887 uint32_t thread_id; 1888 int status; 1889 1890 if (n_tokens != 5) { 1891 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1892 return; 1893 } 1894 1895 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 1896 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 1897 return; 1898 } 1899 1900 if (strcmp(tokens[2], "pipeline") != 0) { 1901 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 1902 return; 1903 } 1904 1905 pipeline_name = tokens[3]; 1906 p = pipeline_find(obj, pipeline_name); 1907 if (!p || !p->ctl) { 1908 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1909 return; 1910 } 1911 1912 if (strcmp(tokens[4], "enable") != 0) { 1913 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 1914 return; 1915 } 1916 1917 status = thread_pipeline_enable(thread_id, obj, pipeline_name); 1918 if (status) { 1919 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 1920 return; 1921 } 1922 } 1923 1924 static const char cmd_thread_pipeline_disable_help[] = 1925 "thread <thread_id> pipeline <pipeline_name> disable\n"; 1926 1927 static void 1928 cmd_thread_pipeline_disable(char **tokens, 1929 uint32_t n_tokens, 1930 char *out, 1931 size_t out_size, 1932 void *obj) 1933 { 1934 struct pipeline *p; 1935 char *pipeline_name; 1936 uint32_t thread_id; 1937 int status; 1938 1939 if (n_tokens != 5) { 1940 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1941 return; 1942 } 1943 1944 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 1945 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 1946 return; 1947 } 1948 1949 if (strcmp(tokens[2], "pipeline") != 0) { 1950 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 1951 return; 1952 } 1953 1954 pipeline_name = tokens[3]; 1955 p = pipeline_find(obj, pipeline_name); 1956 if (!p || !p->ctl) { 1957 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1958 return; 1959 } 1960 1961 if (strcmp(tokens[4], "disable") != 0) { 1962 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 1963 return; 1964 } 1965 1966 status = thread_pipeline_disable(thread_id, obj, pipeline_name); 1967 if (status) { 1968 snprintf(out, out_size, MSG_CMD_FAIL, 1969 "thread pipeline disable"); 1970 return; 1971 } 1972 } 1973 1974 static void 1975 cmd_help(char **tokens, 1976 uint32_t n_tokens, 1977 char *out, 1978 size_t out_size, 1979 void *arg __rte_unused) 1980 { 1981 tokens++; 1982 n_tokens--; 1983 1984 if (n_tokens == 0) { 1985 snprintf(out, out_size, 1986 "Type 'help <command>' for command details.\n\n" 1987 "List of commands:\n" 1988 "\tmempool\n" 1989 "\tlink\n" 1990 "\ttap\n" 1991 "\tpipeline create\n" 1992 "\tpipeline port in\n" 1993 "\tpipeline port out\n" 1994 "\tpipeline build\n" 1995 "\tpipeline table update\n" 1996 "\tpipeline regrd\n" 1997 "\tpipeline regwr\n" 1998 "\tpipeline meter profile add\n" 1999 "\tpipeline meter profile delete\n" 2000 "\tpipeline meter reset\n" 2001 "\tpipeline meter set\n" 2002 "\tpipeline meter stats\n" 2003 "\tpipeline stats\n" 2004 "\tthread pipeline enable\n" 2005 "\tthread pipeline disable\n\n"); 2006 return; 2007 } 2008 2009 if (strcmp(tokens[0], "mempool") == 0) { 2010 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 2011 return; 2012 } 2013 2014 if (strcmp(tokens[0], "link") == 0) { 2015 snprintf(out, out_size, "\n%s\n", cmd_link_help); 2016 return; 2017 } 2018 2019 if (strcmp(tokens[0], "ring") == 0) { 2020 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 2021 return; 2022 } 2023 2024 if (strcmp(tokens[0], "tap") == 0) { 2025 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 2026 return; 2027 } 2028 2029 if ((strcmp(tokens[0], "pipeline") == 0) && 2030 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { 2031 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); 2032 return; 2033 } 2034 2035 if ((strcmp(tokens[0], "pipeline") == 0) && 2036 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { 2037 if (strcmp(tokens[2], "in") == 0) { 2038 snprintf(out, out_size, "\n%s\n", 2039 cmd_pipeline_port_in_help); 2040 return; 2041 } 2042 2043 if (strcmp(tokens[2], "out") == 0) { 2044 snprintf(out, out_size, "\n%s\n", 2045 cmd_pipeline_port_out_help); 2046 return; 2047 } 2048 } 2049 2050 if ((strcmp(tokens[0], "pipeline") == 0) && 2051 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 2052 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 2053 return; 2054 } 2055 2056 if ((strcmp(tokens[0], "pipeline") == 0) && 2057 (n_tokens == 3) && 2058 (strcmp(tokens[1], "table") == 0) && 2059 (strcmp(tokens[2], "update") == 0)) { 2060 snprintf(out, out_size, "\n%s\n", 2061 cmd_pipeline_table_update_help); 2062 return; 2063 } 2064 2065 if ((strcmp(tokens[0], "pipeline") == 0) && 2066 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 2067 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 2068 return; 2069 } 2070 2071 if ((strcmp(tokens[0], "pipeline") == 0) && 2072 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 2073 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 2074 return; 2075 } 2076 2077 if (!strcmp(tokens[0], "pipeline") && 2078 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2079 && !strcmp(tokens[2], "profile") 2080 && !strcmp(tokens[3], "add")) { 2081 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 2082 return; 2083 } 2084 2085 if (!strcmp(tokens[0], "pipeline") && 2086 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2087 && !strcmp(tokens[2], "profile") 2088 && !strcmp(tokens[3], "delete")) { 2089 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 2090 return; 2091 } 2092 2093 if (!strcmp(tokens[0], "pipeline") && 2094 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2095 && !strcmp(tokens[2], "reset")) { 2096 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 2097 return; 2098 } 2099 2100 if (!strcmp(tokens[0], "pipeline") && 2101 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2102 && !strcmp(tokens[2], "set")) { 2103 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 2104 return; 2105 } 2106 2107 if (!strcmp(tokens[0], "pipeline") && 2108 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2109 && !strcmp(tokens[2], "stats")) { 2110 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 2111 return; 2112 } 2113 2114 if ((strcmp(tokens[0], "pipeline") == 0) && 2115 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 2116 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 2117 return; 2118 } 2119 2120 if ((n_tokens == 3) && 2121 (strcmp(tokens[0], "thread") == 0) && 2122 (strcmp(tokens[1], "pipeline") == 0)) { 2123 if (strcmp(tokens[2], "enable") == 0) { 2124 snprintf(out, out_size, "\n%s\n", 2125 cmd_thread_pipeline_enable_help); 2126 return; 2127 } 2128 2129 if (strcmp(tokens[2], "disable") == 0) { 2130 snprintf(out, out_size, "\n%s\n", 2131 cmd_thread_pipeline_disable_help); 2132 return; 2133 } 2134 } 2135 2136 snprintf(out, out_size, "Invalid command\n"); 2137 } 2138 2139 void 2140 cli_process(char *in, char *out, size_t out_size, void *obj) 2141 { 2142 char *tokens[CMD_MAX_TOKENS]; 2143 uint32_t n_tokens = RTE_DIM(tokens); 2144 int status; 2145 2146 if (is_comment(in)) 2147 return; 2148 2149 status = parse_tokenize_string(in, tokens, &n_tokens); 2150 if (status) { 2151 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 2152 return; 2153 } 2154 2155 if (n_tokens == 0) 2156 return; 2157 2158 if (strcmp(tokens[0], "help") == 0) { 2159 cmd_help(tokens, n_tokens, out, out_size, obj); 2160 return; 2161 } 2162 2163 if (strcmp(tokens[0], "mempool") == 0) { 2164 cmd_mempool(tokens, n_tokens, out, out_size, obj); 2165 return; 2166 } 2167 2168 if (strcmp(tokens[0], "link") == 0) { 2169 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 2170 cmd_link_show(tokens, n_tokens, out, out_size, obj); 2171 return; 2172 } 2173 2174 cmd_link(tokens, n_tokens, out, out_size, obj); 2175 return; 2176 } 2177 2178 if (strcmp(tokens[0], "ring") == 0) { 2179 cmd_ring(tokens, n_tokens, out, out_size, obj); 2180 return; 2181 } 2182 2183 if (strcmp(tokens[0], "tap") == 0) { 2184 cmd_tap(tokens, n_tokens, out, out_size, obj); 2185 return; 2186 } 2187 2188 if (strcmp(tokens[0], "pipeline") == 0) { 2189 if ((n_tokens >= 3) && 2190 (strcmp(tokens[2], "create") == 0)) { 2191 cmd_pipeline_create(tokens, n_tokens, out, out_size, 2192 obj); 2193 return; 2194 } 2195 2196 if ((n_tokens >= 4) && 2197 (strcmp(tokens[2], "port") == 0) && 2198 (strcmp(tokens[3], "in") == 0)) { 2199 cmd_pipeline_port_in(tokens, n_tokens, out, out_size, 2200 obj); 2201 return; 2202 } 2203 2204 if ((n_tokens >= 4) && 2205 (strcmp(tokens[2], "port") == 0) && 2206 (strcmp(tokens[3], "out") == 0)) { 2207 cmd_pipeline_port_out(tokens, n_tokens, out, out_size, 2208 obj); 2209 return; 2210 } 2211 2212 if ((n_tokens >= 3) && 2213 (strcmp(tokens[2], "build") == 0)) { 2214 cmd_pipeline_build(tokens, n_tokens, out, out_size, 2215 obj); 2216 return; 2217 } 2218 2219 if ((n_tokens >= 3) && 2220 (strcmp(tokens[2], "table") == 0)) { 2221 cmd_pipeline_table_update(tokens, n_tokens, out, 2222 out_size, obj); 2223 return; 2224 } 2225 2226 if ((n_tokens >= 3) && 2227 (strcmp(tokens[2], "regrd") == 0)) { 2228 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 2229 return; 2230 } 2231 2232 if ((n_tokens >= 3) && 2233 (strcmp(tokens[2], "regwr") == 0)) { 2234 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 2235 return; 2236 } 2237 2238 if ((n_tokens >= 6) && 2239 (strcmp(tokens[2], "meter") == 0) && 2240 (strcmp(tokens[3], "profile") == 0) && 2241 (strcmp(tokens[5], "add") == 0)) { 2242 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 2243 return; 2244 } 2245 2246 if ((n_tokens >= 6) && 2247 (strcmp(tokens[2], "meter") == 0) && 2248 (strcmp(tokens[3], "profile") == 0) && 2249 (strcmp(tokens[5], "delete") == 0)) { 2250 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 2251 return; 2252 } 2253 2254 if ((n_tokens >= 9) && 2255 (strcmp(tokens[2], "meter") == 0) && 2256 (strcmp(tokens[8], "reset") == 0)) { 2257 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 2258 return; 2259 } 2260 2261 if ((n_tokens >= 9) && 2262 (strcmp(tokens[2], "meter") == 0) && 2263 (strcmp(tokens[8], "set") == 0)) { 2264 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 2265 return; 2266 } 2267 2268 if ((n_tokens >= 9) && 2269 (strcmp(tokens[2], "meter") == 0) && 2270 (strcmp(tokens[8], "stats") == 0)) { 2271 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 2272 return; 2273 } 2274 2275 if ((n_tokens >= 3) && 2276 (strcmp(tokens[2], "stats") == 0)) { 2277 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 2278 obj); 2279 return; 2280 } 2281 } 2282 2283 if (strcmp(tokens[0], "thread") == 0) { 2284 if ((n_tokens >= 5) && 2285 (strcmp(tokens[4], "enable") == 0)) { 2286 cmd_thread_pipeline_enable(tokens, n_tokens, 2287 out, out_size, obj); 2288 return; 2289 } 2290 2291 if ((n_tokens >= 5) && 2292 (strcmp(tokens[4], "disable") == 0)) { 2293 cmd_thread_pipeline_disable(tokens, n_tokens, 2294 out, out_size, obj); 2295 return; 2296 } 2297 } 2298 2299 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 2300 } 2301 2302 int 2303 cli_script_process(const char *file_name, 2304 size_t msg_in_len_max, 2305 size_t msg_out_len_max, 2306 void *obj) 2307 { 2308 char *msg_in = NULL, *msg_out = NULL; 2309 FILE *f = NULL; 2310 2311 /* Check input arguments */ 2312 if ((file_name == NULL) || 2313 (strlen(file_name) == 0) || 2314 (msg_in_len_max == 0) || 2315 (msg_out_len_max == 0)) 2316 return -EINVAL; 2317 2318 msg_in = malloc(msg_in_len_max + 1); 2319 msg_out = malloc(msg_out_len_max + 1); 2320 if ((msg_in == NULL) || 2321 (msg_out == NULL)) { 2322 free(msg_out); 2323 free(msg_in); 2324 return -ENOMEM; 2325 } 2326 2327 /* Open input file */ 2328 f = fopen(file_name, "r"); 2329 if (f == NULL) { 2330 free(msg_out); 2331 free(msg_in); 2332 return -EIO; 2333 } 2334 2335 /* Read file */ 2336 for ( ; ; ) { 2337 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 2338 break; 2339 2340 printf("%s", msg_in); 2341 msg_out[0] = 0; 2342 2343 cli_process(msg_in, 2344 msg_out, 2345 msg_out_len_max, 2346 obj); 2347 2348 if (strlen(msg_out)) 2349 printf("%s", msg_out); 2350 } 2351 2352 /* Close file */ 2353 fclose(f); 2354 free(msg_out); 2355 free(msg_in); 2356 return 0; 2357 } 2358