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", 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", 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", 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, "Output 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 1823 static const char cmd_thread_pipeline_enable_help[] = 1824 "thread <thread_id> pipeline <pipeline_name> enable\n"; 1825 1826 static void 1827 cmd_thread_pipeline_enable(char **tokens, 1828 uint32_t n_tokens, 1829 char *out, 1830 size_t out_size, 1831 void *obj) 1832 { 1833 char *pipeline_name; 1834 struct pipeline *p; 1835 uint32_t thread_id; 1836 int status; 1837 1838 if (n_tokens != 5) { 1839 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1840 return; 1841 } 1842 1843 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 1844 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 1845 return; 1846 } 1847 1848 if (strcmp(tokens[2], "pipeline") != 0) { 1849 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 1850 return; 1851 } 1852 1853 pipeline_name = tokens[3]; 1854 p = pipeline_find(obj, pipeline_name); 1855 if (!p || !p->ctl) { 1856 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1857 return; 1858 } 1859 1860 if (strcmp(tokens[4], "enable") != 0) { 1861 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 1862 return; 1863 } 1864 1865 status = thread_pipeline_enable(thread_id, obj, pipeline_name); 1866 if (status) { 1867 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 1868 return; 1869 } 1870 } 1871 1872 static const char cmd_thread_pipeline_disable_help[] = 1873 "thread <thread_id> pipeline <pipeline_name> disable\n"; 1874 1875 static void 1876 cmd_thread_pipeline_disable(char **tokens, 1877 uint32_t n_tokens, 1878 char *out, 1879 size_t out_size, 1880 void *obj) 1881 { 1882 struct pipeline *p; 1883 char *pipeline_name; 1884 uint32_t thread_id; 1885 int status; 1886 1887 if (n_tokens != 5) { 1888 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1889 return; 1890 } 1891 1892 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 1893 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 1894 return; 1895 } 1896 1897 if (strcmp(tokens[2], "pipeline") != 0) { 1898 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 1899 return; 1900 } 1901 1902 pipeline_name = tokens[3]; 1903 p = pipeline_find(obj, pipeline_name); 1904 if (!p || !p->ctl) { 1905 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1906 return; 1907 } 1908 1909 if (strcmp(tokens[4], "disable") != 0) { 1910 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 1911 return; 1912 } 1913 1914 status = thread_pipeline_disable(thread_id, obj, pipeline_name); 1915 if (status) { 1916 snprintf(out, out_size, MSG_CMD_FAIL, 1917 "thread pipeline disable"); 1918 return; 1919 } 1920 } 1921 1922 static void 1923 cmd_help(char **tokens, 1924 uint32_t n_tokens, 1925 char *out, 1926 size_t out_size, 1927 void *arg __rte_unused) 1928 { 1929 tokens++; 1930 n_tokens--; 1931 1932 if (n_tokens == 0) { 1933 snprintf(out, out_size, 1934 "Type 'help <command>' for command details.\n\n" 1935 "List of commands:\n" 1936 "\tmempool\n" 1937 "\tlink\n" 1938 "\ttap\n" 1939 "\tpipeline create\n" 1940 "\tpipeline port in\n" 1941 "\tpipeline port out\n" 1942 "\tpipeline build\n" 1943 "\tpipeline table update\n" 1944 "\tpipeline regrd\n" 1945 "\tpipeline regwr\n" 1946 "\tpipeline meter profile add\n" 1947 "\tpipeline meter profile delete\n" 1948 "\tpipeline meter reset\n" 1949 "\tpipeline meter set\n" 1950 "\tpipeline meter stats\n" 1951 "\tpipeline stats\n" 1952 "\tthread pipeline enable\n" 1953 "\tthread pipeline disable\n\n"); 1954 return; 1955 } 1956 1957 if (strcmp(tokens[0], "mempool") == 0) { 1958 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 1959 return; 1960 } 1961 1962 if (strcmp(tokens[0], "link") == 0) { 1963 snprintf(out, out_size, "\n%s\n", cmd_link_help); 1964 return; 1965 } 1966 1967 if (strcmp(tokens[0], "ring") == 0) { 1968 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 1969 return; 1970 } 1971 1972 if (strcmp(tokens[0], "tap") == 0) { 1973 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 1974 return; 1975 } 1976 1977 if ((strcmp(tokens[0], "pipeline") == 0) && 1978 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { 1979 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); 1980 return; 1981 } 1982 1983 if ((strcmp(tokens[0], "pipeline") == 0) && 1984 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { 1985 if (strcmp(tokens[2], "in") == 0) { 1986 snprintf(out, out_size, "\n%s\n", 1987 cmd_pipeline_port_in_help); 1988 return; 1989 } 1990 1991 if (strcmp(tokens[2], "out") == 0) { 1992 snprintf(out, out_size, "\n%s\n", 1993 cmd_pipeline_port_out_help); 1994 return; 1995 } 1996 } 1997 1998 if ((strcmp(tokens[0], "pipeline") == 0) && 1999 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 2000 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 2001 return; 2002 } 2003 2004 if ((strcmp(tokens[0], "pipeline") == 0) && 2005 (n_tokens == 3) && 2006 (strcmp(tokens[1], "table") == 0) && 2007 (strcmp(tokens[2], "update") == 0)) { 2008 snprintf(out, out_size, "\n%s\n", 2009 cmd_pipeline_table_update_help); 2010 return; 2011 } 2012 2013 if ((strcmp(tokens[0], "pipeline") == 0) && 2014 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) { 2015 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help); 2016 return; 2017 } 2018 2019 if ((strcmp(tokens[0], "pipeline") == 0) && 2020 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) { 2021 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help); 2022 return; 2023 } 2024 2025 if (!strcmp(tokens[0], "pipeline") && 2026 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2027 && !strcmp(tokens[2], "profile") 2028 && !strcmp(tokens[3], "add")) { 2029 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help); 2030 return; 2031 } 2032 2033 if (!strcmp(tokens[0], "pipeline") && 2034 (n_tokens == 4) && !strcmp(tokens[1], "meter") 2035 && !strcmp(tokens[2], "profile") 2036 && !strcmp(tokens[3], "delete")) { 2037 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help); 2038 return; 2039 } 2040 2041 if (!strcmp(tokens[0], "pipeline") && 2042 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2043 && !strcmp(tokens[2], "reset")) { 2044 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help); 2045 return; 2046 } 2047 2048 if (!strcmp(tokens[0], "pipeline") && 2049 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2050 && !strcmp(tokens[2], "set")) { 2051 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help); 2052 return; 2053 } 2054 2055 if (!strcmp(tokens[0], "pipeline") && 2056 (n_tokens == 3) && !strcmp(tokens[1], "meter") 2057 && !strcmp(tokens[2], "stats")) { 2058 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help); 2059 return; 2060 } 2061 2062 if ((strcmp(tokens[0], "pipeline") == 0) && 2063 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 2064 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 2065 return; 2066 } 2067 2068 if ((n_tokens == 3) && 2069 (strcmp(tokens[0], "thread") == 0) && 2070 (strcmp(tokens[1], "pipeline") == 0)) { 2071 if (strcmp(tokens[2], "enable") == 0) { 2072 snprintf(out, out_size, "\n%s\n", 2073 cmd_thread_pipeline_enable_help); 2074 return; 2075 } 2076 2077 if (strcmp(tokens[2], "disable") == 0) { 2078 snprintf(out, out_size, "\n%s\n", 2079 cmd_thread_pipeline_disable_help); 2080 return; 2081 } 2082 } 2083 2084 snprintf(out, out_size, "Invalid command\n"); 2085 } 2086 2087 void 2088 cli_process(char *in, char *out, size_t out_size, void *obj) 2089 { 2090 char *tokens[CMD_MAX_TOKENS]; 2091 uint32_t n_tokens = RTE_DIM(tokens); 2092 int status; 2093 2094 if (is_comment(in)) 2095 return; 2096 2097 status = parse_tokenize_string(in, tokens, &n_tokens); 2098 if (status) { 2099 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 2100 return; 2101 } 2102 2103 if (n_tokens == 0) 2104 return; 2105 2106 if (strcmp(tokens[0], "help") == 0) { 2107 cmd_help(tokens, n_tokens, out, out_size, obj); 2108 return; 2109 } 2110 2111 if (strcmp(tokens[0], "mempool") == 0) { 2112 cmd_mempool(tokens, n_tokens, out, out_size, obj); 2113 return; 2114 } 2115 2116 if (strcmp(tokens[0], "link") == 0) { 2117 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 2118 cmd_link_show(tokens, n_tokens, out, out_size, obj); 2119 return; 2120 } 2121 2122 cmd_link(tokens, n_tokens, out, out_size, obj); 2123 return; 2124 } 2125 2126 if (strcmp(tokens[0], "ring") == 0) { 2127 cmd_ring(tokens, n_tokens, out, out_size, obj); 2128 return; 2129 } 2130 2131 if (strcmp(tokens[0], "tap") == 0) { 2132 cmd_tap(tokens, n_tokens, out, out_size, obj); 2133 return; 2134 } 2135 2136 if (strcmp(tokens[0], "pipeline") == 0) { 2137 if ((n_tokens >= 3) && 2138 (strcmp(tokens[2], "create") == 0)) { 2139 cmd_pipeline_create(tokens, n_tokens, out, out_size, 2140 obj); 2141 return; 2142 } 2143 2144 if ((n_tokens >= 4) && 2145 (strcmp(tokens[2], "port") == 0) && 2146 (strcmp(tokens[3], "in") == 0)) { 2147 cmd_pipeline_port_in(tokens, n_tokens, out, out_size, 2148 obj); 2149 return; 2150 } 2151 2152 if ((n_tokens >= 4) && 2153 (strcmp(tokens[2], "port") == 0) && 2154 (strcmp(tokens[3], "out") == 0)) { 2155 cmd_pipeline_port_out(tokens, n_tokens, out, out_size, 2156 obj); 2157 return; 2158 } 2159 2160 if ((n_tokens >= 3) && 2161 (strcmp(tokens[2], "build") == 0)) { 2162 cmd_pipeline_build(tokens, n_tokens, out, out_size, 2163 obj); 2164 return; 2165 } 2166 2167 if ((n_tokens >= 3) && 2168 (strcmp(tokens[2], "table") == 0)) { 2169 cmd_pipeline_table_update(tokens, n_tokens, out, 2170 out_size, obj); 2171 return; 2172 } 2173 2174 if ((n_tokens >= 3) && 2175 (strcmp(tokens[2], "regrd") == 0)) { 2176 cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj); 2177 return; 2178 } 2179 2180 if ((n_tokens >= 3) && 2181 (strcmp(tokens[2], "regwr") == 0)) { 2182 cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj); 2183 return; 2184 } 2185 2186 if ((n_tokens >= 6) && 2187 (strcmp(tokens[2], "meter") == 0) && 2188 (strcmp(tokens[3], "profile") == 0) && 2189 (strcmp(tokens[5], "add") == 0)) { 2190 cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj); 2191 return; 2192 } 2193 2194 if ((n_tokens >= 6) && 2195 (strcmp(tokens[2], "meter") == 0) && 2196 (strcmp(tokens[3], "profile") == 0) && 2197 (strcmp(tokens[5], "delete") == 0)) { 2198 cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj); 2199 return; 2200 } 2201 2202 if ((n_tokens >= 9) && 2203 (strcmp(tokens[2], "meter") == 0) && 2204 (strcmp(tokens[8], "reset") == 0)) { 2205 cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj); 2206 return; 2207 } 2208 2209 if ((n_tokens >= 9) && 2210 (strcmp(tokens[2], "meter") == 0) && 2211 (strcmp(tokens[8], "set") == 0)) { 2212 cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj); 2213 return; 2214 } 2215 2216 if ((n_tokens >= 9) && 2217 (strcmp(tokens[2], "meter") == 0) && 2218 (strcmp(tokens[8], "stats") == 0)) { 2219 cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj); 2220 return; 2221 } 2222 2223 if ((n_tokens >= 3) && 2224 (strcmp(tokens[2], "stats") == 0)) { 2225 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 2226 obj); 2227 return; 2228 } 2229 } 2230 2231 if (strcmp(tokens[0], "thread") == 0) { 2232 if ((n_tokens >= 5) && 2233 (strcmp(tokens[4], "enable") == 0)) { 2234 cmd_thread_pipeline_enable(tokens, n_tokens, 2235 out, out_size, obj); 2236 return; 2237 } 2238 2239 if ((n_tokens >= 5) && 2240 (strcmp(tokens[4], "disable") == 0)) { 2241 cmd_thread_pipeline_disable(tokens, n_tokens, 2242 out, out_size, obj); 2243 return; 2244 } 2245 } 2246 2247 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 2248 } 2249 2250 int 2251 cli_script_process(const char *file_name, 2252 size_t msg_in_len_max, 2253 size_t msg_out_len_max, 2254 void *obj) 2255 { 2256 char *msg_in = NULL, *msg_out = NULL; 2257 FILE *f = NULL; 2258 2259 /* Check input arguments */ 2260 if ((file_name == NULL) || 2261 (strlen(file_name) == 0) || 2262 (msg_in_len_max == 0) || 2263 (msg_out_len_max == 0)) 2264 return -EINVAL; 2265 2266 msg_in = malloc(msg_in_len_max + 1); 2267 msg_out = malloc(msg_out_len_max + 1); 2268 if ((msg_in == NULL) || 2269 (msg_out == NULL)) { 2270 free(msg_out); 2271 free(msg_in); 2272 return -ENOMEM; 2273 } 2274 2275 /* Open input file */ 2276 f = fopen(file_name, "r"); 2277 if (f == NULL) { 2278 free(msg_out); 2279 free(msg_in); 2280 return -EIO; 2281 } 2282 2283 /* Read file */ 2284 for ( ; ; ) { 2285 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 2286 break; 2287 2288 printf("%s", msg_in); 2289 msg_out[0] = 0; 2290 2291 cli_process(msg_in, 2292 msg_out, 2293 msg_out_len_max, 2294 obj); 2295 2296 if (strlen(msg_out)) 2297 printf("%s", msg_out); 2298 } 2299 2300 /* Close file */ 2301 fclose(f); 2302 free(msg_out); 2303 free(msg_in); 2304 return 0; 2305 } 2306