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