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, 10); 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_stats_help[] = 1260 "pipeline <pipeline_name> stats\n"; 1261 1262 static void 1263 cmd_pipeline_stats(char **tokens, 1264 uint32_t n_tokens, 1265 char *out, 1266 size_t out_size, 1267 void *obj) 1268 { 1269 struct rte_swx_ctl_pipeline_info info; 1270 struct pipeline *p; 1271 uint32_t i; 1272 int status; 1273 1274 if (n_tokens != 3) { 1275 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1276 return; 1277 } 1278 1279 p = pipeline_find(obj, tokens[1]); 1280 if (!p || !p->ctl) { 1281 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1282 return; 1283 } 1284 1285 if (strcmp(tokens[2], "stats")) { 1286 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1287 return; 1288 } 1289 1290 status = rte_swx_ctl_pipeline_info_get(p->p, &info); 1291 if (status) { 1292 snprintf(out, out_size, "Pipeline info get error."); 1293 return; 1294 } 1295 1296 snprintf(out, out_size, "Input ports:\n"); 1297 out_size -= strlen(out); 1298 out += strlen(out); 1299 1300 for (i = 0; i < info.n_ports_in; i++) { 1301 struct rte_swx_port_in_stats stats; 1302 1303 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats); 1304 1305 snprintf(out, out_size, "\tPort %u:" 1306 " packets %" PRIu64 1307 " bytes %" PRIu64 1308 " empty %" PRIu64 "\n", 1309 i, stats.n_pkts, stats.n_bytes, stats.n_empty); 1310 out_size -= strlen(out); 1311 out += strlen(out); 1312 } 1313 1314 snprintf(out, out_size, "Output ports:\n"); 1315 out_size -= strlen(out); 1316 out += strlen(out); 1317 1318 for (i = 0; i < info.n_ports_out; i++) { 1319 struct rte_swx_port_out_stats stats; 1320 1321 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); 1322 1323 snprintf(out, out_size, "\tPort %u:" 1324 " packets %" PRIu64 1325 " bytes %" PRIu64 "\n", 1326 i, stats.n_pkts, stats.n_bytes); 1327 out_size -= strlen(out); 1328 out += strlen(out); 1329 } 1330 } 1331 1332 static const char cmd_thread_pipeline_enable_help[] = 1333 "thread <thread_id> pipeline <pipeline_name> enable\n"; 1334 1335 static void 1336 cmd_thread_pipeline_enable(char **tokens, 1337 uint32_t n_tokens, 1338 char *out, 1339 size_t out_size, 1340 void *obj) 1341 { 1342 char *pipeline_name; 1343 struct pipeline *p; 1344 uint32_t thread_id; 1345 int status; 1346 1347 if (n_tokens != 5) { 1348 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1349 return; 1350 } 1351 1352 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 1353 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 1354 return; 1355 } 1356 1357 if (strcmp(tokens[2], "pipeline") != 0) { 1358 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 1359 return; 1360 } 1361 1362 pipeline_name = tokens[3]; 1363 p = pipeline_find(obj, pipeline_name); 1364 if (!p || !p->ctl) { 1365 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1366 return; 1367 } 1368 1369 if (strcmp(tokens[4], "enable") != 0) { 1370 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 1371 return; 1372 } 1373 1374 status = thread_pipeline_enable(thread_id, obj, pipeline_name); 1375 if (status) { 1376 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 1377 return; 1378 } 1379 } 1380 1381 static const char cmd_thread_pipeline_disable_help[] = 1382 "thread <thread_id> pipeline <pipeline_name> disable\n"; 1383 1384 static void 1385 cmd_thread_pipeline_disable(char **tokens, 1386 uint32_t n_tokens, 1387 char *out, 1388 size_t out_size, 1389 void *obj) 1390 { 1391 struct pipeline *p; 1392 char *pipeline_name; 1393 uint32_t thread_id; 1394 int status; 1395 1396 if (n_tokens != 5) { 1397 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1398 return; 1399 } 1400 1401 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 1402 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 1403 return; 1404 } 1405 1406 if (strcmp(tokens[2], "pipeline") != 0) { 1407 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 1408 return; 1409 } 1410 1411 pipeline_name = tokens[3]; 1412 p = pipeline_find(obj, pipeline_name); 1413 if (!p || !p->ctl) { 1414 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); 1415 return; 1416 } 1417 1418 if (strcmp(tokens[4], "disable") != 0) { 1419 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 1420 return; 1421 } 1422 1423 status = thread_pipeline_disable(thread_id, obj, pipeline_name); 1424 if (status) { 1425 snprintf(out, out_size, MSG_CMD_FAIL, 1426 "thread pipeline disable"); 1427 return; 1428 } 1429 } 1430 1431 static void 1432 cmd_help(char **tokens, 1433 uint32_t n_tokens, 1434 char *out, 1435 size_t out_size, 1436 void *arg __rte_unused) 1437 { 1438 tokens++; 1439 n_tokens--; 1440 1441 if (n_tokens == 0) { 1442 snprintf(out, out_size, 1443 "Type 'help <command>' for command details.\n\n" 1444 "List of commands:\n" 1445 "\tmempool\n" 1446 "\tlink\n" 1447 "\ttap\n" 1448 "\tpipeline create\n" 1449 "\tpipeline port in\n" 1450 "\tpipeline port out\n" 1451 "\tpipeline build\n" 1452 "\tpipeline table update\n" 1453 "\tpipeline stats\n" 1454 "\tthread pipeline enable\n" 1455 "\tthread pipeline disable\n\n"); 1456 return; 1457 } 1458 1459 if (strcmp(tokens[0], "mempool") == 0) { 1460 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 1461 return; 1462 } 1463 1464 if (strcmp(tokens[0], "link") == 0) { 1465 snprintf(out, out_size, "\n%s\n", cmd_link_help); 1466 return; 1467 } 1468 1469 if (strcmp(tokens[0], "ring") == 0) { 1470 snprintf(out, out_size, "\n%s\n", cmd_ring_help); 1471 return; 1472 } 1473 1474 if (strcmp(tokens[0], "tap") == 0) { 1475 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 1476 return; 1477 } 1478 1479 if ((strcmp(tokens[0], "pipeline") == 0) && 1480 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { 1481 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); 1482 return; 1483 } 1484 1485 if ((strcmp(tokens[0], "pipeline") == 0) && 1486 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) { 1487 if (strcmp(tokens[2], "in") == 0) { 1488 snprintf(out, out_size, "\n%s\n", 1489 cmd_pipeline_port_in_help); 1490 return; 1491 } 1492 1493 if (strcmp(tokens[2], "out") == 0) { 1494 snprintf(out, out_size, "\n%s\n", 1495 cmd_pipeline_port_out_help); 1496 return; 1497 } 1498 } 1499 1500 if ((strcmp(tokens[0], "pipeline") == 0) && 1501 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) { 1502 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help); 1503 return; 1504 } 1505 1506 if ((strcmp(tokens[0], "pipeline") == 0) && 1507 (n_tokens == 3) && 1508 (strcmp(tokens[1], "table") == 0) && 1509 (strcmp(tokens[2], "update") == 0)) { 1510 snprintf(out, out_size, "\n%s\n", 1511 cmd_pipeline_table_update_help); 1512 return; 1513 } 1514 1515 if ((strcmp(tokens[0], "pipeline") == 0) && 1516 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) { 1517 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help); 1518 return; 1519 } 1520 1521 if ((n_tokens == 3) && 1522 (strcmp(tokens[0], "thread") == 0) && 1523 (strcmp(tokens[1], "pipeline") == 0)) { 1524 if (strcmp(tokens[2], "enable") == 0) { 1525 snprintf(out, out_size, "\n%s\n", 1526 cmd_thread_pipeline_enable_help); 1527 return; 1528 } 1529 1530 if (strcmp(tokens[2], "disable") == 0) { 1531 snprintf(out, out_size, "\n%s\n", 1532 cmd_thread_pipeline_disable_help); 1533 return; 1534 } 1535 } 1536 1537 snprintf(out, out_size, "Invalid command\n"); 1538 } 1539 1540 void 1541 cli_process(char *in, char *out, size_t out_size, void *obj) 1542 { 1543 char *tokens[CMD_MAX_TOKENS]; 1544 uint32_t n_tokens = RTE_DIM(tokens); 1545 int status; 1546 1547 if (is_comment(in)) 1548 return; 1549 1550 status = parse_tokenize_string(in, tokens, &n_tokens); 1551 if (status) { 1552 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 1553 return; 1554 } 1555 1556 if (n_tokens == 0) 1557 return; 1558 1559 if (strcmp(tokens[0], "help") == 0) { 1560 cmd_help(tokens, n_tokens, out, out_size, obj); 1561 return; 1562 } 1563 1564 if (strcmp(tokens[0], "mempool") == 0) { 1565 cmd_mempool(tokens, n_tokens, out, out_size, obj); 1566 return; 1567 } 1568 1569 if (strcmp(tokens[0], "link") == 0) { 1570 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) { 1571 cmd_link_show(tokens, n_tokens, out, out_size, obj); 1572 return; 1573 } 1574 1575 cmd_link(tokens, n_tokens, out, out_size, obj); 1576 return; 1577 } 1578 1579 if (strcmp(tokens[0], "ring") == 0) { 1580 cmd_ring(tokens, n_tokens, out, out_size, obj); 1581 return; 1582 } 1583 1584 if (strcmp(tokens[0], "tap") == 0) { 1585 cmd_tap(tokens, n_tokens, out, out_size, obj); 1586 return; 1587 } 1588 1589 if (strcmp(tokens[0], "pipeline") == 0) { 1590 if ((n_tokens >= 3) && 1591 (strcmp(tokens[2], "create") == 0)) { 1592 cmd_pipeline_create(tokens, n_tokens, out, out_size, 1593 obj); 1594 return; 1595 } 1596 1597 if ((n_tokens >= 4) && 1598 (strcmp(tokens[2], "port") == 0) && 1599 (strcmp(tokens[3], "in") == 0)) { 1600 cmd_pipeline_port_in(tokens, n_tokens, out, out_size, 1601 obj); 1602 return; 1603 } 1604 1605 if ((n_tokens >= 4) && 1606 (strcmp(tokens[2], "port") == 0) && 1607 (strcmp(tokens[3], "out") == 0)) { 1608 cmd_pipeline_port_out(tokens, n_tokens, out, out_size, 1609 obj); 1610 return; 1611 } 1612 1613 if ((n_tokens >= 3) && 1614 (strcmp(tokens[2], "build") == 0)) { 1615 cmd_pipeline_build(tokens, n_tokens, out, out_size, 1616 obj); 1617 return; 1618 } 1619 1620 if ((n_tokens >= 3) && 1621 (strcmp(tokens[2], "table") == 0)) { 1622 cmd_pipeline_table_update(tokens, n_tokens, out, 1623 out_size, obj); 1624 return; 1625 } 1626 1627 if ((n_tokens >= 3) && 1628 (strcmp(tokens[2], "stats") == 0)) { 1629 cmd_pipeline_stats(tokens, n_tokens, out, out_size, 1630 obj); 1631 return; 1632 } 1633 } 1634 1635 if (strcmp(tokens[0], "thread") == 0) { 1636 if ((n_tokens >= 5) && 1637 (strcmp(tokens[4], "enable") == 0)) { 1638 cmd_thread_pipeline_enable(tokens, n_tokens, 1639 out, out_size, obj); 1640 return; 1641 } 1642 1643 if ((n_tokens >= 5) && 1644 (strcmp(tokens[4], "disable") == 0)) { 1645 cmd_thread_pipeline_disable(tokens, n_tokens, 1646 out, out_size, obj); 1647 return; 1648 } 1649 } 1650 1651 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 1652 } 1653 1654 int 1655 cli_script_process(const char *file_name, 1656 size_t msg_in_len_max, 1657 size_t msg_out_len_max, 1658 void *obj) 1659 { 1660 char *msg_in = NULL, *msg_out = NULL; 1661 FILE *f = NULL; 1662 1663 /* Check input arguments */ 1664 if ((file_name == NULL) || 1665 (strlen(file_name) == 0) || 1666 (msg_in_len_max == 0) || 1667 (msg_out_len_max == 0)) 1668 return -EINVAL; 1669 1670 msg_in = malloc(msg_in_len_max + 1); 1671 msg_out = malloc(msg_out_len_max + 1); 1672 if ((msg_in == NULL) || 1673 (msg_out == NULL)) { 1674 free(msg_out); 1675 free(msg_in); 1676 return -ENOMEM; 1677 } 1678 1679 /* Open input file */ 1680 f = fopen(file_name, "r"); 1681 if (f == NULL) { 1682 free(msg_out); 1683 free(msg_in); 1684 return -EIO; 1685 } 1686 1687 /* Read file */ 1688 for ( ; ; ) { 1689 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 1690 break; 1691 1692 printf("%s", msg_in); 1693 msg_out[0] = 0; 1694 1695 cli_process(msg_in, 1696 msg_out, 1697 msg_out_len_max, 1698 obj); 1699 1700 if (strlen(msg_out)) 1701 printf("%s", msg_out); 1702 } 1703 1704 /* Close file */ 1705 fclose(f); 1706 free(msg_out); 1707 free(msg_in); 1708 return 0; 1709 } 1710