1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2018 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_cycles.h> 12 13 #include "cli.h" 14 #include "kni.h" 15 #include "link.h" 16 #include "mempool.h" 17 #include "parser.h" 18 #include "pipeline.h" 19 #include "swq.h" 20 #include "tap.h" 21 #include "thread.h" 22 #include "tmgr.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 static int 41 is_comment(char *in) 42 { 43 if ((strlen(in) && index("!#%;", in[0])) || 44 (strncmp(in, "//", 2) == 0) || 45 (strncmp(in, "--", 2) == 0)) 46 return 1; 47 48 return 0; 49 } 50 51 /** 52 * mempool <mempool_name> 53 * buffer <buffer_size> 54 * pool <pool_size> 55 * cache <cache_size> 56 * cpu <cpu_id> 57 */ 58 static void 59 cmd_mempool(char **tokens, 60 uint32_t n_tokens, 61 char *out, 62 size_t out_size) 63 { 64 struct mempool_params p; 65 char *name; 66 struct mempool *mempool; 67 68 if (n_tokens != 10) { 69 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 70 return; 71 } 72 73 name = tokens[1]; 74 75 if (strcmp(tokens[2], "buffer") != 0) { 76 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer"); 77 return; 78 } 79 80 if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) { 81 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size"); 82 return; 83 } 84 85 if (strcmp(tokens[4], "pool") != 0) { 86 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool"); 87 return; 88 } 89 90 if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) { 91 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size"); 92 return; 93 } 94 95 if (strcmp(tokens[6], "cache") != 0) { 96 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); 97 return; 98 } 99 100 if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) { 101 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); 102 return; 103 } 104 105 if (strcmp(tokens[8], "cpu") != 0) { 106 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 107 return; 108 } 109 110 if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) { 111 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 112 return; 113 } 114 115 mempool = mempool_create(name, &p); 116 if (mempool == NULL) { 117 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 118 return; 119 } 120 } 121 122 /** 123 * link <link_name> 124 * dev <device_name> | port <port_id> 125 * rxq <n_queues> <queue_size> <mempool_name> 126 * txq <n_queues> <queue_size> 127 * promiscuous on | off 128 * [rss <qid_0> ... <qid_n>] 129 */ 130 static void 131 cmd_link(char **tokens, 132 uint32_t n_tokens, 133 char *out, 134 size_t out_size) 135 { 136 struct link_params p; 137 struct link_params_rss rss; 138 struct link *link; 139 char *name; 140 141 memset(&p, 0, sizeof(p)); 142 143 if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) { 144 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 145 return; 146 } 147 name = tokens[1]; 148 149 if (strcmp(tokens[2], "dev") == 0) 150 p.dev_name = tokens[3]; 151 else if (strcmp(tokens[2], "port") == 0) { 152 p.dev_name = NULL; 153 154 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) { 155 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 156 return; 157 } 158 } else { 159 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port"); 160 return; 161 } 162 163 if (strcmp(tokens[4], "rxq") != 0) { 164 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 165 return; 166 } 167 168 if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) { 169 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 170 return; 171 } 172 if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) { 173 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 174 return; 175 } 176 177 p.rx.mempool_name = tokens[7]; 178 179 if (strcmp(tokens[8], "txq") != 0) { 180 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 181 return; 182 } 183 184 if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) { 185 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 186 return; 187 } 188 189 if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) { 190 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 191 return; 192 } 193 194 if (strcmp(tokens[11], "promiscuous") != 0) { 195 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous"); 196 return; 197 } 198 199 if (strcmp(tokens[12], "on") == 0) 200 p.promiscuous = 1; 201 else if (strcmp(tokens[12], "off") == 0) 202 p.promiscuous = 0; 203 else { 204 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off"); 205 return; 206 } 207 208 /* RSS */ 209 p.rx.rss = NULL; 210 if (n_tokens > 13) { 211 uint32_t queue_id, i; 212 213 if (strcmp(tokens[13], "rss") != 0) { 214 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss"); 215 return; 216 } 217 218 p.rx.rss = &rss; 219 220 rss.n_queues = 0; 221 for (i = 14; i < n_tokens; i++) { 222 if (parser_read_uint32(&queue_id, tokens[i]) != 0) { 223 snprintf(out, out_size, MSG_ARG_INVALID, 224 "queue_id"); 225 return; 226 } 227 228 rss.queue_id[rss.n_queues] = queue_id; 229 rss.n_queues++; 230 } 231 } 232 233 link = link_create(name, &p); 234 if (link == NULL) { 235 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 236 return; 237 } 238 } 239 240 /** 241 * swq <swq_name> 242 * size <size> 243 * cpu <cpu_id> 244 */ 245 static void 246 cmd_swq(char **tokens, 247 uint32_t n_tokens, 248 char *out, 249 size_t out_size) 250 { 251 struct swq_params p; 252 char *name; 253 struct swq *swq; 254 255 if (n_tokens != 6) { 256 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 257 return; 258 } 259 260 name = tokens[1]; 261 262 if (strcmp(tokens[2], "size") != 0) { 263 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 264 return; 265 } 266 267 if (parser_read_uint32(&p.size, tokens[3]) != 0) { 268 snprintf(out, out_size, MSG_ARG_INVALID, "size"); 269 return; 270 } 271 272 if (strcmp(tokens[4], "cpu") != 0) { 273 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 274 return; 275 } 276 277 if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) { 278 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 279 return; 280 } 281 282 swq = swq_create(name, &p); 283 if (swq == NULL) { 284 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 285 return; 286 } 287 } 288 289 /** 290 * tmgr subport profile 291 * <tb_rate> <tb_size> 292 * <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> 293 * <tc_period> 294 */ 295 static void 296 cmd_tmgr_subport_profile(char **tokens, 297 uint32_t n_tokens, 298 char *out, 299 size_t out_size) 300 { 301 struct rte_sched_subport_params p; 302 int status, i; 303 304 if (n_tokens != 10) { 305 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 306 return; 307 } 308 309 if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) { 310 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); 311 return; 312 } 313 314 if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) { 315 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); 316 return; 317 } 318 319 for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) 320 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) { 321 snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate"); 322 return; 323 } 324 325 if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) { 326 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period"); 327 return; 328 } 329 330 status = tmgr_subport_profile_add(&p); 331 if (status != 0) { 332 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 333 return; 334 } 335 } 336 337 /** 338 * tmgr pipe profile 339 * <tb_rate> <tb_size> 340 * <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> 341 * <tc_period> 342 * <tc_ov_weight> 343 * <wrr_weight0..15> 344 */ 345 static void 346 cmd_tmgr_pipe_profile(char **tokens, 347 uint32_t n_tokens, 348 char *out, 349 size_t out_size) 350 { 351 struct rte_sched_pipe_params p; 352 int status, i; 353 354 if (n_tokens != 27) { 355 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 356 return; 357 } 358 359 if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) { 360 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); 361 return; 362 } 363 364 if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) { 365 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); 366 return; 367 } 368 369 for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) 370 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) { 371 snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate"); 372 return; 373 } 374 375 if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) { 376 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period"); 377 return; 378 } 379 380 #ifdef RTE_SCHED_SUBPORT_TC_OV 381 if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) { 382 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight"); 383 return; 384 } 385 #endif 386 387 for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++) 388 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) { 389 snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights"); 390 return; 391 } 392 393 status = tmgr_pipe_profile_add(&p); 394 if (status != 0) { 395 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 396 return; 397 } 398 } 399 400 /** 401 * tmgr <tmgr_name> 402 * rate <rate> 403 * spp <n_subports_per_port> 404 * pps <n_pipes_per_subport> 405 * qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3> 406 * fo <frame_overhead> 407 * mtu <mtu> 408 * cpu <cpu_id> 409 */ 410 static void 411 cmd_tmgr(char **tokens, 412 uint32_t n_tokens, 413 char *out, 414 size_t out_size) 415 { 416 struct tmgr_port_params p; 417 char *name; 418 struct tmgr_port *tmgr_port; 419 int i; 420 421 if (n_tokens != 19) { 422 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 423 return; 424 } 425 426 name = tokens[1]; 427 428 if (strcmp(tokens[2], "rate") != 0) { 429 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate"); 430 return; 431 } 432 433 if (parser_read_uint32(&p.rate, tokens[3]) != 0) { 434 snprintf(out, out_size, MSG_ARG_INVALID, "rate"); 435 return; 436 } 437 438 if (strcmp(tokens[4], "spp") != 0) { 439 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 440 return; 441 } 442 443 if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) { 444 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); 445 return; 446 } 447 448 if (strcmp(tokens[6], "pps") != 0) { 449 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); 450 return; 451 } 452 453 if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) { 454 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); 455 return; 456 } 457 458 if (strcmp(tokens[8], "qsize") != 0) { 459 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize"); 460 return; 461 } 462 463 for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) 464 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) { 465 snprintf(out, out_size, MSG_ARG_INVALID, "qsize"); 466 return; 467 } 468 469 if (strcmp(tokens[13], "fo") != 0) { 470 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo"); 471 return; 472 } 473 474 if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) { 475 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead"); 476 return; 477 } 478 479 if (strcmp(tokens[15], "mtu") != 0) { 480 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu"); 481 return; 482 } 483 484 if (parser_read_uint32(&p.mtu, tokens[16]) != 0) { 485 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 486 return; 487 } 488 489 if (strcmp(tokens[17], "cpu") != 0) { 490 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 491 return; 492 } 493 494 if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) { 495 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 496 return; 497 } 498 499 tmgr_port = tmgr_port_create(name, &p); 500 if (tmgr_port == NULL) { 501 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 502 return; 503 } 504 } 505 506 /** 507 * tmgr <tmgr_name> subport <subport_id> 508 * profile <subport_profile_id> 509 */ 510 static void 511 cmd_tmgr_subport(char **tokens, 512 uint32_t n_tokens, 513 char *out, 514 size_t out_size) 515 { 516 uint32_t subport_id, subport_profile_id; 517 int status; 518 char *name; 519 520 if (n_tokens != 6) { 521 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 522 return; 523 } 524 525 name = tokens[1]; 526 527 if (parser_read_uint32(&subport_id, tokens[3]) != 0) { 528 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id"); 529 return; 530 } 531 532 if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) { 533 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id"); 534 return; 535 } 536 537 status = tmgr_subport_config(name, subport_id, subport_profile_id); 538 if (status) { 539 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 540 return; 541 } 542 } 543 544 /** 545 * tmgr <tmgr_name> subport <subport_id> pipe 546 * from <pipe_id_first> to <pipe_id_last> 547 * profile <pipe_profile_id> 548 */ 549 static void 550 cmd_tmgr_subport_pipe(char **tokens, 551 uint32_t n_tokens, 552 char *out, 553 size_t out_size) 554 { 555 uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id; 556 int status; 557 char *name; 558 559 if (n_tokens != 11) { 560 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 561 return; 562 } 563 564 name = tokens[1]; 565 566 if (parser_read_uint32(&subport_id, tokens[3]) != 0) { 567 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id"); 568 return; 569 } 570 571 if (strcmp(tokens[4], "pipe") != 0) { 572 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe"); 573 return; 574 } 575 576 if (strcmp(tokens[5], "from") != 0) { 577 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 578 return; 579 } 580 581 if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) { 582 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first"); 583 return; 584 } 585 586 if (strcmp(tokens[7], "to") != 0) { 587 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 588 return; 589 } 590 591 if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) { 592 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last"); 593 return; 594 } 595 596 if (strcmp(tokens[9], "profile") != 0) { 597 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 598 return; 599 } 600 601 if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) { 602 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id"); 603 return; 604 } 605 606 status = tmgr_pipe_config(name, subport_id, pipe_id_first, 607 pipe_id_last, pipe_profile_id); 608 if (status) { 609 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 610 return; 611 } 612 } 613 614 /** 615 * tap <tap_name> 616 */ 617 static void 618 cmd_tap(char **tokens, 619 uint32_t n_tokens, 620 char *out, 621 size_t out_size) 622 { 623 char *name; 624 struct tap *tap; 625 626 if (n_tokens != 2) { 627 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 628 return; 629 } 630 631 name = tokens[1]; 632 633 tap = tap_create(name); 634 if (tap == NULL) { 635 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 636 return; 637 } 638 } 639 640 /** 641 * kni <kni_name> 642 * link <link_name> 643 * mempool <mempool_name> 644 * [thread <thread_id>] 645 */ 646 static void 647 cmd_kni(char **tokens, 648 uint32_t n_tokens, 649 char *out, 650 size_t out_size) 651 { 652 struct kni_params p; 653 char *name; 654 struct kni *kni; 655 656 memset(&p, 0, sizeof(p)); 657 if ((n_tokens != 6) && (n_tokens != 8)) { 658 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 659 return; 660 } 661 662 name = tokens[1]; 663 664 if (strcmp(tokens[2], "link") != 0) { 665 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link"); 666 return; 667 } 668 669 p.link_name = tokens[3]; 670 671 if (strcmp(tokens[4], "mempool") != 0) { 672 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool"); 673 return; 674 } 675 676 p.mempool_name = tokens[5]; 677 678 if (n_tokens == 8) { 679 if (strcmp(tokens[6], "thread") != 0) { 680 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread"); 681 return; 682 } 683 684 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) { 685 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 686 return; 687 } 688 689 p.force_bind = 1; 690 } else 691 p.force_bind = 0; 692 693 kni = kni_create(name, &p); 694 if (kni == NULL) { 695 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 696 return; 697 } 698 } 699 700 /** 701 * port in action profile <profile_name> 702 * [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>] 703 * [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>] 704 */ 705 static void 706 cmd_port_in_action_profile(char **tokens, 707 uint32_t n_tokens, 708 char *out, 709 size_t out_size) 710 { 711 struct port_in_action_profile_params p; 712 struct port_in_action_profile *ap; 713 char *name; 714 uint32_t t0; 715 716 memset(&p, 0, sizeof(p)); 717 718 if (n_tokens < 5) { 719 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 720 return; 721 } 722 723 if (strcmp(tokens[1], "in") != 0) { 724 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 725 return; 726 } 727 728 if (strcmp(tokens[2], "action") != 0) { 729 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); 730 return; 731 } 732 733 if (strcmp(tokens[3], "profile") != 0) { 734 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 735 return; 736 } 737 738 name = tokens[4]; 739 740 t0 = 5; 741 742 if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) { 743 uint32_t size; 744 745 if (n_tokens < t0 + 10) { 746 snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter"); 747 return; 748 } 749 750 if (strcmp(tokens[t0 + 1], "match") == 0) 751 p.fltr.filter_on_match = 1; 752 else if (strcmp(tokens[t0 + 1], "mismatch") == 0) 753 p.fltr.filter_on_match = 0; 754 else { 755 snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch"); 756 return; 757 } 758 759 if (strcmp(tokens[t0 + 2], "offset") != 0) { 760 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 761 return; 762 } 763 764 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) { 765 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 766 return; 767 } 768 769 if (strcmp(tokens[t0 + 4], "mask") != 0) { 770 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 771 return; 772 } 773 774 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; 775 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) || 776 (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) { 777 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 778 return; 779 } 780 781 if (strcmp(tokens[t0 + 6], "key") != 0) { 782 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 783 return; 784 } 785 786 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; 787 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) || 788 (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) { 789 snprintf(out, out_size, MSG_ARG_INVALID, "key_value"); 790 return; 791 } 792 793 if (strcmp(tokens[t0 + 8], "port") != 0) { 794 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 795 return; 796 } 797 798 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) { 799 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 800 return; 801 } 802 803 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR; 804 t0 += 10; 805 } /* filter */ 806 807 if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) { 808 uint32_t i; 809 810 if (n_tokens < t0 + 22) { 811 snprintf(out, out_size, MSG_ARG_MISMATCH, 812 "port in action profile balance"); 813 return; 814 } 815 816 if (strcmp(tokens[t0 + 1], "offset") != 0) { 817 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 818 return; 819 } 820 821 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { 822 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 823 return; 824 } 825 826 if (strcmp(tokens[t0 + 3], "mask") != 0) { 827 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 828 return; 829 } 830 831 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; 832 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) { 833 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 834 return; 835 } 836 837 if (strcmp(tokens[t0 + 5], "port") != 0) { 838 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 839 return; 840 } 841 842 for (i = 0; i < 16; i++) 843 if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) { 844 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 845 return; 846 } 847 848 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB; 849 t0 += 22; 850 } /* balance */ 851 852 if (t0 < n_tokens) { 853 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 854 return; 855 } 856 857 ap = port_in_action_profile_create(name, &p); 858 if (ap == NULL) { 859 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 860 return; 861 } 862 } 863 864 /** 865 * table action profile <profile_name> 866 * ipv4 | ipv6 867 * offset <ip_offset> 868 * fwd 869 * [balance offset <key_offset> mask <key_mask> outoffset <out_offset>] 870 * [meter srtcm | trtcm 871 * tc <n_tc> 872 * stats none | pkts | bytes | both] 873 * [tm spp <n_subports_per_port> pps <n_pipes_per_subport>] 874 * [encap ether | vlan | qinq | mpls | pppoe] 875 * [nat src | dst 876 * proto udp | tcp] 877 * [ttl drop | fwd 878 * stats none | pkts] 879 * [stats pkts | bytes | both] 880 * [time] 881 */ 882 static void 883 cmd_table_action_profile(char **tokens, 884 uint32_t n_tokens, 885 char *out, 886 size_t out_size) 887 { 888 struct table_action_profile_params p; 889 struct table_action_profile *ap; 890 char *name; 891 uint32_t t0; 892 893 memset(&p, 0, sizeof(p)); 894 895 if (n_tokens < 8) { 896 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 897 return; 898 } 899 900 if (strcmp(tokens[1], "action") != 0) { 901 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); 902 return; 903 } 904 905 if (strcmp(tokens[2], "profile") != 0) { 906 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 907 return; 908 } 909 910 name = tokens[3]; 911 912 if (strcmp(tokens[4], "ipv4") == 0) 913 p.common.ip_version = 1; 914 else if (strcmp(tokens[4], "ipv6") == 0) 915 p.common.ip_version = 0; 916 else { 917 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6"); 918 return; 919 } 920 921 if (strcmp(tokens[5], "offset") != 0) { 922 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 923 return; 924 } 925 926 if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) { 927 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset"); 928 return; 929 } 930 931 if (strcmp(tokens[7], "fwd") != 0) { 932 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); 933 return; 934 } 935 936 p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; 937 938 t0 = 8; 939 if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) { 940 if (n_tokens < t0 + 7) { 941 snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance"); 942 return; 943 } 944 945 if (strcmp(tokens[t0 + 1], "offset") != 0) { 946 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 947 return; 948 } 949 950 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { 951 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 952 return; 953 } 954 955 if (strcmp(tokens[t0 + 3], "mask") != 0) { 956 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 957 return; 958 } 959 960 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; 961 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) { 962 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 963 return; 964 } 965 966 if (strcmp(tokens[t0 + 5], "outoffset") != 0) { 967 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); 968 return; 969 } 970 971 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) { 972 snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); 973 return; 974 } 975 976 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; 977 t0 += 7; 978 } /* balance */ 979 980 if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) { 981 if (n_tokens < t0 + 6) { 982 snprintf(out, out_size, MSG_ARG_MISMATCH, 983 "table action profile meter"); 984 return; 985 } 986 987 if (strcmp(tokens[t0 + 1], "srtcm") == 0) 988 p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM; 989 else if (strcmp(tokens[t0 + 1], "trtcm") == 0) 990 p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM; 991 else { 992 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 993 "srtcm or trtcm"); 994 return; 995 } 996 997 if (strcmp(tokens[t0 + 2], "tc") != 0) { 998 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); 999 return; 1000 } 1001 1002 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) { 1003 snprintf(out, out_size, MSG_ARG_INVALID, "n_tc"); 1004 return; 1005 } 1006 1007 if (strcmp(tokens[t0 + 4], "stats") != 0) { 1008 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1009 return; 1010 } 1011 1012 if (strcmp(tokens[t0 + 5], "none") == 0) { 1013 p.mtr.n_packets_enabled = 0; 1014 p.mtr.n_bytes_enabled = 0; 1015 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) { 1016 p.mtr.n_packets_enabled = 1; 1017 p.mtr.n_bytes_enabled = 0; 1018 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) { 1019 p.mtr.n_packets_enabled = 0; 1020 p.mtr.n_bytes_enabled = 1; 1021 } else if (strcmp(tokens[t0 + 5], "both") == 0) { 1022 p.mtr.n_packets_enabled = 1; 1023 p.mtr.n_bytes_enabled = 1; 1024 } else { 1025 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1026 "none or pkts or bytes or both"); 1027 return; 1028 } 1029 1030 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR; 1031 t0 += 6; 1032 } /* meter */ 1033 1034 if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) { 1035 if (n_tokens < t0 + 5) { 1036 snprintf(out, out_size, MSG_ARG_MISMATCH, 1037 "table action profile tm"); 1038 return; 1039 } 1040 1041 if (strcmp(tokens[t0 + 1], "spp") != 0) { 1042 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 1043 return; 1044 } 1045 1046 if (parser_read_uint32(&p.tm.n_subports_per_port, 1047 tokens[t0 + 2]) != 0) { 1048 snprintf(out, out_size, MSG_ARG_INVALID, 1049 "n_subports_per_port"); 1050 return; 1051 } 1052 1053 if (strcmp(tokens[t0 + 3], "pps") != 0) { 1054 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); 1055 return; 1056 } 1057 1058 if (parser_read_uint32(&p.tm.n_pipes_per_subport, 1059 tokens[t0 + 4]) != 0) { 1060 snprintf(out, out_size, MSG_ARG_INVALID, 1061 "n_pipes_per_subport"); 1062 return; 1063 } 1064 1065 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; 1066 t0 += 5; 1067 } /* tm */ 1068 1069 if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) { 1070 if (n_tokens < t0 + 2) { 1071 snprintf(out, out_size, MSG_ARG_MISMATCH, 1072 "action profile encap"); 1073 return; 1074 } 1075 1076 if (strcmp(tokens[t0 + 1], "ether") == 0) 1077 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER; 1078 else if (strcmp(tokens[t0 + 1], "vlan") == 0) 1079 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN; 1080 else if (strcmp(tokens[t0 + 1], "qinq") == 0) 1081 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ; 1082 else if (strcmp(tokens[t0 + 1], "mpls") == 0) 1083 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; 1084 else if (strcmp(tokens[t0 + 1], "pppoe") == 0) 1085 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; 1086 else { 1087 snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); 1088 return; 1089 } 1090 1091 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; 1092 t0 += 2; 1093 } /* encap */ 1094 1095 if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) { 1096 if (n_tokens < t0 + 4) { 1097 snprintf(out, out_size, MSG_ARG_MISMATCH, 1098 "table action profile nat"); 1099 return; 1100 } 1101 1102 if (strcmp(tokens[t0 + 1], "src") == 0) 1103 p.nat.source_nat = 1; 1104 else if (strcmp(tokens[t0 + 1], "dst") == 0) 1105 p.nat.source_nat = 0; 1106 else { 1107 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1108 "src or dst"); 1109 return; 1110 } 1111 1112 if (strcmp(tokens[t0 + 2], "proto") != 0) { 1113 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); 1114 return; 1115 } 1116 1117 if (strcmp(tokens[t0 + 3], "tcp") == 0) 1118 p.nat.proto = 0x06; 1119 else if (strcmp(tokens[t0 + 3], "udp") == 0) 1120 p.nat.proto = 0x11; 1121 else { 1122 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1123 "tcp or udp"); 1124 return; 1125 } 1126 1127 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT; 1128 t0 += 4; 1129 } /* nat */ 1130 1131 if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) { 1132 if (n_tokens < t0 + 4) { 1133 snprintf(out, out_size, MSG_ARG_MISMATCH, 1134 "table action profile ttl"); 1135 return; 1136 } 1137 1138 if (strcmp(tokens[t0 + 1], "drop") == 0) 1139 p.ttl.drop = 1; 1140 else if (strcmp(tokens[t0 + 1], "fwd") == 0) 1141 p.ttl.drop = 0; 1142 else { 1143 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1144 "drop or fwd"); 1145 return; 1146 } 1147 1148 if (strcmp(tokens[t0 + 2], "stats") != 0) { 1149 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1150 return; 1151 } 1152 1153 if (strcmp(tokens[t0 + 3], "none") == 0) 1154 p.ttl.n_packets_enabled = 0; 1155 else if (strcmp(tokens[t0 + 3], "pkts") == 0) 1156 p.ttl.n_packets_enabled = 1; 1157 else { 1158 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1159 "none or pkts"); 1160 return; 1161 } 1162 1163 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL; 1164 t0 += 4; 1165 } /* ttl */ 1166 1167 if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) { 1168 if (n_tokens < t0 + 2) { 1169 snprintf(out, out_size, MSG_ARG_MISMATCH, 1170 "table action profile stats"); 1171 return; 1172 } 1173 1174 if (strcmp(tokens[t0 + 1], "pkts") == 0) { 1175 p.stats.n_packets_enabled = 1; 1176 p.stats.n_bytes_enabled = 0; 1177 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) { 1178 p.stats.n_packets_enabled = 0; 1179 p.stats.n_bytes_enabled = 1; 1180 } else if (strcmp(tokens[t0 + 1], "both") == 0) { 1181 p.stats.n_packets_enabled = 1; 1182 p.stats.n_bytes_enabled = 1; 1183 } else { 1184 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1185 "pkts or bytes or both"); 1186 return; 1187 } 1188 1189 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS; 1190 t0 += 2; 1191 } /* stats */ 1192 1193 if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) { 1194 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME; 1195 t0 += 1; 1196 } /* time */ 1197 1198 if (t0 < n_tokens) { 1199 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1200 return; 1201 } 1202 1203 ap = table_action_profile_create(name, &p); 1204 if (ap == NULL) { 1205 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1206 return; 1207 } 1208 } 1209 1210 /** 1211 * pipeline <pipeline_name> 1212 * period <timer_period_ms> 1213 * offset_port_id <offset_port_id> 1214 * cpu <cpu_id> 1215 */ 1216 static void 1217 cmd_pipeline(char **tokens, 1218 uint32_t n_tokens, 1219 char *out, 1220 size_t out_size) 1221 { 1222 struct pipeline_params p; 1223 char *name; 1224 struct pipeline *pipeline; 1225 1226 if (n_tokens != 8) { 1227 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1228 return; 1229 } 1230 1231 name = tokens[1]; 1232 1233 if (strcmp(tokens[2], "period") != 0) { 1234 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); 1235 return; 1236 } 1237 1238 if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) { 1239 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); 1240 return; 1241 } 1242 1243 if (strcmp(tokens[4], "offset_port_id") != 0) { 1244 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); 1245 return; 1246 } 1247 1248 if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) { 1249 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); 1250 return; 1251 } 1252 1253 if (strcmp(tokens[6], "cpu") != 0) { 1254 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 1255 return; 1256 } 1257 1258 if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) { 1259 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 1260 return; 1261 } 1262 1263 pipeline = pipeline_create(name, &p); 1264 if (pipeline == NULL) { 1265 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1266 return; 1267 } 1268 } 1269 1270 /** 1271 * pipeline <pipeline_name> port in 1272 * bsz <burst_size> 1273 * link <link_name> rxq <queue_id> 1274 * | swq <swq_name> 1275 * | tmgr <tmgr_name> 1276 * | tap <tap_name> mempool <mempool_name> mtu <mtu> 1277 * | kni <kni_name> 1278 * | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt> 1279 * [action <port_in_action_profile_name>] 1280 * [disabled] 1281 */ 1282 static void 1283 cmd_pipeline_port_in(char **tokens, 1284 uint32_t n_tokens, 1285 char *out, 1286 size_t out_size) 1287 { 1288 struct port_in_params p; 1289 char *pipeline_name; 1290 uint32_t t0; 1291 int enabled, status; 1292 1293 if (n_tokens < 7) { 1294 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1295 return; 1296 } 1297 1298 pipeline_name = tokens[1]; 1299 1300 if (strcmp(tokens[2], "port") != 0) { 1301 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1302 return; 1303 } 1304 1305 if (strcmp(tokens[3], "in") != 0) { 1306 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 1307 return; 1308 } 1309 1310 if (strcmp(tokens[4], "bsz") != 0) { 1311 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 1312 return; 1313 } 1314 1315 if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 1316 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 1317 return; 1318 } 1319 1320 t0 = 6; 1321 1322 if (strcmp(tokens[t0], "link") == 0) { 1323 if (n_tokens < t0 + 4) { 1324 snprintf(out, out_size, MSG_ARG_MISMATCH, 1325 "pipeline port in link"); 1326 return; 1327 } 1328 1329 p.type = PORT_IN_RXQ; 1330 1331 p.dev_name = tokens[t0 + 1]; 1332 1333 if (strcmp(tokens[t0 + 2], "rxq") != 0) { 1334 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 1335 return; 1336 } 1337 1338 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) { 1339 snprintf(out, out_size, MSG_ARG_INVALID, 1340 "queue_id"); 1341 return; 1342 } 1343 t0 += 4; 1344 } else if (strcmp(tokens[t0], "swq") == 0) { 1345 if (n_tokens < t0 + 2) { 1346 snprintf(out, out_size, MSG_ARG_MISMATCH, 1347 "pipeline port in swq"); 1348 return; 1349 } 1350 1351 p.type = PORT_IN_SWQ; 1352 1353 p.dev_name = tokens[t0 + 1]; 1354 1355 t0 += 2; 1356 } else if (strcmp(tokens[t0], "tmgr") == 0) { 1357 if (n_tokens < t0 + 2) { 1358 snprintf(out, out_size, MSG_ARG_MISMATCH, 1359 "pipeline port in tmgr"); 1360 return; 1361 } 1362 1363 p.type = PORT_IN_TMGR; 1364 1365 p.dev_name = tokens[t0 + 1]; 1366 1367 t0 += 2; 1368 } else if (strcmp(tokens[t0], "tap") == 0) { 1369 if (n_tokens < t0 + 6) { 1370 snprintf(out, out_size, MSG_ARG_MISMATCH, 1371 "pipeline port in tap"); 1372 return; 1373 } 1374 1375 p.type = PORT_IN_TAP; 1376 1377 p.dev_name = tokens[t0 + 1]; 1378 1379 if (strcmp(tokens[t0 + 2], "mempool") != 0) { 1380 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1381 "mempool"); 1382 return; 1383 } 1384 1385 p.tap.mempool_name = tokens[t0 + 3]; 1386 1387 if (strcmp(tokens[t0 + 4], "mtu") != 0) { 1388 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1389 "mtu"); 1390 return; 1391 } 1392 1393 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) { 1394 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 1395 return; 1396 } 1397 1398 t0 += 6; 1399 } else if (strcmp(tokens[t0], "kni") == 0) { 1400 if (n_tokens < t0 + 2) { 1401 snprintf(out, out_size, MSG_ARG_MISMATCH, 1402 "pipeline port in kni"); 1403 return; 1404 } 1405 1406 p.type = PORT_IN_KNI; 1407 1408 p.dev_name = tokens[t0 + 1]; 1409 1410 t0 += 2; 1411 } else if (strcmp(tokens[t0], "source") == 0) { 1412 if (n_tokens < t0 + 6) { 1413 snprintf(out, out_size, MSG_ARG_MISMATCH, 1414 "pipeline port in source"); 1415 return; 1416 } 1417 1418 p.type = PORT_IN_SOURCE; 1419 1420 p.dev_name = NULL; 1421 1422 if (strcmp(tokens[t0 + 1], "mempool") != 0) { 1423 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1424 "mempool"); 1425 return; 1426 } 1427 1428 p.source.mempool_name = tokens[t0 + 2]; 1429 1430 if (strcmp(tokens[t0 + 3], "file") != 0) { 1431 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1432 "file"); 1433 return; 1434 } 1435 1436 p.source.file_name = tokens[t0 + 4]; 1437 1438 if (strcmp(tokens[t0 + 5], "bpp") != 0) { 1439 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1440 "bpp"); 1441 return; 1442 } 1443 1444 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) { 1445 snprintf(out, out_size, MSG_ARG_INVALID, 1446 "n_bytes_per_pkt"); 1447 return; 1448 } 1449 1450 t0 += 7; 1451 } else { 1452 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1453 return; 1454 } 1455 1456 p.action_profile_name = NULL; 1457 if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) { 1458 if (n_tokens < t0 + 2) { 1459 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 1460 return; 1461 } 1462 1463 p.action_profile_name = tokens[t0 + 1]; 1464 1465 t0 += 2; 1466 } 1467 1468 enabled = 1; 1469 if ((n_tokens > t0) && 1470 (strcmp(tokens[t0], "disabled") == 0)) { 1471 enabled = 0; 1472 1473 t0 += 1; 1474 } 1475 1476 if (n_tokens != t0) { 1477 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1478 return; 1479 } 1480 1481 status = pipeline_port_in_create(pipeline_name, 1482 &p, enabled); 1483 if (status) { 1484 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1485 return; 1486 } 1487 } 1488 1489 /** 1490 * pipeline <pipeline_name> port out 1491 * bsz <burst_size> 1492 * link <link_name> txq <txq_id> 1493 * | swq <swq_name> 1494 * | tmgr <tmgr_name> 1495 * | tap <tap_name> 1496 * | kni <kni_name> 1497 * | sink [file <file_name> pkts <max_n_pkts>] 1498 */ 1499 static void 1500 cmd_pipeline_port_out(char **tokens, 1501 uint32_t n_tokens, 1502 char *out, 1503 size_t out_size) 1504 { 1505 struct port_out_params p; 1506 char *pipeline_name; 1507 int status; 1508 1509 memset(&p, 0, sizeof(p)); 1510 1511 if (n_tokens < 7) { 1512 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1513 return; 1514 } 1515 1516 pipeline_name = tokens[1]; 1517 1518 if (strcmp(tokens[2], "port") != 0) { 1519 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1520 return; 1521 } 1522 1523 if (strcmp(tokens[3], "out") != 0) { 1524 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 1525 return; 1526 } 1527 1528 if (strcmp(tokens[4], "bsz") != 0) { 1529 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 1530 return; 1531 } 1532 1533 if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 1534 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 1535 return; 1536 } 1537 1538 if (strcmp(tokens[6], "link") == 0) { 1539 if (n_tokens != 10) { 1540 snprintf(out, out_size, MSG_ARG_MISMATCH, 1541 "pipeline port out link"); 1542 return; 1543 } 1544 1545 p.type = PORT_OUT_TXQ; 1546 1547 p.dev_name = tokens[7]; 1548 1549 if (strcmp(tokens[8], "txq") != 0) { 1550 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 1551 return; 1552 } 1553 1554 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) { 1555 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 1556 return; 1557 } 1558 } else if (strcmp(tokens[6], "swq") == 0) { 1559 if (n_tokens != 8) { 1560 snprintf(out, out_size, MSG_ARG_MISMATCH, 1561 "pipeline port out swq"); 1562 return; 1563 } 1564 1565 p.type = PORT_OUT_SWQ; 1566 1567 p.dev_name = tokens[7]; 1568 } else if (strcmp(tokens[6], "tmgr") == 0) { 1569 if (n_tokens != 8) { 1570 snprintf(out, out_size, MSG_ARG_MISMATCH, 1571 "pipeline port out tmgr"); 1572 return; 1573 } 1574 1575 p.type = PORT_OUT_TMGR; 1576 1577 p.dev_name = tokens[7]; 1578 } else if (strcmp(tokens[6], "tap") == 0) { 1579 if (n_tokens != 8) { 1580 snprintf(out, out_size, MSG_ARG_MISMATCH, 1581 "pipeline port out tap"); 1582 return; 1583 } 1584 1585 p.type = PORT_OUT_TAP; 1586 1587 p.dev_name = tokens[7]; 1588 } else if (strcmp(tokens[6], "kni") == 0) { 1589 if (n_tokens != 8) { 1590 snprintf(out, out_size, MSG_ARG_MISMATCH, 1591 "pipeline port out kni"); 1592 return; 1593 } 1594 1595 p.type = PORT_OUT_KNI; 1596 1597 p.dev_name = tokens[7]; 1598 } else if (strcmp(tokens[6], "sink") == 0) { 1599 if ((n_tokens != 7) && (n_tokens != 11)) { 1600 snprintf(out, out_size, MSG_ARG_MISMATCH, 1601 "pipeline port out sink"); 1602 return; 1603 } 1604 1605 p.type = PORT_OUT_SINK; 1606 1607 p.dev_name = NULL; 1608 1609 if (n_tokens == 7) { 1610 p.sink.file_name = NULL; 1611 p.sink.max_n_pkts = 0; 1612 } else { 1613 if (strcmp(tokens[7], "file") != 0) { 1614 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1615 "file"); 1616 return; 1617 } 1618 1619 p.sink.file_name = tokens[8]; 1620 1621 if (strcmp(tokens[9], "pkts") != 0) { 1622 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); 1623 return; 1624 } 1625 1626 if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) { 1627 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); 1628 return; 1629 } 1630 } 1631 } else { 1632 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1633 return; 1634 } 1635 1636 status = pipeline_port_out_create(pipeline_name, &p); 1637 if (status) { 1638 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1639 return; 1640 } 1641 } 1642 1643 /** 1644 * pipeline <pipeline_name> table 1645 * match 1646 * acl 1647 * ipv4 | ipv6 1648 * offset <ip_header_offset> 1649 * size <n_rules> 1650 * | array 1651 * offset <key_offset> 1652 * size <n_keys> 1653 * | hash 1654 * ext | lru 1655 * key <key_size> 1656 * mask <key_mask> 1657 * offset <key_offset> 1658 * buckets <n_buckets> 1659 * size <n_keys> 1660 * | lpm 1661 * ipv4 | ipv6 1662 * offset <ip_header_offset> 1663 * size <n_rules> 1664 * | stub 1665 * [action <table_action_profile_name>] 1666 */ 1667 static void 1668 cmd_pipeline_table(char **tokens, 1669 uint32_t n_tokens, 1670 char *out, 1671 size_t out_size) 1672 { 1673 uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; 1674 struct table_params p; 1675 char *pipeline_name; 1676 uint32_t t0; 1677 int status; 1678 1679 if (n_tokens < 5) { 1680 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1681 return; 1682 } 1683 1684 pipeline_name = tokens[1]; 1685 1686 if (strcmp(tokens[2], "table") != 0) { 1687 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 1688 return; 1689 } 1690 1691 if (strcmp(tokens[3], "match") != 0) { 1692 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 1693 return; 1694 } 1695 1696 t0 = 4; 1697 if (strcmp(tokens[t0], "acl") == 0) { 1698 if (n_tokens < t0 + 6) { 1699 snprintf(out, out_size, MSG_ARG_MISMATCH, 1700 "pipeline table acl"); 1701 return; 1702 } 1703 1704 p.match_type = TABLE_ACL; 1705 1706 if (strcmp(tokens[t0 + 1], "ipv4") == 0) 1707 p.match.acl.ip_version = 1; 1708 else if (strcmp(tokens[t0 + 1], "ipv6") == 0) 1709 p.match.acl.ip_version = 0; 1710 else { 1711 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1712 "ipv4 or ipv6"); 1713 return; 1714 } 1715 1716 if (strcmp(tokens[t0 + 2], "offset") != 0) { 1717 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1718 return; 1719 } 1720 1721 if (parser_read_uint32(&p.match.acl.ip_header_offset, 1722 tokens[t0 + 3]) != 0) { 1723 snprintf(out, out_size, MSG_ARG_INVALID, 1724 "ip_header_offset"); 1725 return; 1726 } 1727 1728 if (strcmp(tokens[t0 + 4], "size") != 0) { 1729 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 1730 return; 1731 } 1732 1733 if (parser_read_uint32(&p.match.acl.n_rules, 1734 tokens[t0 + 5]) != 0) { 1735 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 1736 return; 1737 } 1738 1739 t0 += 6; 1740 } else if (strcmp(tokens[t0], "array") == 0) { 1741 if (n_tokens < t0 + 5) { 1742 snprintf(out, out_size, MSG_ARG_MISMATCH, 1743 "pipeline table array"); 1744 return; 1745 } 1746 1747 p.match_type = TABLE_ARRAY; 1748 1749 if (strcmp(tokens[t0 + 1], "offset") != 0) { 1750 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1751 return; 1752 } 1753 1754 if (parser_read_uint32(&p.match.array.key_offset, 1755 tokens[t0 + 2]) != 0) { 1756 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1757 return; 1758 } 1759 1760 if (strcmp(tokens[t0 + 3], "size") != 0) { 1761 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 1762 return; 1763 } 1764 1765 if (parser_read_uint32(&p.match.array.n_keys, 1766 tokens[t0 + 4]) != 0) { 1767 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 1768 return; 1769 } 1770 1771 t0 += 5; 1772 } else if (strcmp(tokens[t0], "hash") == 0) { 1773 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; 1774 1775 if (n_tokens < t0 + 12) { 1776 snprintf(out, out_size, MSG_ARG_MISMATCH, 1777 "pipeline table hash"); 1778 return; 1779 } 1780 1781 p.match_type = TABLE_HASH; 1782 1783 if (strcmp(tokens[t0 + 1], "ext") == 0) 1784 p.match.hash.extendable_bucket = 1; 1785 else if (strcmp(tokens[t0 + 1], "lru") == 0) 1786 p.match.hash.extendable_bucket = 0; 1787 else { 1788 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1789 "ext or lru"); 1790 return; 1791 } 1792 1793 if (strcmp(tokens[t0 + 2], "key") != 0) { 1794 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 1795 return; 1796 } 1797 1798 if ((parser_read_uint32(&p.match.hash.key_size, 1799 tokens[t0 + 3]) != 0) || 1800 (p.match.hash.key_size == 0) || 1801 (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) { 1802 snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); 1803 return; 1804 } 1805 1806 if (strcmp(tokens[t0 + 4], "mask") != 0) { 1807 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 1808 return; 1809 } 1810 1811 if ((parse_hex_string(tokens[t0 + 5], 1812 key_mask, &key_mask_size) != 0) || 1813 (key_mask_size != p.match.hash.key_size)) { 1814 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 1815 return; 1816 } 1817 p.match.hash.key_mask = key_mask; 1818 1819 if (strcmp(tokens[t0 + 6], "offset") != 0) { 1820 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1821 return; 1822 } 1823 1824 if (parser_read_uint32(&p.match.hash.key_offset, 1825 tokens[t0 + 7]) != 0) { 1826 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1827 return; 1828 } 1829 1830 if (strcmp(tokens[t0 + 8], "buckets") != 0) { 1831 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); 1832 return; 1833 } 1834 1835 if (parser_read_uint32(&p.match.hash.n_buckets, 1836 tokens[t0 + 9]) != 0) { 1837 snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); 1838 return; 1839 } 1840 1841 if (strcmp(tokens[t0 + 10], "size") != 0) { 1842 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 1843 return; 1844 } 1845 1846 if (parser_read_uint32(&p.match.hash.n_keys, 1847 tokens[t0 + 11]) != 0) { 1848 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 1849 return; 1850 } 1851 1852 t0 += 12; 1853 } else if (strcmp(tokens[t0], "lpm") == 0) { 1854 if (n_tokens < t0 + 6) { 1855 snprintf(out, out_size, MSG_ARG_MISMATCH, 1856 "pipeline table lpm"); 1857 return; 1858 } 1859 1860 p.match_type = TABLE_LPM; 1861 1862 if (strcmp(tokens[t0 + 1], "ipv4") == 0) 1863 p.match.lpm.key_size = 4; 1864 else if (strcmp(tokens[t0 + 1], "ipv6") == 0) 1865 p.match.lpm.key_size = 16; 1866 else { 1867 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1868 "ipv4 or ipv6"); 1869 return; 1870 } 1871 1872 if (strcmp(tokens[t0 + 2], "offset") != 0) { 1873 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1874 return; 1875 } 1876 1877 if (parser_read_uint32(&p.match.lpm.key_offset, 1878 tokens[t0 + 3]) != 0) { 1879 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1880 return; 1881 } 1882 1883 if (strcmp(tokens[t0 + 4], "size") != 0) { 1884 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 1885 return; 1886 } 1887 1888 if (parser_read_uint32(&p.match.lpm.n_rules, 1889 tokens[t0 + 5]) != 0) { 1890 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 1891 return; 1892 } 1893 1894 t0 += 6; 1895 } else if (strcmp(tokens[t0], "stub") == 0) { 1896 p.match_type = TABLE_STUB; 1897 1898 t0 += 1; 1899 } else { 1900 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1901 return; 1902 } 1903 1904 p.action_profile_name = NULL; 1905 if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) { 1906 if (n_tokens < t0 + 2) { 1907 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 1908 return; 1909 } 1910 1911 p.action_profile_name = tokens[t0 + 1]; 1912 1913 t0 += 2; 1914 } 1915 1916 if (n_tokens > t0) { 1917 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1918 return; 1919 } 1920 1921 status = pipeline_table_create(pipeline_name, &p); 1922 if (status) { 1923 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1924 return; 1925 } 1926 } 1927 1928 /** 1929 * pipeline <pipeline_name> port in <port_id> table <table_id> 1930 */ 1931 static void 1932 cmd_pipeline_port_in_table(char **tokens, 1933 uint32_t n_tokens, 1934 char *out, 1935 size_t out_size) 1936 { 1937 char *pipeline_name; 1938 uint32_t port_id, table_id; 1939 int status; 1940 1941 if (n_tokens != 7) { 1942 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1943 return; 1944 } 1945 1946 pipeline_name = tokens[1]; 1947 1948 if (strcmp(tokens[2], "port") != 0) { 1949 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1950 return; 1951 } 1952 1953 if (strcmp(tokens[3], "in") != 0) { 1954 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 1955 return; 1956 } 1957 1958 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 1959 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 1960 return; 1961 } 1962 1963 if (strcmp(tokens[5], "table") != 0) { 1964 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 1965 return; 1966 } 1967 1968 if (parser_read_uint32(&table_id, tokens[6]) != 0) { 1969 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 1970 return; 1971 } 1972 1973 status = pipeline_port_in_connect_to_table(pipeline_name, 1974 port_id, 1975 table_id); 1976 if (status) { 1977 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1978 return; 1979 } 1980 } 1981 1982 /** 1983 * pipeline <pipeline_name> port in <port_id> stats read [clear] 1984 */ 1985 1986 #define MSG_PIPELINE_PORT_IN_STATS \ 1987 "Pkts in: %" PRIu64 "\n" \ 1988 "Pkts dropped by AH: %" PRIu64 "\n" \ 1989 "Pkts dropped by other: %" PRIu64 "\n" 1990 1991 static void 1992 cmd_pipeline_port_in_stats(char **tokens, 1993 uint32_t n_tokens, 1994 char *out, 1995 size_t out_size) 1996 { 1997 struct rte_pipeline_port_in_stats stats; 1998 char *pipeline_name; 1999 uint32_t port_id; 2000 int clear, status; 2001 2002 if ((n_tokens != 7) && (n_tokens != 8)) { 2003 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2004 return; 2005 } 2006 2007 pipeline_name = tokens[1]; 2008 2009 if (strcmp(tokens[2], "port") != 0) { 2010 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2011 return; 2012 } 2013 2014 if (strcmp(tokens[3], "in") != 0) { 2015 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2016 return; 2017 } 2018 2019 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2020 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2021 return; 2022 } 2023 2024 if (strcmp(tokens[5], "stats") != 0) { 2025 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2026 return; 2027 } 2028 2029 if (strcmp(tokens[6], "read") != 0) { 2030 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2031 return; 2032 } 2033 2034 clear = 0; 2035 if (n_tokens == 8) { 2036 if (strcmp(tokens[7], "clear") != 0) { 2037 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2038 return; 2039 } 2040 2041 clear = 1; 2042 } 2043 2044 status = pipeline_port_in_stats_read(pipeline_name, 2045 port_id, 2046 &stats, 2047 clear); 2048 if (status) { 2049 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2050 return; 2051 } 2052 2053 snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, 2054 stats.stats.n_pkts_in, 2055 stats.n_pkts_dropped_by_ah, 2056 stats.stats.n_pkts_drop); 2057 } 2058 2059 /** 2060 * pipeline <pipeline_name> port in <port_id> enable 2061 */ 2062 static void 2063 cmd_pipeline_port_in_enable(char **tokens, 2064 uint32_t n_tokens, 2065 char *out, 2066 size_t out_size) 2067 { 2068 char *pipeline_name; 2069 uint32_t port_id; 2070 int status; 2071 2072 if (n_tokens != 6) { 2073 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2074 return; 2075 } 2076 2077 pipeline_name = tokens[1]; 2078 2079 if (strcmp(tokens[2], "port") != 0) { 2080 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2081 return; 2082 } 2083 2084 if (strcmp(tokens[3], "in") != 0) { 2085 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2086 return; 2087 } 2088 2089 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2090 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2091 return; 2092 } 2093 2094 if (strcmp(tokens[5], "enable") != 0) { 2095 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2096 return; 2097 } 2098 2099 status = pipeline_port_in_enable(pipeline_name, port_id); 2100 if (status) { 2101 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2102 return; 2103 } 2104 } 2105 2106 /** 2107 * pipeline <pipeline_name> port in <port_id> disable 2108 */ 2109 static void 2110 cmd_pipeline_port_in_disable(char **tokens, 2111 uint32_t n_tokens, 2112 char *out, 2113 size_t out_size) 2114 { 2115 char *pipeline_name; 2116 uint32_t port_id; 2117 int status; 2118 2119 if (n_tokens != 6) { 2120 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2121 return; 2122 } 2123 2124 pipeline_name = tokens[1]; 2125 2126 if (strcmp(tokens[2], "port") != 0) { 2127 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2128 return; 2129 } 2130 2131 if (strcmp(tokens[3], "in") != 0) { 2132 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2133 return; 2134 } 2135 2136 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2137 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2138 return; 2139 } 2140 2141 if (strcmp(tokens[5], "disable") != 0) { 2142 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2143 return; 2144 } 2145 2146 status = pipeline_port_in_disable(pipeline_name, port_id); 2147 if (status) { 2148 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2149 return; 2150 } 2151 } 2152 2153 /** 2154 * pipeline <pipeline_name> port out <port_id> stats read [clear] 2155 */ 2156 #define MSG_PIPELINE_PORT_OUT_STATS \ 2157 "Pkts in: %" PRIu64 "\n" \ 2158 "Pkts dropped by AH: %" PRIu64 "\n" \ 2159 "Pkts dropped by other: %" PRIu64 "\n" 2160 2161 static void 2162 cmd_pipeline_port_out_stats(char **tokens, 2163 uint32_t n_tokens, 2164 char *out, 2165 size_t out_size) 2166 { 2167 struct rte_pipeline_port_out_stats stats; 2168 char *pipeline_name; 2169 uint32_t port_id; 2170 int clear, status; 2171 2172 if ((n_tokens != 7) && (n_tokens != 8)) { 2173 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2174 return; 2175 } 2176 2177 pipeline_name = tokens[1]; 2178 2179 if (strcmp(tokens[2], "port") != 0) { 2180 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2181 return; 2182 } 2183 2184 if (strcmp(tokens[3], "out") != 0) { 2185 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 2186 return; 2187 } 2188 2189 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2190 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2191 return; 2192 } 2193 2194 if (strcmp(tokens[5], "stats") != 0) { 2195 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2196 return; 2197 } 2198 2199 if (strcmp(tokens[6], "read") != 0) { 2200 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2201 return; 2202 } 2203 2204 clear = 0; 2205 if (n_tokens == 8) { 2206 if (strcmp(tokens[7], "clear") != 0) { 2207 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2208 return; 2209 } 2210 2211 clear = 1; 2212 } 2213 2214 status = pipeline_port_out_stats_read(pipeline_name, 2215 port_id, 2216 &stats, 2217 clear); 2218 if (status) { 2219 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2220 return; 2221 } 2222 2223 snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, 2224 stats.stats.n_pkts_in, 2225 stats.n_pkts_dropped_by_ah, 2226 stats.stats.n_pkts_drop); 2227 } 2228 2229 /** 2230 * pipeline <pipeline_name> table <table_id> stats read [clear] 2231 */ 2232 #define MSG_PIPELINE_TABLE_STATS \ 2233 "Pkts in: %" PRIu64 "\n" \ 2234 "Pkts in with lookup miss: %" PRIu64 "\n" \ 2235 "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ 2236 "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ 2237 "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ 2238 "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" 2239 2240 static void 2241 cmd_pipeline_table_stats(char **tokens, 2242 uint32_t n_tokens, 2243 char *out, 2244 size_t out_size) 2245 { 2246 struct rte_pipeline_table_stats stats; 2247 char *pipeline_name; 2248 uint32_t table_id; 2249 int clear, status; 2250 2251 if ((n_tokens != 6) && (n_tokens != 7)) { 2252 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2253 return; 2254 } 2255 2256 pipeline_name = tokens[1]; 2257 2258 if (strcmp(tokens[2], "table") != 0) { 2259 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2260 return; 2261 } 2262 2263 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 2264 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2265 return; 2266 } 2267 2268 if (strcmp(tokens[4], "stats") != 0) { 2269 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2270 return; 2271 } 2272 2273 if (strcmp(tokens[5], "read") != 0) { 2274 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2275 return; 2276 } 2277 2278 clear = 0; 2279 if (n_tokens == 7) { 2280 if (strcmp(tokens[6], "clear") != 0) { 2281 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2282 return; 2283 } 2284 2285 clear = 1; 2286 } 2287 2288 status = pipeline_table_stats_read(pipeline_name, 2289 table_id, 2290 &stats, 2291 clear); 2292 if (status) { 2293 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2294 return; 2295 } 2296 2297 snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, 2298 stats.stats.n_pkts_in, 2299 stats.stats.n_pkts_lookup_miss, 2300 stats.n_pkts_dropped_by_lkp_hit_ah, 2301 stats.n_pkts_dropped_lkp_hit, 2302 stats.n_pkts_dropped_by_lkp_miss_ah, 2303 stats.n_pkts_dropped_lkp_miss); 2304 } 2305 2306 /** 2307 * <match> ::= 2308 * 2309 * match 2310 * acl 2311 * priority <priority> 2312 * ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth> 2313 * <sp0> <sp1> <dp0> <dp1> <proto> 2314 * | array <pos> 2315 * | hash 2316 * raw <key> 2317 * | ipv4_5tuple <sa> <da> <sp> <dp> <proto> 2318 * | ipv6_5tuple <sa> <da> <sp> <dp> <proto> 2319 * | ipv4_addr <addr> 2320 * | ipv6_addr <addr> 2321 * | qinq <svlan> <cvlan> 2322 * | lpm 2323 * ipv4 | ipv6 <addr> <depth> 2324 */ 2325 struct pkt_key_qinq { 2326 uint16_t ethertype_svlan; 2327 uint16_t svlan; 2328 uint16_t ethertype_cvlan; 2329 uint16_t cvlan; 2330 } __attribute__((__packed__)); 2331 2332 struct pkt_key_ipv4_5tuple { 2333 uint8_t time_to_live; 2334 uint8_t proto; 2335 uint16_t hdr_checksum; 2336 uint32_t sa; 2337 uint32_t da; 2338 uint16_t sp; 2339 uint16_t dp; 2340 } __attribute__((__packed__)); 2341 2342 struct pkt_key_ipv6_5tuple { 2343 uint16_t payload_length; 2344 uint8_t proto; 2345 uint8_t hop_limit; 2346 uint8_t sa[16]; 2347 uint8_t da[16]; 2348 uint16_t sp; 2349 uint16_t dp; 2350 } __attribute__((__packed__)); 2351 2352 struct pkt_key_ipv4_addr { 2353 uint32_t addr; 2354 } __attribute__((__packed__)); 2355 2356 struct pkt_key_ipv6_addr { 2357 uint8_t addr[16]; 2358 } __attribute__((__packed__)); 2359 2360 static uint32_t 2361 parse_match(char **tokens, 2362 uint32_t n_tokens, 2363 char *out, 2364 size_t out_size, 2365 struct table_rule_match *m) 2366 { 2367 memset(m, 0, sizeof(*m)); 2368 2369 if (n_tokens < 2) 2370 return 0; 2371 2372 if (strcmp(tokens[0], "match") != 0) { 2373 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2374 return 0; 2375 } 2376 2377 if (strcmp(tokens[1], "acl") == 0) { 2378 if (n_tokens < 14) { 2379 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2380 return 0; 2381 } 2382 2383 m->match_type = TABLE_ACL; 2384 2385 if (strcmp(tokens[2], "priority") != 0) { 2386 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); 2387 return 0; 2388 } 2389 2390 if (parser_read_uint32(&m->match.acl.priority, 2391 tokens[3]) != 0) { 2392 snprintf(out, out_size, MSG_ARG_INVALID, "priority"); 2393 return 0; 2394 } 2395 2396 if (strcmp(tokens[4], "ipv4") == 0) { 2397 struct in_addr saddr, daddr; 2398 2399 m->match.acl.ip_version = 1; 2400 2401 if (parse_ipv4_addr(tokens[5], &saddr) != 0) { 2402 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2403 return 0; 2404 } 2405 m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); 2406 2407 if (parse_ipv4_addr(tokens[7], &daddr) != 0) { 2408 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2409 return 0; 2410 } 2411 m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); 2412 } else if (strcmp(tokens[4], "ipv6") == 0) { 2413 struct in6_addr saddr, daddr; 2414 2415 m->match.acl.ip_version = 0; 2416 2417 if (parse_ipv6_addr(tokens[5], &saddr) != 0) { 2418 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2419 return 0; 2420 } 2421 memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); 2422 2423 if (parse_ipv6_addr(tokens[7], &daddr) != 0) { 2424 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2425 return 0; 2426 } 2427 memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); 2428 } else { 2429 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2430 "ipv4 or ipv6"); 2431 return 0; 2432 } 2433 2434 if (parser_read_uint32(&m->match.acl.sa_depth, 2435 tokens[6]) != 0) { 2436 snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); 2437 return 0; 2438 } 2439 2440 if (parser_read_uint32(&m->match.acl.da_depth, 2441 tokens[8]) != 0) { 2442 snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); 2443 return 0; 2444 } 2445 2446 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { 2447 snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); 2448 return 0; 2449 } 2450 2451 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { 2452 snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); 2453 return 0; 2454 } 2455 2456 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { 2457 snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); 2458 return 0; 2459 } 2460 2461 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { 2462 snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); 2463 return 0; 2464 } 2465 2466 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { 2467 snprintf(out, out_size, MSG_ARG_INVALID, "proto"); 2468 return 0; 2469 } 2470 2471 m->match.acl.proto_mask = 0xff; 2472 2473 return 14; 2474 } /* acl */ 2475 2476 if (strcmp(tokens[1], "array") == 0) { 2477 if (n_tokens < 3) { 2478 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2479 return 0; 2480 } 2481 2482 m->match_type = TABLE_ARRAY; 2483 2484 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { 2485 snprintf(out, out_size, MSG_ARG_INVALID, "pos"); 2486 return 0; 2487 } 2488 2489 return 3; 2490 } /* array */ 2491 2492 if (strcmp(tokens[1], "hash") == 0) { 2493 if (n_tokens < 3) { 2494 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2495 return 0; 2496 } 2497 2498 m->match_type = TABLE_HASH; 2499 2500 if (strcmp(tokens[2], "raw") == 0) { 2501 uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; 2502 2503 if (n_tokens < 4) { 2504 snprintf(out, out_size, MSG_ARG_MISMATCH, 2505 tokens[0]); 2506 return 0; 2507 } 2508 2509 if (parse_hex_string(tokens[3], 2510 m->match.hash.key, &key_size) != 0) { 2511 snprintf(out, out_size, MSG_ARG_INVALID, "key"); 2512 return 0; 2513 } 2514 2515 return 4; 2516 } /* hash raw */ 2517 2518 if (strcmp(tokens[2], "ipv4_5tuple") == 0) { 2519 struct pkt_key_ipv4_5tuple *ipv4 = 2520 (struct pkt_key_ipv4_5tuple *) m->match.hash.key; 2521 struct in_addr saddr, daddr; 2522 uint16_t sp, dp; 2523 uint8_t proto; 2524 2525 if (n_tokens < 8) { 2526 snprintf(out, out_size, MSG_ARG_MISMATCH, 2527 tokens[0]); 2528 return 0; 2529 } 2530 2531 if (parse_ipv4_addr(tokens[3], &saddr) != 0) { 2532 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2533 return 0; 2534 } 2535 2536 if (parse_ipv4_addr(tokens[4], &daddr) != 0) { 2537 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2538 return 0; 2539 } 2540 2541 if (parser_read_uint16(&sp, tokens[5]) != 0) { 2542 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 2543 return 0; 2544 } 2545 2546 if (parser_read_uint16(&dp, tokens[6]) != 0) { 2547 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 2548 return 0; 2549 } 2550 2551 if (parser_read_uint8(&proto, tokens[7]) != 0) { 2552 snprintf(out, out_size, MSG_ARG_INVALID, 2553 "proto"); 2554 return 0; 2555 } 2556 2557 ipv4->sa = saddr.s_addr; 2558 ipv4->da = daddr.s_addr; 2559 ipv4->sp = rte_cpu_to_be_16(sp); 2560 ipv4->dp = rte_cpu_to_be_16(dp); 2561 ipv4->proto = proto; 2562 2563 return 8; 2564 } /* hash ipv4_5tuple */ 2565 2566 if (strcmp(tokens[2], "ipv6_5tuple") == 0) { 2567 struct pkt_key_ipv6_5tuple *ipv6 = 2568 (struct pkt_key_ipv6_5tuple *) m->match.hash.key; 2569 struct in6_addr saddr, daddr; 2570 uint16_t sp, dp; 2571 uint8_t proto; 2572 2573 if (n_tokens < 8) { 2574 snprintf(out, out_size, MSG_ARG_MISMATCH, 2575 tokens[0]); 2576 return 0; 2577 } 2578 2579 if (parse_ipv6_addr(tokens[3], &saddr) != 0) { 2580 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2581 return 0; 2582 } 2583 2584 if (parse_ipv6_addr(tokens[4], &daddr) != 0) { 2585 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2586 return 0; 2587 } 2588 2589 if (parser_read_uint16(&sp, tokens[5]) != 0) { 2590 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 2591 return 0; 2592 } 2593 2594 if (parser_read_uint16(&dp, tokens[6]) != 0) { 2595 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 2596 return 0; 2597 } 2598 2599 if (parser_read_uint8(&proto, tokens[7]) != 0) { 2600 snprintf(out, out_size, MSG_ARG_INVALID, 2601 "proto"); 2602 return 0; 2603 } 2604 2605 memcpy(ipv6->sa, saddr.s6_addr, 16); 2606 memcpy(ipv6->da, daddr.s6_addr, 16); 2607 ipv6->sp = rte_cpu_to_be_16(sp); 2608 ipv6->dp = rte_cpu_to_be_16(dp); 2609 ipv6->proto = proto; 2610 2611 return 8; 2612 } /* hash ipv6_5tuple */ 2613 2614 if (strcmp(tokens[2], "ipv4_addr") == 0) { 2615 struct pkt_key_ipv4_addr *ipv4_addr = 2616 (struct pkt_key_ipv4_addr *) m->match.hash.key; 2617 struct in_addr addr; 2618 2619 if (n_tokens < 4) { 2620 snprintf(out, out_size, MSG_ARG_MISMATCH, 2621 tokens[0]); 2622 return 0; 2623 } 2624 2625 if (parse_ipv4_addr(tokens[3], &addr) != 0) { 2626 snprintf(out, out_size, MSG_ARG_INVALID, 2627 "addr"); 2628 return 0; 2629 } 2630 2631 ipv4_addr->addr = addr.s_addr; 2632 2633 return 4; 2634 } /* hash ipv4_addr */ 2635 2636 if (strcmp(tokens[2], "ipv6_addr") == 0) { 2637 struct pkt_key_ipv6_addr *ipv6_addr = 2638 (struct pkt_key_ipv6_addr *) m->match.hash.key; 2639 struct in6_addr addr; 2640 2641 if (n_tokens < 4) { 2642 snprintf(out, out_size, MSG_ARG_MISMATCH, 2643 tokens[0]); 2644 return 0; 2645 } 2646 2647 if (parse_ipv6_addr(tokens[3], &addr) != 0) { 2648 snprintf(out, out_size, MSG_ARG_INVALID, 2649 "addr"); 2650 return 0; 2651 } 2652 2653 memcpy(ipv6_addr->addr, addr.s6_addr, 16); 2654 2655 return 4; 2656 } /* hash ipv6_5tuple */ 2657 2658 if (strcmp(tokens[2], "qinq") == 0) { 2659 struct pkt_key_qinq *qinq = 2660 (struct pkt_key_qinq *) m->match.hash.key; 2661 uint16_t svlan, cvlan; 2662 2663 if (n_tokens < 5) { 2664 snprintf(out, out_size, MSG_ARG_MISMATCH, 2665 tokens[0]); 2666 return 0; 2667 } 2668 2669 if ((parser_read_uint16(&svlan, tokens[3]) != 0) || 2670 (svlan > 0xFFF)) { 2671 snprintf(out, out_size, MSG_ARG_INVALID, 2672 "svlan"); 2673 return 0; 2674 } 2675 2676 if ((parser_read_uint16(&cvlan, tokens[4]) != 0) || 2677 (cvlan > 0xFFF)) { 2678 snprintf(out, out_size, MSG_ARG_INVALID, 2679 "cvlan"); 2680 return 0; 2681 } 2682 2683 qinq->svlan = rte_cpu_to_be_16(svlan); 2684 qinq->cvlan = rte_cpu_to_be_16(cvlan); 2685 2686 return 5; 2687 } /* hash qinq */ 2688 2689 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2690 return 0; 2691 } /* hash */ 2692 2693 if (strcmp(tokens[1], "lpm") == 0) { 2694 if (n_tokens < 5) { 2695 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2696 return 0; 2697 } 2698 2699 m->match_type = TABLE_LPM; 2700 2701 if (strcmp(tokens[2], "ipv4") == 0) { 2702 struct in_addr addr; 2703 2704 m->match.lpm.ip_version = 1; 2705 2706 if (parse_ipv4_addr(tokens[3], &addr) != 0) { 2707 snprintf(out, out_size, MSG_ARG_INVALID, 2708 "addr"); 2709 return 0; 2710 } 2711 2712 m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr); 2713 } else if (strcmp(tokens[2], "ipv6") == 0) { 2714 struct in6_addr addr; 2715 2716 m->match.lpm.ip_version = 0; 2717 2718 if (parse_ipv6_addr(tokens[3], &addr) != 0) { 2719 snprintf(out, out_size, MSG_ARG_INVALID, 2720 "addr"); 2721 return 0; 2722 } 2723 2724 memcpy(m->match.lpm.ipv6, addr.s6_addr, 16); 2725 } else { 2726 snprintf(out, out_size, MSG_ARG_MISMATCH, 2727 "ipv4 or ipv6"); 2728 return 0; 2729 } 2730 2731 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) { 2732 snprintf(out, out_size, MSG_ARG_INVALID, "depth"); 2733 return 0; 2734 } 2735 2736 return 5; 2737 } /* lpm */ 2738 2739 snprintf(out, out_size, MSG_ARG_MISMATCH, 2740 "acl or array or hash or lpm"); 2741 return 0; 2742 } 2743 2744 /** 2745 * table_action ::= 2746 * 2747 * action 2748 * fwd 2749 * drop 2750 * | port <port_id> 2751 * | meta 2752 * | table <table_id> 2753 * [balance <out0> ... <out7>] 2754 * [meter 2755 * tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 2756 * [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 2757 * tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 2758 * tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]] 2759 * [tm subport <subport_id> pipe <pipe_id>] 2760 * [encap 2761 * ether <da> <sa> 2762 * | vlan <da> <sa> <pcp> <dei> <vid> 2763 * | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid> 2764 * | mpls unicast | multicast 2765 * <da> <sa> 2766 * label0 <label> <tc> <ttl> 2767 * [label1 <label> <tc> <ttl> 2768 * [label2 <label> <tc> <ttl> 2769 * [label3 <label> <tc> <ttl>]]] 2770 * | pppoe <da> <sa> <session_id>] 2771 * [nat ipv4 | ipv6 <addr> <port>] 2772 * [ttl dec | keep] 2773 * [stats] 2774 * [time] 2775 * 2776 * where: 2777 * <pa> ::= g | y | r | drop 2778 */ 2779 static uint32_t 2780 parse_table_action_fwd(char **tokens, 2781 uint32_t n_tokens, 2782 struct table_rule_action *a) 2783 { 2784 if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0)) 2785 return 0; 2786 2787 tokens++; 2788 n_tokens--; 2789 2790 if (n_tokens && (strcmp(tokens[0], "drop") == 0)) { 2791 a->fwd.action = RTE_PIPELINE_ACTION_DROP; 2792 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 2793 return 1 + 1; 2794 } 2795 2796 if (n_tokens && (strcmp(tokens[0], "port") == 0)) { 2797 uint32_t id; 2798 2799 if ((n_tokens < 2) || 2800 parser_read_uint32(&id, tokens[1])) 2801 return 0; 2802 2803 a->fwd.action = RTE_PIPELINE_ACTION_PORT; 2804 a->fwd.id = id; 2805 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 2806 return 1 + 2; 2807 } 2808 2809 if (n_tokens && (strcmp(tokens[0], "meta") == 0)) { 2810 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META; 2811 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 2812 return 1 + 1; 2813 } 2814 2815 if (n_tokens && (strcmp(tokens[0], "table") == 0)) { 2816 uint32_t id; 2817 2818 if ((n_tokens < 2) || 2819 parser_read_uint32(&id, tokens[1])) 2820 return 0; 2821 2822 a->fwd.action = RTE_PIPELINE_ACTION_TABLE; 2823 a->fwd.id = id; 2824 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 2825 return 1 + 2; 2826 } 2827 2828 return 0; 2829 } 2830 2831 static uint32_t 2832 parse_table_action_balance(char **tokens, 2833 uint32_t n_tokens, 2834 struct table_rule_action *a) 2835 { 2836 uint32_t i; 2837 2838 if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0)) 2839 return 0; 2840 2841 tokens++; 2842 n_tokens--; 2843 2844 if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE) 2845 return 0; 2846 2847 for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++) 2848 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0) 2849 return 0; 2850 2851 a->action_mask |= 1 << RTE_TABLE_ACTION_LB; 2852 return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE; 2853 2854 } 2855 2856 static int 2857 parse_policer_action(char *token, enum rte_table_action_policer *a) 2858 { 2859 if (strcmp(token, "g") == 0) { 2860 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN; 2861 return 0; 2862 } 2863 2864 if (strcmp(token, "y") == 0) { 2865 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW; 2866 return 0; 2867 } 2868 2869 if (strcmp(token, "r") == 0) { 2870 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED; 2871 return 0; 2872 } 2873 2874 if (strcmp(token, "drop") == 0) { 2875 *a = RTE_TABLE_ACTION_POLICER_DROP; 2876 return 0; 2877 } 2878 2879 return -1; 2880 } 2881 2882 static uint32_t 2883 parse_table_action_meter_tc(char **tokens, 2884 uint32_t n_tokens, 2885 struct rte_table_action_mtr_tc_params *mtr) 2886 { 2887 if ((n_tokens < 9) || 2888 strcmp(tokens[0], "meter") || 2889 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) || 2890 strcmp(tokens[2], "policer") || 2891 strcmp(tokens[3], "g") || 2892 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) || 2893 strcmp(tokens[5], "y") || 2894 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) || 2895 strcmp(tokens[7], "r") || 2896 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED])) 2897 return 0; 2898 2899 return 9; 2900 } 2901 2902 static uint32_t 2903 parse_table_action_meter(char **tokens, 2904 uint32_t n_tokens, 2905 struct table_rule_action *a) 2906 { 2907 if ((n_tokens == 0) || strcmp(tokens[0], "meter")) 2908 return 0; 2909 2910 tokens++; 2911 n_tokens--; 2912 2913 if ((n_tokens < 10) || 2914 strcmp(tokens[0], "tc0") || 2915 (parse_table_action_meter_tc(tokens + 1, 2916 n_tokens - 1, 2917 &a->mtr.mtr[0]) == 0)) 2918 return 0; 2919 2920 tokens += 10; 2921 n_tokens -= 10; 2922 2923 if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) { 2924 a->mtr.tc_mask = 1; 2925 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 2926 return 1 + 10; 2927 } 2928 2929 if ((n_tokens < 30) || 2930 (parse_table_action_meter_tc(tokens + 1, 2931 n_tokens - 1, &a->mtr.mtr[1]) == 0) || 2932 strcmp(tokens[10], "tc2") || 2933 (parse_table_action_meter_tc(tokens + 11, 2934 n_tokens - 11, &a->mtr.mtr[2]) == 0) || 2935 strcmp(tokens[20], "tc3") || 2936 (parse_table_action_meter_tc(tokens + 21, 2937 n_tokens - 21, &a->mtr.mtr[3]) == 0)) 2938 return 0; 2939 2940 a->mtr.tc_mask = 0xF; 2941 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 2942 return 1 + 10 + 3 * 10; 2943 } 2944 2945 static uint32_t 2946 parse_table_action_tm(char **tokens, 2947 uint32_t n_tokens, 2948 struct table_rule_action *a) 2949 { 2950 uint32_t subport_id, pipe_id; 2951 2952 if ((n_tokens < 5) || 2953 strcmp(tokens[0], "tm") || 2954 strcmp(tokens[1], "subport") || 2955 parser_read_uint32(&subport_id, tokens[2]) || 2956 strcmp(tokens[3], "pipe") || 2957 parser_read_uint32(&pipe_id, tokens[4])) 2958 return 0; 2959 2960 a->tm.subport_id = subport_id; 2961 a->tm.pipe_id = pipe_id; 2962 a->action_mask |= 1 << RTE_TABLE_ACTION_TM; 2963 return 5; 2964 } 2965 2966 static uint32_t 2967 parse_table_action_encap(char **tokens, 2968 uint32_t n_tokens, 2969 struct table_rule_action *a) 2970 { 2971 if ((n_tokens == 0) || strcmp(tokens[0], "encap")) 2972 return 0; 2973 2974 tokens++; 2975 n_tokens--; 2976 2977 /* ether */ 2978 if (n_tokens && (strcmp(tokens[0], "ether") == 0)) { 2979 if ((n_tokens < 3) || 2980 parse_mac_addr(tokens[1], &a->encap.ether.ether.da) || 2981 parse_mac_addr(tokens[2], &a->encap.ether.ether.sa)) 2982 return 0; 2983 2984 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER; 2985 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 2986 return 1 + 3; 2987 } 2988 2989 /* vlan */ 2990 if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) { 2991 uint32_t pcp, dei, vid; 2992 2993 if ((n_tokens < 6) || 2994 parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) || 2995 parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) || 2996 parser_read_uint32(&pcp, tokens[3]) || 2997 (pcp > 0x7) || 2998 parser_read_uint32(&dei, tokens[4]) || 2999 (dei > 0x1) || 3000 parser_read_uint32(&vid, tokens[5]) || 3001 (vid > 0xFFF)) 3002 return 0; 3003 3004 a->encap.vlan.vlan.pcp = pcp & 0x7; 3005 a->encap.vlan.vlan.dei = dei & 0x1; 3006 a->encap.vlan.vlan.vid = vid & 0xFFF; 3007 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN; 3008 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3009 return 1 + 6; 3010 } 3011 3012 /* qinq */ 3013 if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) { 3014 uint32_t svlan_pcp, svlan_dei, svlan_vid; 3015 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid; 3016 3017 if ((n_tokens < 9) || 3018 parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) || 3019 parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) || 3020 parser_read_uint32(&svlan_pcp, tokens[3]) || 3021 (svlan_pcp > 0x7) || 3022 parser_read_uint32(&svlan_dei, tokens[4]) || 3023 (svlan_dei > 0x1) || 3024 parser_read_uint32(&svlan_vid, tokens[5]) || 3025 (svlan_vid > 0xFFF) || 3026 parser_read_uint32(&cvlan_pcp, tokens[6]) || 3027 (cvlan_pcp > 0x7) || 3028 parser_read_uint32(&cvlan_dei, tokens[7]) || 3029 (cvlan_dei > 0x1) || 3030 parser_read_uint32(&cvlan_vid, tokens[8]) || 3031 (cvlan_vid > 0xFFF)) 3032 return 0; 3033 3034 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7; 3035 a->encap.qinq.svlan.dei = svlan_dei & 0x1; 3036 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF; 3037 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7; 3038 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1; 3039 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF; 3040 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ; 3041 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3042 return 1 + 9; 3043 } 3044 3045 /* mpls */ 3046 if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) { 3047 uint32_t label, tc, ttl; 3048 3049 if (n_tokens < 8) 3050 return 0; 3051 3052 if (strcmp(tokens[1], "unicast") == 0) 3053 a->encap.mpls.unicast = 1; 3054 else if (strcmp(tokens[1], "multicast") == 0) 3055 a->encap.mpls.unicast = 0; 3056 else 3057 return 0; 3058 3059 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) || 3060 parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) || 3061 strcmp(tokens[4], "label0") || 3062 parser_read_uint32(&label, tokens[5]) || 3063 (label > 0xFFFFF) || 3064 parser_read_uint32(&tc, tokens[6]) || 3065 (tc > 0x7) || 3066 parser_read_uint32(&ttl, tokens[7]) || 3067 (ttl > 0x3F)) 3068 return 0; 3069 3070 a->encap.mpls.mpls[0].label = label; 3071 a->encap.mpls.mpls[0].tc = tc; 3072 a->encap.mpls.mpls[0].ttl = ttl; 3073 3074 tokens += 8; 3075 n_tokens -= 8; 3076 3077 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) { 3078 a->encap.mpls.mpls_count = 1; 3079 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3080 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3081 return 1 + 8; 3082 } 3083 3084 if ((n_tokens < 4) || 3085 parser_read_uint32(&label, tokens[1]) || 3086 (label > 0xFFFFF) || 3087 parser_read_uint32(&tc, tokens[2]) || 3088 (tc > 0x7) || 3089 parser_read_uint32(&ttl, tokens[3]) || 3090 (ttl > 0x3F)) 3091 return 0; 3092 3093 a->encap.mpls.mpls[1].label = label; 3094 a->encap.mpls.mpls[1].tc = tc; 3095 a->encap.mpls.mpls[1].ttl = ttl; 3096 3097 tokens += 4; 3098 n_tokens -= 4; 3099 3100 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) { 3101 a->encap.mpls.mpls_count = 2; 3102 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3103 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3104 return 1 + 8 + 4; 3105 } 3106 3107 if ((n_tokens < 4) || 3108 parser_read_uint32(&label, tokens[1]) || 3109 (label > 0xFFFFF) || 3110 parser_read_uint32(&tc, tokens[2]) || 3111 (tc > 0x7) || 3112 parser_read_uint32(&ttl, tokens[3]) || 3113 (ttl > 0x3F)) 3114 return 0; 3115 3116 a->encap.mpls.mpls[2].label = label; 3117 a->encap.mpls.mpls[2].tc = tc; 3118 a->encap.mpls.mpls[2].ttl = ttl; 3119 3120 tokens += 4; 3121 n_tokens -= 4; 3122 3123 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) { 3124 a->encap.mpls.mpls_count = 3; 3125 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3126 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3127 return 1 + 8 + 4 + 4; 3128 } 3129 3130 if ((n_tokens < 4) || 3131 parser_read_uint32(&label, tokens[1]) || 3132 (label > 0xFFFFF) || 3133 parser_read_uint32(&tc, tokens[2]) || 3134 (tc > 0x7) || 3135 parser_read_uint32(&ttl, tokens[3]) || 3136 (ttl > 0x3F)) 3137 return 0; 3138 3139 a->encap.mpls.mpls[3].label = label; 3140 a->encap.mpls.mpls[3].tc = tc; 3141 a->encap.mpls.mpls[3].ttl = ttl; 3142 3143 a->encap.mpls.mpls_count = 4; 3144 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3145 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3146 return 1 + 8 + 4 + 4 + 4; 3147 } 3148 3149 /* pppoe */ 3150 if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) { 3151 if ((n_tokens < 4) || 3152 parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) || 3153 parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) || 3154 parser_read_uint16(&a->encap.pppoe.pppoe.session_id, 3155 tokens[3])) 3156 return 0; 3157 3158 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE; 3159 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3160 return 1 + 4; 3161 } 3162 3163 return 0; 3164 } 3165 3166 static uint32_t 3167 parse_table_action_nat(char **tokens, 3168 uint32_t n_tokens, 3169 struct table_rule_action *a) 3170 { 3171 if ((n_tokens < 4) || 3172 strcmp(tokens[0], "nat")) 3173 return 0; 3174 3175 if (strcmp(tokens[1], "ipv4") == 0) { 3176 struct in_addr addr; 3177 uint16_t port; 3178 3179 if (parse_ipv4_addr(tokens[2], &addr) || 3180 parser_read_uint16(&port, tokens[3])) 3181 return 0; 3182 3183 a->nat.ip_version = 1; 3184 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr); 3185 a->nat.port = port; 3186 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3187 return 4; 3188 } 3189 3190 if (strcmp(tokens[1], "ipv6") == 0) { 3191 struct in6_addr addr; 3192 uint16_t port; 3193 3194 if (parse_ipv6_addr(tokens[2], &addr) || 3195 parser_read_uint16(&port, tokens[3])) 3196 return 0; 3197 3198 a->nat.ip_version = 0; 3199 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16); 3200 a->nat.port = port; 3201 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3202 return 4; 3203 } 3204 3205 return 0; 3206 } 3207 3208 static uint32_t 3209 parse_table_action_ttl(char **tokens, 3210 uint32_t n_tokens, 3211 struct table_rule_action *a) 3212 { 3213 if ((n_tokens < 2) || 3214 strcmp(tokens[0], "ttl")) 3215 return 0; 3216 3217 if (strcmp(tokens[1], "dec") == 0) 3218 a->ttl.decrement = 1; 3219 else if (strcmp(tokens[1], "keep") == 0) 3220 a->ttl.decrement = 0; 3221 else 3222 return 0; 3223 3224 a->action_mask |= 1 << RTE_TABLE_ACTION_TTL; 3225 return 2; 3226 } 3227 3228 static uint32_t 3229 parse_table_action_stats(char **tokens, 3230 uint32_t n_tokens, 3231 struct table_rule_action *a) 3232 { 3233 if ((n_tokens < 1) || 3234 strcmp(tokens[0], "stats")) 3235 return 0; 3236 3237 a->stats.n_packets = 0; 3238 a->stats.n_bytes = 0; 3239 a->action_mask |= 1 << RTE_TABLE_ACTION_STATS; 3240 return 1; 3241 } 3242 3243 static uint32_t 3244 parse_table_action_time(char **tokens, 3245 uint32_t n_tokens, 3246 struct table_rule_action *a) 3247 { 3248 if ((n_tokens < 1) || 3249 strcmp(tokens[0], "time")) 3250 return 0; 3251 3252 a->time.time = rte_rdtsc(); 3253 a->action_mask |= 1 << RTE_TABLE_ACTION_TIME; 3254 return 1; 3255 } 3256 3257 static uint32_t 3258 parse_table_action(char **tokens, 3259 uint32_t n_tokens, 3260 char *out, 3261 size_t out_size, 3262 struct table_rule_action *a) 3263 { 3264 uint32_t n_tokens0 = n_tokens; 3265 3266 memset(a, 0, sizeof(*a)); 3267 3268 if ((n_tokens < 2) || 3269 strcmp(tokens[0], "action")) 3270 return 0; 3271 3272 tokens++; 3273 n_tokens--; 3274 3275 if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) { 3276 uint32_t n; 3277 3278 n = parse_table_action_fwd(tokens, n_tokens, a); 3279 if (n == 0) { 3280 snprintf(out, out_size, MSG_ARG_INVALID, 3281 "action fwd"); 3282 return 0; 3283 } 3284 3285 tokens += n; 3286 n_tokens -= n; 3287 } 3288 3289 if (n_tokens && (strcmp(tokens[0], "balance") == 0)) { 3290 uint32_t n; 3291 3292 n = parse_table_action_balance(tokens, n_tokens, a); 3293 if (n == 0) { 3294 snprintf(out, out_size, MSG_ARG_INVALID, 3295 "action balance"); 3296 return 0; 3297 } 3298 3299 tokens += n; 3300 n_tokens -= n; 3301 } 3302 3303 if (n_tokens && (strcmp(tokens[0], "meter") == 0)) { 3304 uint32_t n; 3305 3306 n = parse_table_action_meter(tokens, n_tokens, a); 3307 if (n == 0) { 3308 snprintf(out, out_size, MSG_ARG_INVALID, 3309 "action meter"); 3310 return 0; 3311 } 3312 3313 tokens += n; 3314 n_tokens -= n; 3315 } 3316 3317 if (n_tokens && (strcmp(tokens[0], "tm") == 0)) { 3318 uint32_t n; 3319 3320 n = parse_table_action_tm(tokens, n_tokens, a); 3321 if (n == 0) { 3322 snprintf(out, out_size, MSG_ARG_INVALID, 3323 "action tm"); 3324 return 0; 3325 } 3326 3327 tokens += n; 3328 n_tokens -= n; 3329 } 3330 3331 if (n_tokens && (strcmp(tokens[0], "encap") == 0)) { 3332 uint32_t n; 3333 3334 n = parse_table_action_encap(tokens, n_tokens, a); 3335 if (n == 0) { 3336 snprintf(out, out_size, MSG_ARG_INVALID, 3337 "action encap"); 3338 return 0; 3339 } 3340 3341 tokens += n; 3342 n_tokens -= n; 3343 } 3344 3345 if (n_tokens && (strcmp(tokens[0], "nat") == 0)) { 3346 uint32_t n; 3347 3348 n = parse_table_action_nat(tokens, n_tokens, a); 3349 if (n == 0) { 3350 snprintf(out, out_size, MSG_ARG_INVALID, 3351 "action nat"); 3352 return 0; 3353 } 3354 3355 tokens += n; 3356 n_tokens -= n; 3357 } 3358 3359 if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) { 3360 uint32_t n; 3361 3362 n = parse_table_action_ttl(tokens, n_tokens, a); 3363 if (n == 0) { 3364 snprintf(out, out_size, MSG_ARG_INVALID, 3365 "action ttl"); 3366 return 0; 3367 } 3368 3369 tokens += n; 3370 n_tokens -= n; 3371 } 3372 3373 if (n_tokens && (strcmp(tokens[0], "stats") == 0)) { 3374 uint32_t n; 3375 3376 n = parse_table_action_stats(tokens, n_tokens, a); 3377 if (n == 0) { 3378 snprintf(out, out_size, MSG_ARG_INVALID, 3379 "action stats"); 3380 return 0; 3381 } 3382 3383 tokens += n; 3384 n_tokens -= n; 3385 } 3386 3387 if (n_tokens && (strcmp(tokens[0], "time") == 0)) { 3388 uint32_t n; 3389 3390 n = parse_table_action_time(tokens, n_tokens, a); 3391 if (n == 0) { 3392 snprintf(out, out_size, MSG_ARG_INVALID, 3393 "action time"); 3394 return 0; 3395 } 3396 3397 tokens += n; 3398 n_tokens -= n; 3399 } 3400 3401 if (n_tokens0 - n_tokens == 1) { 3402 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 3403 return 0; 3404 } 3405 3406 return n_tokens0 - n_tokens; 3407 } 3408 3409 /** 3410 * pipeline <pipeline_name> table <table_id> rule add 3411 * match <match> 3412 * action <table_action> 3413 */ 3414 static void 3415 cmd_pipeline_table_rule_add(char **tokens, 3416 uint32_t n_tokens, 3417 char *out, 3418 size_t out_size) 3419 { 3420 struct table_rule_match m; 3421 struct table_rule_action a; 3422 char *pipeline_name; 3423 void *data; 3424 uint32_t table_id, t0, n_tokens_parsed; 3425 int status; 3426 3427 if (n_tokens < 8) { 3428 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3429 return; 3430 } 3431 3432 pipeline_name = tokens[1]; 3433 3434 if (strcmp(tokens[2], "table") != 0) { 3435 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 3436 return; 3437 } 3438 3439 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 3440 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3441 return; 3442 } 3443 3444 if (strcmp(tokens[4], "rule") != 0) { 3445 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 3446 return; 3447 } 3448 3449 if (strcmp(tokens[5], "add") != 0) { 3450 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 3451 return; 3452 } 3453 3454 t0 = 6; 3455 3456 /* match */ 3457 n_tokens_parsed = parse_match(tokens + t0, 3458 n_tokens - t0, 3459 out, 3460 out_size, 3461 &m); 3462 if (n_tokens_parsed == 0) 3463 return; 3464 t0 += n_tokens_parsed; 3465 3466 /* action */ 3467 n_tokens_parsed = parse_table_action(tokens + t0, 3468 n_tokens - t0, 3469 out, 3470 out_size, 3471 &a); 3472 if (n_tokens_parsed == 0) 3473 return; 3474 t0 += n_tokens_parsed; 3475 3476 if (t0 != n_tokens) { 3477 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 3478 return; 3479 } 3480 3481 status = pipeline_table_rule_add(pipeline_name, table_id, 3482 &m, &a, &data); 3483 if (status) { 3484 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 3485 return; 3486 } 3487 } 3488 3489 /** 3490 * pipeline <pipeline_name> table <table_id> rule add 3491 * match 3492 * default 3493 * action 3494 * fwd 3495 * drop 3496 * | port <port_id> 3497 * | meta 3498 * | table <table_id> 3499 */ 3500 static void 3501 cmd_pipeline_table_rule_add_default(char **tokens, 3502 uint32_t n_tokens, 3503 char *out, 3504 size_t out_size) 3505 { 3506 struct table_rule_action action; 3507 void *data; 3508 char *pipeline_name; 3509 uint32_t table_id; 3510 int status; 3511 3512 if ((n_tokens != 11) && (n_tokens != 12)) { 3513 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3514 return; 3515 } 3516 3517 pipeline_name = tokens[1]; 3518 3519 if (strcmp(tokens[2], "table") != 0) { 3520 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 3521 return; 3522 } 3523 3524 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 3525 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3526 return; 3527 } 3528 3529 if (strcmp(tokens[4], "rule") != 0) { 3530 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 3531 return; 3532 } 3533 3534 if (strcmp(tokens[5], "add") != 0) { 3535 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 3536 return; 3537 } 3538 3539 if (strcmp(tokens[6], "match") != 0) { 3540 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 3541 return; 3542 } 3543 3544 if (strcmp(tokens[7], "default") != 0) { 3545 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 3546 return; 3547 } 3548 3549 if (strcmp(tokens[8], "action") != 0) { 3550 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 3551 return; 3552 } 3553 3554 if (strcmp(tokens[9], "fwd") != 0) { 3555 snprintf(out, out_size, MSG_ARG_INVALID, "fwd"); 3556 return; 3557 } 3558 3559 action.action_mask = 1 << RTE_TABLE_ACTION_FWD; 3560 3561 if (strcmp(tokens[10], "drop") == 0) { 3562 if (n_tokens != 11) { 3563 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3564 return; 3565 } 3566 3567 action.fwd.action = RTE_PIPELINE_ACTION_DROP; 3568 } else if (strcmp(tokens[10], "port") == 0) { 3569 uint32_t id; 3570 3571 if (n_tokens != 12) { 3572 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3573 return; 3574 } 3575 3576 if (parser_read_uint32(&id, tokens[11]) != 0) { 3577 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 3578 return; 3579 } 3580 3581 action.fwd.action = RTE_PIPELINE_ACTION_PORT; 3582 action.fwd.id = id; 3583 } else if (strcmp(tokens[10], "meta") == 0) { 3584 if (n_tokens != 11) { 3585 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3586 return; 3587 } 3588 3589 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META; 3590 } else if (strcmp(tokens[10], "table") == 0) { 3591 uint32_t id; 3592 3593 if (n_tokens != 12) { 3594 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3595 return; 3596 } 3597 3598 if (parser_read_uint32(&id, tokens[11]) != 0) { 3599 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3600 return; 3601 } 3602 3603 action.fwd.action = RTE_PIPELINE_ACTION_TABLE; 3604 action.fwd.id = id; 3605 } else { 3606 snprintf(out, out_size, MSG_ARG_INVALID, 3607 "drop or port or meta or table"); 3608 return; 3609 } 3610 3611 status = pipeline_table_rule_add_default(pipeline_name, 3612 table_id, 3613 &action, 3614 &data); 3615 if (status) { 3616 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 3617 return; 3618 } 3619 } 3620 3621 /** 3622 * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules> 3623 * 3624 * File <file_name>: 3625 * - line format: match <match> action <action> 3626 */ 3627 static int 3628 cli_rule_file_process(const char *file_name, 3629 size_t line_len_max, 3630 struct table_rule_match *m, 3631 struct table_rule_action *a, 3632 uint32_t *n_rules, 3633 uint32_t *line_number, 3634 char *out, 3635 size_t out_size); 3636 3637 static void 3638 cmd_pipeline_table_rule_add_bulk(char **tokens, 3639 uint32_t n_tokens, 3640 char *out, 3641 size_t out_size) 3642 { 3643 struct table_rule_match *match; 3644 struct table_rule_action *action; 3645 void **data; 3646 char *pipeline_name, *file_name; 3647 uint32_t table_id, n_rules, n_rules_parsed, line_number; 3648 int status; 3649 3650 if (n_tokens != 9) { 3651 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3652 return; 3653 } 3654 3655 pipeline_name = tokens[1]; 3656 3657 if (strcmp(tokens[2], "table") != 0) { 3658 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 3659 return; 3660 } 3661 3662 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 3663 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3664 return; 3665 } 3666 3667 if (strcmp(tokens[4], "rule") != 0) { 3668 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 3669 return; 3670 } 3671 3672 if (strcmp(tokens[5], "add") != 0) { 3673 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 3674 return; 3675 } 3676 3677 if (strcmp(tokens[6], "bulk") != 0) { 3678 snprintf(out, out_size, MSG_ARG_INVALID, "bulk"); 3679 return; 3680 } 3681 3682 file_name = tokens[7]; 3683 3684 if ((parser_read_uint32(&n_rules, tokens[8]) != 0) || 3685 (n_rules == 0)) { 3686 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 3687 return; 3688 } 3689 3690 /* Memory allocation. */ 3691 match = calloc(n_rules, sizeof(struct table_rule_match)); 3692 action = calloc(n_rules, sizeof(struct table_rule_action)); 3693 data = calloc(n_rules, sizeof(void *)); 3694 if ((match == NULL) || (action == NULL) || (data == NULL)) { 3695 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 3696 free(data); 3697 free(action); 3698 free(match); 3699 return; 3700 } 3701 3702 /* Load rule file */ 3703 n_rules_parsed = n_rules; 3704 status = cli_rule_file_process(file_name, 3705 1024, 3706 match, 3707 action, 3708 &n_rules_parsed, 3709 &line_number, 3710 out, 3711 out_size); 3712 if (status) { 3713 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 3714 free(data); 3715 free(action); 3716 free(match); 3717 return; 3718 } 3719 if (n_rules_parsed != n_rules) { 3720 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name); 3721 free(data); 3722 free(action); 3723 free(match); 3724 return; 3725 } 3726 3727 /* Rule bulk add */ 3728 status = pipeline_table_rule_add_bulk(pipeline_name, 3729 table_id, 3730 match, 3731 action, 3732 data, 3733 &n_rules); 3734 if (status) { 3735 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 3736 free(data); 3737 free(action); 3738 free(match); 3739 return; 3740 } 3741 3742 /* Memory free */ 3743 free(data); 3744 free(action); 3745 free(match); 3746 } 3747 3748 /** 3749 * pipeline <pipeline_name> table <table_id> rule delete 3750 * match <match> 3751 */ 3752 static void 3753 cmd_pipeline_table_rule_delete(char **tokens, 3754 uint32_t n_tokens, 3755 char *out, 3756 size_t out_size) 3757 { 3758 struct table_rule_match m; 3759 char *pipeline_name; 3760 uint32_t table_id, n_tokens_parsed, t0; 3761 int status; 3762 3763 if (n_tokens < 8) { 3764 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3765 return; 3766 } 3767 3768 pipeline_name = tokens[1]; 3769 3770 if (strcmp(tokens[2], "table") != 0) { 3771 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 3772 return; 3773 } 3774 3775 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 3776 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3777 return; 3778 } 3779 3780 if (strcmp(tokens[4], "rule") != 0) { 3781 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 3782 return; 3783 } 3784 3785 if (strcmp(tokens[5], "delete") != 0) { 3786 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 3787 return; 3788 } 3789 3790 t0 = 6; 3791 3792 /* match */ 3793 n_tokens_parsed = parse_match(tokens + t0, 3794 n_tokens - t0, 3795 out, 3796 out_size, 3797 &m); 3798 if (n_tokens_parsed == 0) 3799 return; 3800 t0 += n_tokens_parsed; 3801 3802 if (n_tokens != t0) { 3803 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3804 return; 3805 } 3806 3807 status = pipeline_table_rule_delete(pipeline_name, 3808 table_id, 3809 &m); 3810 if (status) { 3811 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 3812 return; 3813 } 3814 } 3815 3816 /** 3817 * pipeline <pipeline_name> table <table_id> rule delete 3818 * match 3819 * default 3820 */ 3821 static void 3822 cmd_pipeline_table_rule_delete_default(char **tokens, 3823 uint32_t n_tokens, 3824 char *out, 3825 size_t out_size) 3826 { 3827 char *pipeline_name; 3828 uint32_t table_id; 3829 int status; 3830 3831 if (n_tokens != 8) { 3832 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3833 return; 3834 } 3835 3836 pipeline_name = tokens[1]; 3837 3838 if (strcmp(tokens[2], "table") != 0) { 3839 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 3840 return; 3841 } 3842 3843 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 3844 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3845 return; 3846 } 3847 3848 if (strcmp(tokens[4], "rule") != 0) { 3849 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 3850 return; 3851 } 3852 3853 if (strcmp(tokens[5], "delete") != 0) { 3854 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 3855 return; 3856 } 3857 3858 if (strcmp(tokens[6], "match") != 0) { 3859 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 3860 return; 3861 } 3862 3863 if (strcmp(tokens[7], "default") != 0) { 3864 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 3865 return; 3866 } 3867 3868 status = pipeline_table_rule_delete_default(pipeline_name, 3869 table_id); 3870 if (status) { 3871 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 3872 return; 3873 } 3874 } 3875 3876 /** 3877 * pipeline <pipeline_name> table <table_id> rule read stats [clear] 3878 */ 3879 static void 3880 cmd_pipeline_table_rule_stats_read(char **tokens, 3881 uint32_t n_tokens __rte_unused, 3882 char *out, 3883 size_t out_size) 3884 { 3885 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 3886 } 3887 3888 /** 3889 * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id> 3890 * add srtcm cir <cir> cbs <cbs> ebs <ebs> 3891 * | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs> 3892 */ 3893 static void 3894 cmd_pipeline_table_meter_profile_add(char **tokens, 3895 uint32_t n_tokens, 3896 char *out, 3897 size_t out_size) 3898 { 3899 struct rte_table_action_meter_profile p; 3900 char *pipeline_name; 3901 uint32_t table_id, meter_profile_id; 3902 int status; 3903 3904 if (n_tokens < 9) { 3905 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3906 return; 3907 } 3908 3909 pipeline_name = tokens[1]; 3910 3911 if (strcmp(tokens[2], "table") != 0) { 3912 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 3913 return; 3914 } 3915 3916 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 3917 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3918 return; 3919 } 3920 3921 if (strcmp(tokens[4], "meter") != 0) { 3922 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 3923 return; 3924 } 3925 3926 if (strcmp(tokens[5], "profile") != 0) { 3927 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 3928 return; 3929 } 3930 3931 if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 3932 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 3933 return; 3934 } 3935 3936 if (strcmp(tokens[7], "add") != 0) { 3937 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 3938 return; 3939 } 3940 3941 if (strcmp(tokens[8], "srtcm") == 0) { 3942 if (n_tokens != 15) { 3943 snprintf(out, out_size, MSG_ARG_MISMATCH, 3944 tokens[0]); 3945 return; 3946 } 3947 3948 p.alg = RTE_TABLE_ACTION_METER_SRTCM; 3949 3950 if (strcmp(tokens[9], "cir") != 0) { 3951 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 3952 return; 3953 } 3954 3955 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) { 3956 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 3957 return; 3958 } 3959 3960 if (strcmp(tokens[11], "cbs") != 0) { 3961 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 3962 return; 3963 } 3964 3965 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) { 3966 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 3967 return; 3968 } 3969 3970 if (strcmp(tokens[13], "ebs") != 0) { 3971 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs"); 3972 return; 3973 } 3974 3975 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) { 3976 snprintf(out, out_size, MSG_ARG_INVALID, "ebs"); 3977 return; 3978 } 3979 } else if (strcmp(tokens[8], "trtcm") == 0) { 3980 if (n_tokens != 17) { 3981 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3982 return; 3983 } 3984 3985 p.alg = RTE_TABLE_ACTION_METER_TRTCM; 3986 3987 if (strcmp(tokens[9], "cir") != 0) { 3988 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 3989 return; 3990 } 3991 3992 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) { 3993 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 3994 return; 3995 } 3996 3997 if (strcmp(tokens[11], "pir") != 0) { 3998 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 3999 return; 4000 } 4001 4002 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) { 4003 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 4004 return; 4005 } 4006 if (strcmp(tokens[13], "cbs") != 0) { 4007 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 4008 return; 4009 } 4010 4011 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) { 4012 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 4013 return; 4014 } 4015 4016 if (strcmp(tokens[15], "pbs") != 0) { 4017 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 4018 return; 4019 } 4020 4021 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) { 4022 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 4023 return; 4024 } 4025 } else { 4026 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4027 return; 4028 } 4029 4030 status = pipeline_table_mtr_profile_add(pipeline_name, 4031 table_id, 4032 meter_profile_id, 4033 &p); 4034 if (status) { 4035 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4036 return; 4037 } 4038 } 4039 4040 /** 4041 * pipeline <pipeline_name> table <table_id> 4042 * meter profile <meter_profile_id> delete 4043 */ 4044 static void 4045 cmd_pipeline_table_meter_profile_delete(char **tokens, 4046 uint32_t n_tokens, 4047 char *out, 4048 size_t out_size) 4049 { 4050 char *pipeline_name; 4051 uint32_t table_id, meter_profile_id; 4052 int status; 4053 4054 if (n_tokens != 8) { 4055 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4056 return; 4057 } 4058 4059 pipeline_name = tokens[1]; 4060 4061 if (strcmp(tokens[2], "table") != 0) { 4062 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 4063 return; 4064 } 4065 4066 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4067 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4068 return; 4069 } 4070 4071 if (strcmp(tokens[4], "meter") != 0) { 4072 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 4073 return; 4074 } 4075 4076 if (strcmp(tokens[5], "profile") != 0) { 4077 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 4078 return; 4079 } 4080 4081 if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 4082 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 4083 return; 4084 } 4085 4086 if (strcmp(tokens[7], "delete") != 0) { 4087 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4088 return; 4089 } 4090 4091 status = pipeline_table_mtr_profile_delete(pipeline_name, 4092 table_id, 4093 meter_profile_id); 4094 if (status) { 4095 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4096 return; 4097 } 4098 } 4099 4100 /** 4101 * pipeline <pipeline_name> table <table_id> rule read meter [clear] 4102 */ 4103 static void 4104 cmd_pipeline_table_rule_meter_read(char **tokens, 4105 uint32_t n_tokens __rte_unused, 4106 char *out, 4107 size_t out_size) 4108 { 4109 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 4110 } 4111 4112 /** 4113 * pipeline <pipeline_name> table <table_id> dscp <file_name> 4114 * 4115 * File <file_name>: 4116 * - exactly 64 lines 4117 * - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r 4118 */ 4119 static int 4120 load_dscp_table(struct rte_table_action_dscp_table *dscp_table, 4121 const char *file_name, 4122 uint32_t *line_number) 4123 { 4124 FILE *f = NULL; 4125 uint32_t dscp, l; 4126 4127 /* Check input arguments */ 4128 if ((dscp_table == NULL) || 4129 (file_name == NULL) || 4130 (line_number == NULL)) { 4131 if (line_number) 4132 *line_number = 0; 4133 return -EINVAL; 4134 } 4135 4136 /* Open input file */ 4137 f = fopen(file_name, "r"); 4138 if (f == NULL) { 4139 *line_number = 0; 4140 return -EINVAL; 4141 } 4142 4143 /* Read file */ 4144 for (dscp = 0, l = 1; ; l++) { 4145 char line[64]; 4146 char *tokens[3]; 4147 enum rte_meter_color color; 4148 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens); 4149 4150 if (fgets(line, sizeof(line), f) == NULL) 4151 break; 4152 4153 if (is_comment(line)) 4154 continue; 4155 4156 if (parse_tokenize_string(line, tokens, &n_tokens)) { 4157 *line_number = l; 4158 fclose(f); 4159 return -EINVAL; 4160 } 4161 4162 if (n_tokens == 0) 4163 continue; 4164 4165 if ((dscp >= RTE_DIM(dscp_table->entry)) || 4166 (n_tokens != RTE_DIM(tokens)) || 4167 parser_read_uint32(&tc_id, tokens[0]) || 4168 (tc_id >= RTE_TABLE_ACTION_TC_MAX) || 4169 parser_read_uint32(&tc_queue_id, tokens[1]) || 4170 (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) || 4171 (strlen(tokens[2]) != 1)) { 4172 *line_number = l; 4173 fclose(f); 4174 return -EINVAL; 4175 } 4176 4177 switch (tokens[2][0]) { 4178 case 'g': 4179 case 'G': 4180 color = e_RTE_METER_GREEN; 4181 break; 4182 4183 case 'y': 4184 case 'Y': 4185 color = e_RTE_METER_YELLOW; 4186 break; 4187 4188 case 'r': 4189 case 'R': 4190 color = e_RTE_METER_RED; 4191 break; 4192 4193 default: 4194 *line_number = l; 4195 fclose(f); 4196 return -EINVAL; 4197 } 4198 4199 dscp_table->entry[dscp].tc_id = tc_id; 4200 dscp_table->entry[dscp].tc_queue_id = tc_queue_id; 4201 dscp_table->entry[dscp].color = color; 4202 dscp++; 4203 } 4204 4205 /* Close file */ 4206 fclose(f); 4207 return 0; 4208 } 4209 4210 static void 4211 cmd_pipeline_table_dscp(char **tokens, 4212 uint32_t n_tokens, 4213 char *out, 4214 size_t out_size) 4215 { 4216 struct rte_table_action_dscp_table dscp_table; 4217 char *pipeline_name, *file_name; 4218 uint32_t table_id, line_number; 4219 int status; 4220 4221 if (n_tokens != 6) { 4222 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4223 return; 4224 } 4225 4226 pipeline_name = tokens[1]; 4227 4228 if (strcmp(tokens[2], "table") != 0) { 4229 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 4230 return; 4231 } 4232 4233 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4234 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4235 return; 4236 } 4237 4238 if (strcmp(tokens[4], "dscp") != 0) { 4239 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp"); 4240 return; 4241 } 4242 4243 file_name = tokens[5]; 4244 4245 status = load_dscp_table(&dscp_table, file_name, &line_number); 4246 if (status) { 4247 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 4248 return; 4249 } 4250 4251 status = pipeline_table_dscp_table_update(pipeline_name, 4252 table_id, 4253 UINT64_MAX, 4254 &dscp_table); 4255 if (status) { 4256 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4257 return; 4258 } 4259 } 4260 4261 /** 4262 * pipeline <pipeline_name> table <table_id> rule read ttl [clear] 4263 */ 4264 static void 4265 cmd_pipeline_table_rule_ttl_read(char **tokens, 4266 uint32_t n_tokens __rte_unused, 4267 char *out, 4268 size_t out_size) 4269 { 4270 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 4271 } 4272 4273 /** 4274 * thread <thread_id> pipeline <pipeline_name> enable 4275 */ 4276 static void 4277 cmd_thread_pipeline_enable(char **tokens, 4278 uint32_t n_tokens, 4279 char *out, 4280 size_t out_size) 4281 { 4282 char *pipeline_name; 4283 uint32_t thread_id; 4284 int status; 4285 4286 if (n_tokens != 5) { 4287 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4288 return; 4289 } 4290 4291 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 4292 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 4293 return; 4294 } 4295 4296 if (strcmp(tokens[2], "pipeline") != 0) { 4297 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 4298 return; 4299 } 4300 4301 pipeline_name = tokens[3]; 4302 4303 if (strcmp(tokens[4], "enable") != 0) { 4304 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 4305 return; 4306 } 4307 4308 status = thread_pipeline_enable(thread_id, pipeline_name); 4309 if (status) { 4310 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 4311 return; 4312 } 4313 } 4314 4315 /** 4316 * thread <thread_id> pipeline <pipeline_name> disable 4317 */ 4318 static void 4319 cmd_thread_pipeline_disable(char **tokens, 4320 uint32_t n_tokens, 4321 char *out, 4322 size_t out_size) 4323 { 4324 char *pipeline_name; 4325 uint32_t thread_id; 4326 int status; 4327 4328 if (n_tokens != 5) { 4329 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4330 return; 4331 } 4332 4333 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 4334 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 4335 return; 4336 } 4337 4338 if (strcmp(tokens[2], "pipeline") != 0) { 4339 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 4340 return; 4341 } 4342 4343 pipeline_name = tokens[3]; 4344 4345 if (strcmp(tokens[4], "disable") != 0) { 4346 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 4347 return; 4348 } 4349 4350 status = thread_pipeline_disable(thread_id, pipeline_name); 4351 if (status) { 4352 snprintf(out, out_size, MSG_CMD_FAIL, 4353 "thread pipeline disable"); 4354 return; 4355 } 4356 } 4357 4358 void 4359 cli_process(char *in, char *out, size_t out_size) 4360 { 4361 char *tokens[CMD_MAX_TOKENS]; 4362 uint32_t n_tokens = RTE_DIM(tokens); 4363 int status; 4364 4365 if (is_comment(in)) 4366 return; 4367 4368 status = parse_tokenize_string(in, tokens, &n_tokens); 4369 if (status) { 4370 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 4371 return; 4372 } 4373 4374 if (n_tokens == 0) 4375 return; 4376 4377 if (strcmp(tokens[0], "mempool") == 0) { 4378 cmd_mempool(tokens, n_tokens, out, out_size); 4379 return; 4380 } 4381 4382 if (strcmp(tokens[0], "link") == 0) { 4383 cmd_link(tokens, n_tokens, out, out_size); 4384 return; 4385 } 4386 4387 if (strcmp(tokens[0], "swq") == 0) { 4388 cmd_swq(tokens, n_tokens, out, out_size); 4389 return; 4390 } 4391 4392 if (strcmp(tokens[0], "tmgr") == 0) { 4393 if ((n_tokens >= 3) && 4394 (strcmp(tokens[1], "subport") == 0) && 4395 (strcmp(tokens[2], "profile") == 0)) { 4396 cmd_tmgr_subport_profile(tokens, n_tokens, 4397 out, out_size); 4398 return; 4399 } 4400 4401 if ((n_tokens >= 3) && 4402 (strcmp(tokens[1], "pipe") == 0) && 4403 (strcmp(tokens[2], "profile") == 0)) { 4404 cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size); 4405 return; 4406 } 4407 4408 if ((n_tokens >= 5) && 4409 (strcmp(tokens[2], "subport") == 0) && 4410 (strcmp(tokens[4], "profile") == 0)) { 4411 cmd_tmgr_subport(tokens, n_tokens, out, out_size); 4412 return; 4413 } 4414 4415 if ((n_tokens >= 5) && 4416 (strcmp(tokens[2], "subport") == 0) && 4417 (strcmp(tokens[4], "pipe") == 0)) { 4418 cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size); 4419 return; 4420 } 4421 4422 cmd_tmgr(tokens, n_tokens, out, out_size); 4423 return; 4424 } 4425 4426 if (strcmp(tokens[0], "tap") == 0) { 4427 cmd_tap(tokens, n_tokens, out, out_size); 4428 return; 4429 } 4430 4431 if (strcmp(tokens[0], "kni") == 0) { 4432 cmd_kni(tokens, n_tokens, out, out_size); 4433 return; 4434 } 4435 4436 if (strcmp(tokens[0], "port") == 0) { 4437 cmd_port_in_action_profile(tokens, n_tokens, out, out_size); 4438 return; 4439 } 4440 4441 if (strcmp(tokens[0], "table") == 0) { 4442 cmd_table_action_profile(tokens, n_tokens, out, out_size); 4443 return; 4444 } 4445 4446 if (strcmp(tokens[0], "pipeline") == 0) { 4447 if ((n_tokens >= 3) && 4448 (strcmp(tokens[2], "period") == 0)) { 4449 cmd_pipeline(tokens, n_tokens, out, out_size); 4450 return; 4451 } 4452 4453 if ((n_tokens >= 5) && 4454 (strcmp(tokens[2], "port") == 0) && 4455 (strcmp(tokens[3], "in") == 0) && 4456 (strcmp(tokens[4], "bsz") == 0)) { 4457 cmd_pipeline_port_in(tokens, n_tokens, out, out_size); 4458 return; 4459 } 4460 4461 if ((n_tokens >= 5) && 4462 (strcmp(tokens[2], "port") == 0) && 4463 (strcmp(tokens[3], "out") == 0) && 4464 (strcmp(tokens[4], "bsz") == 0)) { 4465 cmd_pipeline_port_out(tokens, n_tokens, out, out_size); 4466 return; 4467 } 4468 4469 if ((n_tokens >= 4) && 4470 (strcmp(tokens[2], "table") == 0) && 4471 (strcmp(tokens[3], "match") == 0)) { 4472 cmd_pipeline_table(tokens, n_tokens, out, out_size); 4473 return; 4474 } 4475 4476 if ((n_tokens >= 6) && 4477 (strcmp(tokens[2], "port") == 0) && 4478 (strcmp(tokens[3], "in") == 0) && 4479 (strcmp(tokens[5], "table") == 0)) { 4480 cmd_pipeline_port_in_table(tokens, n_tokens, 4481 out, out_size); 4482 return; 4483 } 4484 4485 if ((n_tokens >= 6) && 4486 (strcmp(tokens[2], "port") == 0) && 4487 (strcmp(tokens[3], "in") == 0) && 4488 (strcmp(tokens[5], "stats") == 0)) { 4489 cmd_pipeline_port_in_stats(tokens, n_tokens, 4490 out, out_size); 4491 return; 4492 } 4493 4494 if ((n_tokens >= 6) && 4495 (strcmp(tokens[2], "port") == 0) && 4496 (strcmp(tokens[3], "in") == 0) && 4497 (strcmp(tokens[5], "enable") == 0)) { 4498 cmd_pipeline_port_in_enable(tokens, n_tokens, 4499 out, out_size); 4500 return; 4501 } 4502 4503 if ((n_tokens >= 6) && 4504 (strcmp(tokens[2], "port") == 0) && 4505 (strcmp(tokens[3], "in") == 0) && 4506 (strcmp(tokens[5], "disable") == 0)) { 4507 cmd_pipeline_port_in_disable(tokens, n_tokens, 4508 out, out_size); 4509 return; 4510 } 4511 4512 if ((n_tokens >= 6) && 4513 (strcmp(tokens[2], "port") == 0) && 4514 (strcmp(tokens[3], "out") == 0) && 4515 (strcmp(tokens[5], "stats") == 0)) { 4516 cmd_pipeline_port_out_stats(tokens, n_tokens, 4517 out, out_size); 4518 return; 4519 } 4520 4521 if ((n_tokens >= 5) && 4522 (strcmp(tokens[2], "table") == 0) && 4523 (strcmp(tokens[4], "stats") == 0)) { 4524 cmd_pipeline_table_stats(tokens, n_tokens, 4525 out, out_size); 4526 return; 4527 } 4528 4529 if ((n_tokens >= 7) && 4530 (strcmp(tokens[2], "table") == 0) && 4531 (strcmp(tokens[4], "rule") == 0) && 4532 (strcmp(tokens[5], "add") == 0) && 4533 (strcmp(tokens[6], "match") == 0)) { 4534 if ((n_tokens >= 8) && 4535 (strcmp(tokens[7], "default") == 0)) { 4536 cmd_pipeline_table_rule_add_default(tokens, 4537 n_tokens, out, out_size); 4538 return; 4539 } 4540 4541 cmd_pipeline_table_rule_add(tokens, n_tokens, 4542 out, out_size); 4543 return; 4544 } 4545 4546 if ((n_tokens >= 7) && 4547 (strcmp(tokens[2], "table") == 0) && 4548 (strcmp(tokens[4], "rule") == 0) && 4549 (strcmp(tokens[5], "add") == 0) && 4550 (strcmp(tokens[6], "bulk") == 0)) { 4551 cmd_pipeline_table_rule_add_bulk(tokens, 4552 n_tokens, out, out_size); 4553 return; 4554 } 4555 4556 if ((n_tokens >= 7) && 4557 (strcmp(tokens[2], "table") == 0) && 4558 (strcmp(tokens[4], "rule") == 0) && 4559 (strcmp(tokens[5], "delete") == 0) && 4560 (strcmp(tokens[6], "match") == 0)) { 4561 if ((n_tokens >= 8) && 4562 (strcmp(tokens[7], "default") == 0)) { 4563 cmd_pipeline_table_rule_delete_default(tokens, 4564 n_tokens, out, out_size); 4565 return; 4566 } 4567 4568 cmd_pipeline_table_rule_delete(tokens, n_tokens, 4569 out, out_size); 4570 return; 4571 } 4572 4573 if ((n_tokens >= 7) && 4574 (strcmp(tokens[2], "table") == 0) && 4575 (strcmp(tokens[4], "rule") == 0) && 4576 (strcmp(tokens[5], "read") == 0) && 4577 (strcmp(tokens[6], "stats") == 0)) { 4578 cmd_pipeline_table_rule_stats_read(tokens, n_tokens, 4579 out, out_size); 4580 return; 4581 } 4582 4583 if ((n_tokens >= 8) && 4584 (strcmp(tokens[2], "table") == 0) && 4585 (strcmp(tokens[4], "meter") == 0) && 4586 (strcmp(tokens[5], "profile") == 0) && 4587 (strcmp(tokens[7], "add") == 0)) { 4588 cmd_pipeline_table_meter_profile_add(tokens, n_tokens, 4589 out, out_size); 4590 return; 4591 } 4592 4593 if ((n_tokens >= 8) && 4594 (strcmp(tokens[2], "table") == 0) && 4595 (strcmp(tokens[4], "meter") == 0) && 4596 (strcmp(tokens[5], "profile") == 0) && 4597 (strcmp(tokens[7], "delete") == 0)) { 4598 cmd_pipeline_table_meter_profile_delete(tokens, 4599 n_tokens, out, out_size); 4600 return; 4601 } 4602 4603 if ((n_tokens >= 7) && 4604 (strcmp(tokens[2], "table") == 0) && 4605 (strcmp(tokens[4], "rule") == 0) && 4606 (strcmp(tokens[5], "read") == 0) && 4607 (strcmp(tokens[6], "meter") == 0)) { 4608 cmd_pipeline_table_rule_meter_read(tokens, n_tokens, 4609 out, out_size); 4610 return; 4611 } 4612 4613 if ((n_tokens >= 5) && 4614 (strcmp(tokens[2], "table") == 0) && 4615 (strcmp(tokens[4], "dscp") == 0)) { 4616 cmd_pipeline_table_dscp(tokens, n_tokens, 4617 out, out_size); 4618 return; 4619 } 4620 4621 if ((n_tokens >= 7) && 4622 (strcmp(tokens[2], "table") == 0) && 4623 (strcmp(tokens[4], "rule") == 0) && 4624 (strcmp(tokens[5], "read") == 0) && 4625 (strcmp(tokens[6], "ttl") == 0)) { 4626 cmd_pipeline_table_rule_ttl_read(tokens, n_tokens, 4627 out, out_size); 4628 return; 4629 } 4630 } 4631 4632 if (strcmp(tokens[0], "thread") == 0) { 4633 if ((n_tokens >= 5) && 4634 (strcmp(tokens[4], "enable") == 0)) { 4635 cmd_thread_pipeline_enable(tokens, n_tokens, 4636 out, out_size); 4637 return; 4638 } 4639 4640 if ((n_tokens >= 5) && 4641 (strcmp(tokens[4], "disable") == 0)) { 4642 cmd_thread_pipeline_disable(tokens, n_tokens, 4643 out, out_size); 4644 return; 4645 } 4646 } 4647 4648 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 4649 } 4650 4651 int 4652 cli_script_process(const char *file_name, 4653 size_t msg_in_len_max, 4654 size_t msg_out_len_max) 4655 { 4656 char *msg_in = NULL, *msg_out = NULL; 4657 FILE *f = NULL; 4658 4659 /* Check input arguments */ 4660 if ((file_name == NULL) || 4661 (strlen(file_name) == 0) || 4662 (msg_in_len_max == 0) || 4663 (msg_out_len_max == 0)) 4664 return -EINVAL; 4665 4666 msg_in = malloc(msg_in_len_max + 1); 4667 msg_out = malloc(msg_out_len_max + 1); 4668 if ((msg_in == NULL) || 4669 (msg_out == NULL)) { 4670 free(msg_out); 4671 free(msg_in); 4672 return -ENOMEM; 4673 } 4674 4675 /* Open input file */ 4676 f = fopen(file_name, "r"); 4677 if (f == NULL) { 4678 free(msg_out); 4679 free(msg_in); 4680 return -EIO; 4681 } 4682 4683 /* Read file */ 4684 for ( ; ; ) { 4685 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 4686 break; 4687 4688 printf("%s", msg_in); 4689 msg_out[0] = 0; 4690 4691 cli_process(msg_in, 4692 msg_out, 4693 msg_out_len_max); 4694 4695 if (strlen(msg_out)) 4696 printf("%s", msg_out); 4697 } 4698 4699 /* Close file */ 4700 fclose(f); 4701 free(msg_out); 4702 free(msg_in); 4703 return 0; 4704 } 4705 4706 static int 4707 cli_rule_file_process(const char *file_name, 4708 size_t line_len_max, 4709 struct table_rule_match *m, 4710 struct table_rule_action *a, 4711 uint32_t *n_rules, 4712 uint32_t *line_number, 4713 char *out, 4714 size_t out_size) 4715 { 4716 FILE *f = NULL; 4717 char *line = NULL; 4718 uint32_t rule_id, line_id; 4719 int status = 0; 4720 4721 /* Check input arguments */ 4722 if ((file_name == NULL) || 4723 (strlen(file_name) == 0) || 4724 (line_len_max == 0)) { 4725 *line_number = 0; 4726 return -EINVAL; 4727 } 4728 4729 /* Memory allocation */ 4730 line = malloc(line_len_max + 1); 4731 if (line == NULL) { 4732 *line_number = 0; 4733 return -ENOMEM; 4734 } 4735 4736 /* Open file */ 4737 f = fopen(file_name, "r"); 4738 if (f == NULL) { 4739 *line_number = 0; 4740 free(line); 4741 return -EIO; 4742 } 4743 4744 /* Read file */ 4745 for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) { 4746 char *tokens[CMD_MAX_TOKENS]; 4747 uint32_t n_tokens, n_tokens_parsed, t0; 4748 4749 /* Read next line from file. */ 4750 if (fgets(line, line_len_max + 1, f) == NULL) 4751 break; 4752 4753 /* Comment. */ 4754 if (is_comment(line)) 4755 continue; 4756 4757 /* Parse line. */ 4758 n_tokens = RTE_DIM(tokens); 4759 status = parse_tokenize_string(line, tokens, &n_tokens); 4760 if (status) { 4761 status = -EINVAL; 4762 break; 4763 } 4764 4765 /* Empty line. */ 4766 if (n_tokens == 0) 4767 continue; 4768 t0 = 0; 4769 4770 /* Rule match. */ 4771 n_tokens_parsed = parse_match(tokens + t0, 4772 n_tokens - t0, 4773 out, 4774 out_size, 4775 &m[rule_id]); 4776 if (n_tokens_parsed == 0) { 4777 status = -EINVAL; 4778 break; 4779 } 4780 t0 += n_tokens_parsed; 4781 4782 /* Rule action. */ 4783 n_tokens_parsed = parse_table_action(tokens + t0, 4784 n_tokens - t0, 4785 out, 4786 out_size, 4787 &a[rule_id]); 4788 if (n_tokens_parsed == 0) { 4789 status = -EINVAL; 4790 break; 4791 } 4792 t0 += n_tokens_parsed; 4793 4794 /* Line completed. */ 4795 if (t0 < n_tokens) { 4796 status = -EINVAL; 4797 break; 4798 } 4799 4800 /* Increment rule count */ 4801 rule_id++; 4802 } 4803 4804 /* Close file */ 4805 fclose(f); 4806 4807 /* Memory free */ 4808 free(line); 4809 4810 *n_rules = rule_id; 4811 *line_number = line_id; 4812 return status; 4813 } 4814