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