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 static uint32_t 506 root_node_id(uint32_t n_spp, 507 uint32_t n_pps) 508 { 509 uint32_t n_queues = n_spp * n_pps * RTE_SCHED_QUEUES_PER_PIPE; 510 uint32_t n_tc = n_spp * n_pps * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; 511 uint32_t n_pipes = n_spp * n_pps; 512 513 return n_queues + n_tc + n_pipes + n_spp; 514 } 515 516 static uint32_t 517 subport_node_id(uint32_t n_spp, 518 uint32_t n_pps, 519 uint32_t subport_id) 520 { 521 uint32_t n_pipes = n_spp * n_pps; 522 uint32_t n_tc = n_pipes * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; 523 uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE; 524 525 return n_queues + n_tc + n_pipes + subport_id; 526 } 527 528 static uint32_t 529 pipe_node_id(uint32_t n_spp, 530 uint32_t n_pps, 531 uint32_t subport_id, 532 uint32_t pipe_id) 533 { 534 uint32_t n_pipes = n_spp * n_pps; 535 uint32_t n_tc = n_pipes * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; 536 uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE; 537 538 return n_queues + 539 n_tc + 540 pipe_id + 541 subport_id * n_pps; 542 } 543 544 static uint32_t 545 tc_node_id(uint32_t n_spp, 546 uint32_t n_pps, 547 uint32_t subport_id, 548 uint32_t pipe_id, 549 uint32_t tc_id) 550 { 551 uint32_t n_pipes = n_spp * n_pps; 552 uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE; 553 554 return n_queues + 555 tc_id + 556 (pipe_id + subport_id * n_pps) * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; 557 } 558 559 static uint32_t 560 queue_node_id(uint32_t n_spp __rte_unused, 561 uint32_t n_pps, 562 uint32_t subport_id, 563 uint32_t pipe_id, 564 uint32_t tc_id, 565 uint32_t queue_id) 566 { 567 return queue_id + 568 tc_id * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + 569 (pipe_id + subport_id * n_pps) * RTE_SCHED_QUEUES_PER_PIPE; 570 } 571 572 struct tmgr_hierarchy_default_params { 573 uint32_t n_spp; /**< Number of subports per port. */ 574 uint32_t n_pps; /**< Number of pipes per subport. */ 575 576 struct { 577 uint32_t port; 578 uint32_t subport; 579 uint32_t pipe; 580 uint32_t tc[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE]; 581 } shaper_profile_id; 582 583 struct { 584 uint32_t tc[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE]; 585 uint32_t tc_valid[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE]; 586 } shared_shaper_id; 587 588 struct { 589 uint32_t queue[RTE_SCHED_QUEUES_PER_PIPE]; 590 } weight; 591 }; 592 593 static int 594 tmgr_hierarchy_default(struct pmd_internals *softnic, 595 struct tmgr_hierarchy_default_params *params) 596 { 597 struct rte_tm_node_params root_node_params = { 598 .shaper_profile_id = params->shaper_profile_id.port, 599 .nonleaf = { 600 .n_sp_priorities = 1, 601 }, 602 }; 603 604 struct rte_tm_node_params subport_node_params = { 605 .shaper_profile_id = params->shaper_profile_id.subport, 606 .nonleaf = { 607 .n_sp_priorities = 1, 608 }, 609 }; 610 611 struct rte_tm_node_params pipe_node_params = { 612 .shaper_profile_id = params->shaper_profile_id.pipe, 613 .nonleaf = { 614 .n_sp_priorities = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE, 615 }, 616 }; 617 618 struct rte_tm_node_params tc_node_params[] = { 619 [0] = { 620 .shaper_profile_id = params->shaper_profile_id.tc[0], 621 .shared_shaper_id = ¶ms->shared_shaper_id.tc[0], 622 .n_shared_shapers = 623 (¶ms->shared_shaper_id.tc_valid[0]) ? 1 : 0, 624 .nonleaf = { 625 .n_sp_priorities = 1, 626 }, 627 }, 628 629 [1] = { 630 .shaper_profile_id = params->shaper_profile_id.tc[1], 631 .shared_shaper_id = ¶ms->shared_shaper_id.tc[1], 632 .n_shared_shapers = 633 (¶ms->shared_shaper_id.tc_valid[1]) ? 1 : 0, 634 .nonleaf = { 635 .n_sp_priorities = 1, 636 }, 637 }, 638 639 [2] = { 640 .shaper_profile_id = params->shaper_profile_id.tc[2], 641 .shared_shaper_id = ¶ms->shared_shaper_id.tc[2], 642 .n_shared_shapers = 643 (¶ms->shared_shaper_id.tc_valid[2]) ? 1 : 0, 644 .nonleaf = { 645 .n_sp_priorities = 1, 646 }, 647 }, 648 649 [3] = { 650 .shaper_profile_id = params->shaper_profile_id.tc[3], 651 .shared_shaper_id = ¶ms->shared_shaper_id.tc[3], 652 .n_shared_shapers = 653 (¶ms->shared_shaper_id.tc_valid[3]) ? 1 : 0, 654 .nonleaf = { 655 .n_sp_priorities = 1, 656 }, 657 }, 658 }; 659 660 struct rte_tm_node_params queue_node_params = { 661 .shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE, 662 }; 663 664 struct rte_tm_error error; 665 uint32_t n_spp = params->n_spp, n_pps = params->n_pps, s; 666 int status; 667 uint16_t port_id; 668 669 status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); 670 if (status) 671 return -1; 672 673 /* Hierarchy level 0: Root node */ 674 status = rte_tm_node_add(port_id, 675 root_node_id(n_spp, n_pps), 676 RTE_TM_NODE_ID_NULL, 677 0, 678 1, 679 RTE_TM_NODE_LEVEL_ID_ANY, 680 &root_node_params, 681 &error); 682 if (status) 683 return -1; 684 685 /* Hierarchy level 1: Subport nodes */ 686 for (s = 0; s < params->n_spp; s++) { 687 uint32_t p; 688 689 status = rte_tm_node_add(port_id, 690 subport_node_id(n_spp, n_pps, s), 691 root_node_id(n_spp, n_pps), 692 0, 693 1, 694 RTE_TM_NODE_LEVEL_ID_ANY, 695 &subport_node_params, 696 &error); 697 if (status) 698 return -1; 699 700 /* Hierarchy level 2: Pipe nodes */ 701 for (p = 0; p < params->n_pps; p++) { 702 uint32_t t; 703 704 status = rte_tm_node_add(port_id, 705 pipe_node_id(n_spp, n_pps, s, p), 706 subport_node_id(n_spp, n_pps, s), 707 0, 708 1, 709 RTE_TM_NODE_LEVEL_ID_ANY, 710 &pipe_node_params, 711 &error); 712 if (status) 713 return -1; 714 715 /* Hierarchy level 3: Traffic class nodes */ 716 for (t = 0; t < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; t++) { 717 uint32_t q; 718 719 status = rte_tm_node_add(port_id, 720 tc_node_id(n_spp, n_pps, s, p, t), 721 pipe_node_id(n_spp, n_pps, s, p), 722 t, 723 1, 724 RTE_TM_NODE_LEVEL_ID_ANY, 725 &tc_node_params[t], 726 &error); 727 if (status) 728 return -1; 729 730 /* Hierarchy level 4: Queue nodes */ 731 for (q = 0; q < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; q++) { 732 status = rte_tm_node_add(port_id, 733 queue_node_id(n_spp, n_pps, s, p, t, q), 734 tc_node_id(n_spp, n_pps, s, p, t), 735 0, 736 params->weight.queue[q], 737 RTE_TM_NODE_LEVEL_ID_ANY, 738 &queue_node_params, 739 &error); 740 if (status) 741 return -1; 742 } /* Queue */ 743 } /* TC */ 744 } /* Pipe */ 745 } /* Subport */ 746 747 return 0; 748 } 749 750 751 /** 752 * tmgr hierarchy-default 753 * spp <n_subports_per_port> 754 * pps <n_pipes_per_subport> 755 * shaper profile 756 * port <profile_id> 757 * subport <profile_id> 758 * pipe <profile_id> 759 * tc0 <profile_id> 760 * tc1 <profile_id> 761 * tc2 <profile_id> 762 * tc3 <profile_id> 763 * shared shaper 764 * tc0 <id | none> 765 * tc1 <id | none> 766 * tc2 <id | none> 767 * tc3 <id | none> 768 * weight 769 * queue <q0> ... <q15> 770 */ 771 static void 772 cmd_tmgr_hierarchy_default(struct pmd_internals *softnic, 773 char **tokens, 774 uint32_t n_tokens, 775 char *out, 776 size_t out_size) 777 { 778 struct tmgr_hierarchy_default_params p; 779 int i, status; 780 781 memset(&p, 0, sizeof(p)); 782 783 if (n_tokens != 50) { 784 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 785 return; 786 } 787 788 if (strcmp(tokens[1], "hierarchy-default") != 0) { 789 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy-default"); 790 return; 791 } 792 793 if (strcmp(tokens[2], "spp") != 0) { 794 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 795 return; 796 } 797 798 if (softnic_parser_read_uint32(&p.n_spp, tokens[3]) != 0) { 799 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); 800 return; 801 } 802 803 if (strcmp(tokens[4], "pps") != 0) { 804 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); 805 return; 806 } 807 808 if (softnic_parser_read_uint32(&p.n_pps, tokens[5]) != 0) { 809 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); 810 return; 811 } 812 813 /* Shaper profile */ 814 815 if (strcmp(tokens[6], "shaper") != 0) { 816 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); 817 return; 818 } 819 820 if (strcmp(tokens[7], "profile") != 0) { 821 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 822 return; 823 } 824 825 if (strcmp(tokens[8], "port") != 0) { 826 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 827 return; 828 } 829 830 if (softnic_parser_read_uint32(&p.shaper_profile_id.port, tokens[9]) != 0) { 831 snprintf(out, out_size, MSG_ARG_INVALID, "port profile id"); 832 return; 833 } 834 835 if (strcmp(tokens[10], "subport") != 0) { 836 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "subport"); 837 return; 838 } 839 840 if (softnic_parser_read_uint32(&p.shaper_profile_id.subport, tokens[11]) != 0) { 841 snprintf(out, out_size, MSG_ARG_INVALID, "subport profile id"); 842 return; 843 } 844 845 if (strcmp(tokens[12], "pipe") != 0) { 846 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe"); 847 return; 848 } 849 850 if (softnic_parser_read_uint32(&p.shaper_profile_id.pipe, tokens[13]) != 0) { 851 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id"); 852 return; 853 } 854 855 if (strcmp(tokens[14], "tc0") != 0) { 856 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0"); 857 return; 858 } 859 860 if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[0], tokens[15]) != 0) { 861 snprintf(out, out_size, MSG_ARG_INVALID, "tc0 profile id"); 862 return; 863 } 864 865 if (strcmp(tokens[16], "tc1") != 0) { 866 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1"); 867 return; 868 } 869 870 if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[1], tokens[17]) != 0) { 871 snprintf(out, out_size, MSG_ARG_INVALID, "tc1 profile id"); 872 return; 873 } 874 875 if (strcmp(tokens[18], "tc2") != 0) { 876 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2"); 877 return; 878 } 879 880 if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[2], tokens[19]) != 0) { 881 snprintf(out, out_size, MSG_ARG_INVALID, "tc2 profile id"); 882 return; 883 } 884 885 if (strcmp(tokens[20], "tc3") != 0) { 886 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3"); 887 return; 888 } 889 890 if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[3], tokens[21]) != 0) { 891 snprintf(out, out_size, MSG_ARG_INVALID, "tc3 profile id"); 892 return; 893 } 894 895 /* Shared shaper */ 896 897 if (strcmp(tokens[22], "shared") != 0) { 898 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared"); 899 return; 900 } 901 902 if (strcmp(tokens[23], "shaper") != 0) { 903 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); 904 return; 905 } 906 907 if (strcmp(tokens[24], "tc0") != 0) { 908 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0"); 909 return; 910 } 911 912 if (strcmp(tokens[25], "none") == 0) 913 p.shared_shaper_id.tc_valid[0] = 0; 914 else { 915 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[0], tokens[25]) != 0) { 916 snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc0"); 917 return; 918 } 919 920 p.shared_shaper_id.tc_valid[0] = 1; 921 } 922 923 if (strcmp(tokens[26], "tc1") != 0) { 924 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1"); 925 return; 926 } 927 928 if (strcmp(tokens[27], "none") == 0) 929 p.shared_shaper_id.tc_valid[1] = 0; 930 else { 931 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[1], tokens[27]) != 0) { 932 snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc1"); 933 return; 934 } 935 936 p.shared_shaper_id.tc_valid[1] = 1; 937 } 938 939 if (strcmp(tokens[28], "tc2") != 0) { 940 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2"); 941 return; 942 } 943 944 if (strcmp(tokens[29], "none") == 0) 945 p.shared_shaper_id.tc_valid[2] = 0; 946 else { 947 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[2], tokens[29]) != 0) { 948 snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc2"); 949 return; 950 } 951 952 p.shared_shaper_id.tc_valid[2] = 1; 953 } 954 955 if (strcmp(tokens[30], "tc3") != 0) { 956 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3"); 957 return; 958 } 959 960 if (strcmp(tokens[31], "none") == 0) 961 p.shared_shaper_id.tc_valid[3] = 0; 962 else { 963 if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[3], tokens[31]) != 0) { 964 snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc3"); 965 return; 966 } 967 968 p.shared_shaper_id.tc_valid[3] = 1; 969 } 970 971 /* Weight */ 972 973 if (strcmp(tokens[32], "weight") != 0) { 974 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight"); 975 return; 976 } 977 978 if (strcmp(tokens[33], "queue") != 0) { 979 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "queue"); 980 return; 981 } 982 983 for (i = 0; i < 16; i++) { 984 if (softnic_parser_read_uint32(&p.weight.queue[i], tokens[34 + i]) != 0) { 985 snprintf(out, out_size, MSG_ARG_INVALID, "weight queue"); 986 return; 987 } 988 } 989 990 status = tmgr_hierarchy_default(softnic, &p); 991 if (status != 0) { 992 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 993 return; 994 } 995 } 996 997 /** 998 * tmgr hierarchy commit 999 */ 1000 static void 1001 cmd_tmgr_hierarchy_commit(struct pmd_internals *softnic, 1002 char **tokens, 1003 uint32_t n_tokens, 1004 char *out, 1005 size_t out_size) 1006 { 1007 struct rte_tm_error error; 1008 uint16_t port_id; 1009 int status; 1010 1011 if (n_tokens != 3) { 1012 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1013 return; 1014 } 1015 1016 if (strcmp(tokens[1], "hierarchy") != 0) { 1017 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy"); 1018 return; 1019 } 1020 1021 if (strcmp(tokens[2], "commit") != 0) { 1022 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "commit"); 1023 return; 1024 } 1025 1026 status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); 1027 if (status != 0) 1028 return; 1029 1030 status = rte_tm_hierarchy_commit(port_id, 1, &error); 1031 if (status) { 1032 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1033 return; 1034 } 1035 } 1036 1037 /** 1038 * tmgr <tmgr_name> 1039 */ 1040 static void 1041 cmd_tmgr(struct pmd_internals *softnic, 1042 char **tokens, 1043 uint32_t n_tokens, 1044 char *out, 1045 size_t out_size) 1046 { 1047 char *name; 1048 struct softnic_tmgr_port *tmgr_port; 1049 1050 if (n_tokens != 2) { 1051 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1052 return; 1053 } 1054 1055 name = tokens[1]; 1056 1057 tmgr_port = softnic_tmgr_port_create(softnic, name); 1058 if (tmgr_port == NULL) { 1059 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1060 return; 1061 } 1062 } 1063 1064 /** 1065 * tap <tap_name> 1066 */ 1067 static void 1068 cmd_tap(struct pmd_internals *softnic, 1069 char **tokens, 1070 uint32_t n_tokens, 1071 char *out, 1072 size_t out_size) 1073 { 1074 char *name; 1075 struct softnic_tap *tap; 1076 1077 if (n_tokens != 2) { 1078 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1079 return; 1080 } 1081 1082 name = tokens[1]; 1083 1084 tap = softnic_tap_create(softnic, name); 1085 if (tap == NULL) { 1086 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1087 return; 1088 } 1089 } 1090 1091 /** 1092 * port in action profile <profile_name> 1093 * [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>] 1094 * [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>] 1095 */ 1096 static void 1097 cmd_port_in_action_profile(struct pmd_internals *softnic, 1098 char **tokens, 1099 uint32_t n_tokens, 1100 char *out, 1101 size_t out_size) 1102 { 1103 struct softnic_port_in_action_profile_params p; 1104 struct softnic_port_in_action_profile *ap; 1105 char *name; 1106 uint32_t t0; 1107 1108 memset(&p, 0, sizeof(p)); 1109 1110 if (n_tokens < 5) { 1111 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1112 return; 1113 } 1114 1115 if (strcmp(tokens[1], "in") != 0) { 1116 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 1117 return; 1118 } 1119 1120 if (strcmp(tokens[2], "action") != 0) { 1121 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); 1122 return; 1123 } 1124 1125 if (strcmp(tokens[3], "profile") != 0) { 1126 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 1127 return; 1128 } 1129 1130 name = tokens[4]; 1131 1132 t0 = 5; 1133 1134 if (t0 < n_tokens && 1135 (strcmp(tokens[t0], "filter") == 0)) { 1136 uint32_t size; 1137 1138 if (n_tokens < t0 + 10) { 1139 snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter"); 1140 return; 1141 } 1142 1143 if (strcmp(tokens[t0 + 1], "match") == 0) { 1144 p.fltr.filter_on_match = 1; 1145 } else if (strcmp(tokens[t0 + 1], "mismatch") == 0) { 1146 p.fltr.filter_on_match = 0; 1147 } else { 1148 snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch"); 1149 return; 1150 } 1151 1152 if (strcmp(tokens[t0 + 2], "offset") != 0) { 1153 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1154 return; 1155 } 1156 1157 if (softnic_parser_read_uint32(&p.fltr.key_offset, 1158 tokens[t0 + 3]) != 0) { 1159 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1160 return; 1161 } 1162 1163 if (strcmp(tokens[t0 + 4], "mask") != 0) { 1164 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 1165 return; 1166 } 1167 1168 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; 1169 if ((softnic_parse_hex_string(tokens[t0 + 5], 1170 p.fltr.key_mask, &size) != 0) || 1171 size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) { 1172 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 1173 return; 1174 } 1175 1176 if (strcmp(tokens[t0 + 6], "key") != 0) { 1177 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 1178 return; 1179 } 1180 1181 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; 1182 if ((softnic_parse_hex_string(tokens[t0 + 7], 1183 p.fltr.key, &size) != 0) || 1184 size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) { 1185 snprintf(out, out_size, MSG_ARG_INVALID, "key_value"); 1186 return; 1187 } 1188 1189 if (strcmp(tokens[t0 + 8], "port") != 0) { 1190 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1191 return; 1192 } 1193 1194 if (softnic_parser_read_uint32(&p.fltr.port_id, 1195 tokens[t0 + 9]) != 0) { 1196 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 1197 return; 1198 } 1199 1200 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR; 1201 t0 += 10; 1202 } /* filter */ 1203 1204 if (t0 < n_tokens && 1205 (strcmp(tokens[t0], "balance") == 0)) { 1206 uint32_t i; 1207 1208 if (n_tokens < t0 + 22) { 1209 snprintf(out, out_size, MSG_ARG_MISMATCH, 1210 "port in action profile balance"); 1211 return; 1212 } 1213 1214 if (strcmp(tokens[t0 + 1], "offset") != 0) { 1215 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1216 return; 1217 } 1218 1219 if (softnic_parser_read_uint32(&p.lb.key_offset, 1220 tokens[t0 + 2]) != 0) { 1221 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1222 return; 1223 } 1224 1225 if (strcmp(tokens[t0 + 3], "mask") != 0) { 1226 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 1227 return; 1228 } 1229 1230 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; 1231 if (softnic_parse_hex_string(tokens[t0 + 4], 1232 p.lb.key_mask, &p.lb.key_size) != 0) { 1233 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 1234 return; 1235 } 1236 1237 if (strcmp(tokens[t0 + 5], "port") != 0) { 1238 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1239 return; 1240 } 1241 1242 for (i = 0; i < 16; i++) 1243 if (softnic_parser_read_uint32(&p.lb.port_id[i], 1244 tokens[t0 + 6 + i]) != 0) { 1245 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 1246 return; 1247 } 1248 1249 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB; 1250 t0 += 22; 1251 } /* balance */ 1252 1253 if (t0 < n_tokens) { 1254 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1255 return; 1256 } 1257 1258 ap = softnic_port_in_action_profile_create(softnic, name, &p); 1259 if (ap == NULL) { 1260 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1261 return; 1262 } 1263 } 1264 1265 /** 1266 * table action profile <profile_name> 1267 * ipv4 | ipv6 1268 * offset <ip_offset> 1269 * fwd 1270 * [balance offset <key_offset> mask <key_mask> outoffset <out_offset>] 1271 * [meter srtcm | trtcm 1272 * tc <n_tc> 1273 * stats none | pkts | bytes | both] 1274 * [tm spp <n_subports_per_port> pps <n_pipes_per_subport>] 1275 * [encap ether | vlan | qinq | mpls | pppoe] 1276 * [nat src | dst 1277 * proto udp | tcp] 1278 * [ttl drop | fwd 1279 * stats none | pkts] 1280 * [stats pkts | bytes | both] 1281 * [time] 1282 * [tag] 1283 * [decap] 1284 */ 1285 static void 1286 cmd_table_action_profile(struct pmd_internals *softnic, 1287 char **tokens, 1288 uint32_t n_tokens, 1289 char *out, 1290 size_t out_size) 1291 { 1292 struct softnic_table_action_profile_params p; 1293 struct softnic_table_action_profile *ap; 1294 char *name; 1295 uint32_t t0; 1296 1297 memset(&p, 0, sizeof(p)); 1298 1299 if (n_tokens < 8) { 1300 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1301 return; 1302 } 1303 1304 if (strcmp(tokens[1], "action") != 0) { 1305 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); 1306 return; 1307 } 1308 1309 if (strcmp(tokens[2], "profile") != 0) { 1310 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 1311 return; 1312 } 1313 1314 name = tokens[3]; 1315 1316 if (strcmp(tokens[4], "ipv4") == 0) { 1317 p.common.ip_version = 1; 1318 } else if (strcmp(tokens[4], "ipv6") == 0) { 1319 p.common.ip_version = 0; 1320 } else { 1321 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6"); 1322 return; 1323 } 1324 1325 if (strcmp(tokens[5], "offset") != 0) { 1326 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1327 return; 1328 } 1329 1330 if (softnic_parser_read_uint32(&p.common.ip_offset, 1331 tokens[6]) != 0) { 1332 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset"); 1333 return; 1334 } 1335 1336 if (strcmp(tokens[7], "fwd") != 0) { 1337 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); 1338 return; 1339 } 1340 1341 p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; 1342 1343 t0 = 8; 1344 if (t0 < n_tokens && 1345 (strcmp(tokens[t0], "balance") == 0)) { 1346 if (n_tokens < t0 + 7) { 1347 snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance"); 1348 return; 1349 } 1350 1351 if (strcmp(tokens[t0 + 1], "offset") != 0) { 1352 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1353 return; 1354 } 1355 1356 if (softnic_parser_read_uint32(&p.lb.key_offset, 1357 tokens[t0 + 2]) != 0) { 1358 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1359 return; 1360 } 1361 1362 if (strcmp(tokens[t0 + 3], "mask") != 0) { 1363 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 1364 return; 1365 } 1366 1367 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; 1368 if (softnic_parse_hex_string(tokens[t0 + 4], 1369 p.lb.key_mask, &p.lb.key_size) != 0) { 1370 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 1371 return; 1372 } 1373 1374 if (strcmp(tokens[t0 + 5], "outoffset") != 0) { 1375 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); 1376 return; 1377 } 1378 1379 if (softnic_parser_read_uint32(&p.lb.out_offset, 1380 tokens[t0 + 6]) != 0) { 1381 snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); 1382 return; 1383 } 1384 1385 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; 1386 t0 += 7; 1387 } /* balance */ 1388 1389 if (t0 < n_tokens && 1390 (strcmp(tokens[t0], "meter") == 0)) { 1391 if (n_tokens < t0 + 6) { 1392 snprintf(out, out_size, MSG_ARG_MISMATCH, 1393 "table action profile meter"); 1394 return; 1395 } 1396 1397 if (strcmp(tokens[t0 + 1], "srtcm") == 0) { 1398 p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM; 1399 } else if (strcmp(tokens[t0 + 1], "trtcm") == 0) { 1400 p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM; 1401 } else { 1402 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1403 "srtcm or trtcm"); 1404 return; 1405 } 1406 1407 if (strcmp(tokens[t0 + 2], "tc") != 0) { 1408 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); 1409 return; 1410 } 1411 1412 if (softnic_parser_read_uint32(&p.mtr.n_tc, 1413 tokens[t0 + 3]) != 0) { 1414 snprintf(out, out_size, MSG_ARG_INVALID, "n_tc"); 1415 return; 1416 } 1417 1418 if (strcmp(tokens[t0 + 4], "stats") != 0) { 1419 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1420 return; 1421 } 1422 1423 if (strcmp(tokens[t0 + 5], "none") == 0) { 1424 p.mtr.n_packets_enabled = 0; 1425 p.mtr.n_bytes_enabled = 0; 1426 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) { 1427 p.mtr.n_packets_enabled = 1; 1428 p.mtr.n_bytes_enabled = 0; 1429 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) { 1430 p.mtr.n_packets_enabled = 0; 1431 p.mtr.n_bytes_enabled = 1; 1432 } else if (strcmp(tokens[t0 + 5], "both") == 0) { 1433 p.mtr.n_packets_enabled = 1; 1434 p.mtr.n_bytes_enabled = 1; 1435 } else { 1436 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1437 "none or pkts or bytes or both"); 1438 return; 1439 } 1440 1441 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR; 1442 t0 += 6; 1443 } /* meter */ 1444 1445 if (t0 < n_tokens && 1446 (strcmp(tokens[t0], "tm") == 0)) { 1447 if (n_tokens < t0 + 5) { 1448 snprintf(out, out_size, MSG_ARG_MISMATCH, 1449 "table action profile tm"); 1450 return; 1451 } 1452 1453 if (strcmp(tokens[t0 + 1], "spp") != 0) { 1454 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 1455 return; 1456 } 1457 1458 if (softnic_parser_read_uint32(&p.tm.n_subports_per_port, 1459 tokens[t0 + 2]) != 0) { 1460 snprintf(out, out_size, MSG_ARG_INVALID, 1461 "n_subports_per_port"); 1462 return; 1463 } 1464 1465 if (strcmp(tokens[t0 + 3], "pps") != 0) { 1466 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); 1467 return; 1468 } 1469 1470 if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport, 1471 tokens[t0 + 4]) != 0) { 1472 snprintf(out, out_size, MSG_ARG_INVALID, 1473 "n_pipes_per_subport"); 1474 return; 1475 } 1476 1477 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; 1478 t0 += 5; 1479 } /* tm */ 1480 1481 if (t0 < n_tokens && 1482 (strcmp(tokens[t0], "encap") == 0)) { 1483 if (n_tokens < t0 + 2) { 1484 snprintf(out, out_size, MSG_ARG_MISMATCH, 1485 "action profile encap"); 1486 return; 1487 } 1488 1489 if (strcmp(tokens[t0 + 1], "ether") == 0) { 1490 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER; 1491 } else if (strcmp(tokens[t0 + 1], "vlan") == 0) { 1492 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN; 1493 } else if (strcmp(tokens[t0 + 1], "qinq") == 0) { 1494 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ; 1495 } else if (strcmp(tokens[t0 + 1], "mpls") == 0) { 1496 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; 1497 } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) { 1498 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; 1499 } else { 1500 snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); 1501 return; 1502 } 1503 1504 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; 1505 t0 += 2; 1506 } /* encap */ 1507 1508 if (t0 < n_tokens && 1509 (strcmp(tokens[t0], "nat") == 0)) { 1510 if (n_tokens < t0 + 4) { 1511 snprintf(out, out_size, MSG_ARG_MISMATCH, 1512 "table action profile nat"); 1513 return; 1514 } 1515 1516 if (strcmp(tokens[t0 + 1], "src") == 0) { 1517 p.nat.source_nat = 1; 1518 } else if (strcmp(tokens[t0 + 1], "dst") == 0) { 1519 p.nat.source_nat = 0; 1520 } else { 1521 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1522 "src or dst"); 1523 return; 1524 } 1525 1526 if (strcmp(tokens[t0 + 2], "proto") != 0) { 1527 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); 1528 return; 1529 } 1530 1531 if (strcmp(tokens[t0 + 3], "tcp") == 0) { 1532 p.nat.proto = 0x06; 1533 } else if (strcmp(tokens[t0 + 3], "udp") == 0) { 1534 p.nat.proto = 0x11; 1535 } else { 1536 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1537 "tcp or udp"); 1538 return; 1539 } 1540 1541 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT; 1542 t0 += 4; 1543 } /* nat */ 1544 1545 if (t0 < n_tokens && 1546 (strcmp(tokens[t0], "ttl") == 0)) { 1547 if (n_tokens < t0 + 4) { 1548 snprintf(out, out_size, MSG_ARG_MISMATCH, 1549 "table action profile ttl"); 1550 return; 1551 } 1552 1553 if (strcmp(tokens[t0 + 1], "drop") == 0) { 1554 p.ttl.drop = 1; 1555 } else if (strcmp(tokens[t0 + 1], "fwd") == 0) { 1556 p.ttl.drop = 0; 1557 } else { 1558 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1559 "drop or fwd"); 1560 return; 1561 } 1562 1563 if (strcmp(tokens[t0 + 2], "stats") != 0) { 1564 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1565 return; 1566 } 1567 1568 if (strcmp(tokens[t0 + 3], "none") == 0) { 1569 p.ttl.n_packets_enabled = 0; 1570 } else if (strcmp(tokens[t0 + 3], "pkts") == 0) { 1571 p.ttl.n_packets_enabled = 1; 1572 } else { 1573 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1574 "none or pkts"); 1575 return; 1576 } 1577 1578 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL; 1579 t0 += 4; 1580 } /* ttl */ 1581 1582 if (t0 < n_tokens && 1583 (strcmp(tokens[t0], "stats") == 0)) { 1584 if (n_tokens < t0 + 2) { 1585 snprintf(out, out_size, MSG_ARG_MISMATCH, 1586 "table action profile stats"); 1587 return; 1588 } 1589 1590 if (strcmp(tokens[t0 + 1], "pkts") == 0) { 1591 p.stats.n_packets_enabled = 1; 1592 p.stats.n_bytes_enabled = 0; 1593 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) { 1594 p.stats.n_packets_enabled = 0; 1595 p.stats.n_bytes_enabled = 1; 1596 } else if (strcmp(tokens[t0 + 1], "both") == 0) { 1597 p.stats.n_packets_enabled = 1; 1598 p.stats.n_bytes_enabled = 1; 1599 } else { 1600 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1601 "pkts or bytes or both"); 1602 return; 1603 } 1604 1605 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS; 1606 t0 += 2; 1607 } /* stats */ 1608 1609 if (t0 < n_tokens && 1610 (strcmp(tokens[t0], "time") == 0)) { 1611 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME; 1612 t0 += 1; 1613 } /* time */ 1614 1615 if (t0 < n_tokens && 1616 (strcmp(tokens[t0], "tag") == 0)) { 1617 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG; 1618 t0 += 1; 1619 } /* tag */ 1620 1621 if (t0 < n_tokens && 1622 (strcmp(tokens[t0], "decap") == 0)) { 1623 p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP; 1624 t0 += 1; 1625 } /* decap */ 1626 1627 if (t0 < n_tokens) { 1628 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1629 return; 1630 } 1631 1632 ap = softnic_table_action_profile_create(softnic, name, &p); 1633 if (ap == NULL) { 1634 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1635 return; 1636 } 1637 } 1638 1639 /** 1640 * pipeline <pipeline_name> 1641 * period <timer_period_ms> 1642 * offset_port_id <offset_port_id> 1643 */ 1644 static void 1645 cmd_pipeline(struct pmd_internals *softnic, 1646 char **tokens, 1647 uint32_t n_tokens, 1648 char *out, 1649 size_t out_size) 1650 { 1651 struct pipeline_params p; 1652 char *name; 1653 struct pipeline *pipeline; 1654 1655 if (n_tokens != 6) { 1656 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1657 return; 1658 } 1659 1660 name = tokens[1]; 1661 1662 if (strcmp(tokens[2], "period") != 0) { 1663 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); 1664 return; 1665 } 1666 1667 if (softnic_parser_read_uint32(&p.timer_period_ms, 1668 tokens[3]) != 0) { 1669 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); 1670 return; 1671 } 1672 1673 if (strcmp(tokens[4], "offset_port_id") != 0) { 1674 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); 1675 return; 1676 } 1677 1678 if (softnic_parser_read_uint32(&p.offset_port_id, 1679 tokens[5]) != 0) { 1680 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); 1681 return; 1682 } 1683 1684 pipeline = softnic_pipeline_create(softnic, name, &p); 1685 if (pipeline == NULL) { 1686 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1687 return; 1688 } 1689 } 1690 1691 /** 1692 * pipeline <pipeline_name> port in 1693 * bsz <burst_size> 1694 * link <link_name> rxq <queue_id> 1695 * | swq <swq_name> 1696 * | tmgr <tmgr_name> 1697 * | tap <tap_name> mempool <mempool_name> mtu <mtu> 1698 * | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt> 1699 * [action <port_in_action_profile_name>] 1700 * [disabled] 1701 */ 1702 static void 1703 cmd_pipeline_port_in(struct pmd_internals *softnic, 1704 char **tokens, 1705 uint32_t n_tokens, 1706 char *out, 1707 size_t out_size) 1708 { 1709 struct softnic_port_in_params p; 1710 char *pipeline_name; 1711 uint32_t t0; 1712 int enabled, status; 1713 1714 memset(&p, 0, sizeof(p)); 1715 1716 if (n_tokens < 7) { 1717 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1718 return; 1719 } 1720 1721 pipeline_name = tokens[1]; 1722 1723 if (strcmp(tokens[2], "port") != 0) { 1724 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1725 return; 1726 } 1727 1728 if (strcmp(tokens[3], "in") != 0) { 1729 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 1730 return; 1731 } 1732 1733 if (strcmp(tokens[4], "bsz") != 0) { 1734 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 1735 return; 1736 } 1737 1738 if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 1739 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 1740 return; 1741 } 1742 1743 t0 = 6; 1744 1745 if (strcmp(tokens[t0], "link") == 0) { 1746 if (n_tokens < t0 + 4) { 1747 snprintf(out, out_size, MSG_ARG_MISMATCH, 1748 "pipeline port in link"); 1749 return; 1750 } 1751 1752 p.type = PORT_IN_RXQ; 1753 1754 strcpy(p.dev_name, tokens[t0 + 1]); 1755 1756 if (strcmp(tokens[t0 + 2], "rxq") != 0) { 1757 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 1758 return; 1759 } 1760 1761 if (softnic_parser_read_uint16(&p.rxq.queue_id, 1762 tokens[t0 + 3]) != 0) { 1763 snprintf(out, out_size, MSG_ARG_INVALID, 1764 "queue_id"); 1765 return; 1766 } 1767 t0 += 4; 1768 } else if (strcmp(tokens[t0], "swq") == 0) { 1769 if (n_tokens < t0 + 2) { 1770 snprintf(out, out_size, MSG_ARG_MISMATCH, 1771 "pipeline port in swq"); 1772 return; 1773 } 1774 1775 p.type = PORT_IN_SWQ; 1776 1777 strcpy(p.dev_name, tokens[t0 + 1]); 1778 1779 t0 += 2; 1780 } else if (strcmp(tokens[t0], "tmgr") == 0) { 1781 if (n_tokens < t0 + 2) { 1782 snprintf(out, out_size, MSG_ARG_MISMATCH, 1783 "pipeline port in tmgr"); 1784 return; 1785 } 1786 1787 p.type = PORT_IN_TMGR; 1788 1789 strcpy(p.dev_name, tokens[t0 + 1]); 1790 1791 t0 += 2; 1792 } else if (strcmp(tokens[t0], "tap") == 0) { 1793 if (n_tokens < t0 + 6) { 1794 snprintf(out, out_size, MSG_ARG_MISMATCH, 1795 "pipeline port in tap"); 1796 return; 1797 } 1798 1799 p.type = PORT_IN_TAP; 1800 1801 strcpy(p.dev_name, tokens[t0 + 1]); 1802 1803 if (strcmp(tokens[t0 + 2], "mempool") != 0) { 1804 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1805 "mempool"); 1806 return; 1807 } 1808 1809 p.tap.mempool_name = tokens[t0 + 3]; 1810 1811 if (strcmp(tokens[t0 + 4], "mtu") != 0) { 1812 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1813 "mtu"); 1814 return; 1815 } 1816 1817 if (softnic_parser_read_uint32(&p.tap.mtu, 1818 tokens[t0 + 5]) != 0) { 1819 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 1820 return; 1821 } 1822 1823 t0 += 6; 1824 } else if (strcmp(tokens[t0], "source") == 0) { 1825 if (n_tokens < t0 + 6) { 1826 snprintf(out, out_size, MSG_ARG_MISMATCH, 1827 "pipeline port in source"); 1828 return; 1829 } 1830 1831 p.type = PORT_IN_SOURCE; 1832 1833 if (strcmp(tokens[t0 + 1], "mempool") != 0) { 1834 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1835 "mempool"); 1836 return; 1837 } 1838 1839 p.source.mempool_name = tokens[t0 + 2]; 1840 1841 if (strcmp(tokens[t0 + 3], "file") != 0) { 1842 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1843 "file"); 1844 return; 1845 } 1846 1847 p.source.file_name = tokens[t0 + 4]; 1848 1849 if (strcmp(tokens[t0 + 5], "bpp") != 0) { 1850 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1851 "bpp"); 1852 return; 1853 } 1854 1855 if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt, 1856 tokens[t0 + 6]) != 0) { 1857 snprintf(out, out_size, MSG_ARG_INVALID, 1858 "n_bytes_per_pkt"); 1859 return; 1860 } 1861 1862 t0 += 7; 1863 } else { 1864 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1865 return; 1866 } 1867 1868 if (n_tokens > t0 && 1869 (strcmp(tokens[t0], "action") == 0)) { 1870 if (n_tokens < t0 + 2) { 1871 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 1872 return; 1873 } 1874 1875 strcpy(p.action_profile_name, tokens[t0 + 1]); 1876 1877 t0 += 2; 1878 } 1879 1880 enabled = 1; 1881 if (n_tokens > t0 && 1882 (strcmp(tokens[t0], "disabled") == 0)) { 1883 enabled = 0; 1884 1885 t0 += 1; 1886 } 1887 1888 if (n_tokens != t0) { 1889 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1890 return; 1891 } 1892 1893 status = softnic_pipeline_port_in_create(softnic, 1894 pipeline_name, 1895 &p, 1896 enabled); 1897 if (status) { 1898 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1899 return; 1900 } 1901 } 1902 1903 /** 1904 * pipeline <pipeline_name> port out 1905 * bsz <burst_size> 1906 * link <link_name> txq <txq_id> 1907 * | swq <swq_name> 1908 * | tmgr <tmgr_name> 1909 * | tap <tap_name> 1910 * | sink [file <file_name> pkts <max_n_pkts>] 1911 */ 1912 static void 1913 cmd_pipeline_port_out(struct pmd_internals *softnic, 1914 char **tokens, 1915 uint32_t n_tokens, 1916 char *out, 1917 size_t out_size) 1918 { 1919 struct softnic_port_out_params p; 1920 char *pipeline_name; 1921 int status; 1922 1923 memset(&p, 0, sizeof(p)); 1924 1925 if (n_tokens < 7) { 1926 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1927 return; 1928 } 1929 1930 pipeline_name = tokens[1]; 1931 1932 if (strcmp(tokens[2], "port") != 0) { 1933 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1934 return; 1935 } 1936 1937 if (strcmp(tokens[3], "out") != 0) { 1938 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 1939 return; 1940 } 1941 1942 if (strcmp(tokens[4], "bsz") != 0) { 1943 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 1944 return; 1945 } 1946 1947 if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 1948 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 1949 return; 1950 } 1951 1952 if (strcmp(tokens[6], "link") == 0) { 1953 if (n_tokens != 10) { 1954 snprintf(out, out_size, MSG_ARG_MISMATCH, 1955 "pipeline port out link"); 1956 return; 1957 } 1958 1959 p.type = PORT_OUT_TXQ; 1960 1961 strcpy(p.dev_name, tokens[7]); 1962 1963 if (strcmp(tokens[8], "txq") != 0) { 1964 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 1965 return; 1966 } 1967 1968 if (softnic_parser_read_uint16(&p.txq.queue_id, 1969 tokens[9]) != 0) { 1970 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 1971 return; 1972 } 1973 } else if (strcmp(tokens[6], "swq") == 0) { 1974 if (n_tokens != 8) { 1975 snprintf(out, out_size, MSG_ARG_MISMATCH, 1976 "pipeline port out swq"); 1977 return; 1978 } 1979 1980 p.type = PORT_OUT_SWQ; 1981 1982 strcpy(p.dev_name, tokens[7]); 1983 } else if (strcmp(tokens[6], "tmgr") == 0) { 1984 if (n_tokens != 8) { 1985 snprintf(out, out_size, MSG_ARG_MISMATCH, 1986 "pipeline port out tmgr"); 1987 return; 1988 } 1989 1990 p.type = PORT_OUT_TMGR; 1991 1992 strcpy(p.dev_name, tokens[7]); 1993 } else if (strcmp(tokens[6], "tap") == 0) { 1994 if (n_tokens != 8) { 1995 snprintf(out, out_size, MSG_ARG_MISMATCH, 1996 "pipeline port out tap"); 1997 return; 1998 } 1999 2000 p.type = PORT_OUT_TAP; 2001 2002 strcpy(p.dev_name, tokens[7]); 2003 } else if (strcmp(tokens[6], "sink") == 0) { 2004 if ((n_tokens != 7) && (n_tokens != 11)) { 2005 snprintf(out, out_size, MSG_ARG_MISMATCH, 2006 "pipeline port out sink"); 2007 return; 2008 } 2009 2010 p.type = PORT_OUT_SINK; 2011 2012 if (n_tokens == 7) { 2013 p.sink.file_name = NULL; 2014 p.sink.max_n_pkts = 0; 2015 } else { 2016 if (strcmp(tokens[7], "file") != 0) { 2017 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2018 "file"); 2019 return; 2020 } 2021 2022 p.sink.file_name = tokens[8]; 2023 2024 if (strcmp(tokens[9], "pkts") != 0) { 2025 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); 2026 return; 2027 } 2028 2029 if (softnic_parser_read_uint32(&p.sink.max_n_pkts, 2030 tokens[10]) != 0) { 2031 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); 2032 return; 2033 } 2034 } 2035 } else { 2036 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 2037 return; 2038 } 2039 2040 status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p); 2041 if (status) { 2042 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2043 return; 2044 } 2045 } 2046 2047 /** 2048 * pipeline <pipeline_name> table 2049 * match 2050 * acl 2051 * ipv4 | ipv6 2052 * offset <ip_header_offset> 2053 * size <n_rules> 2054 * | array 2055 * offset <key_offset> 2056 * size <n_keys> 2057 * | hash 2058 * ext | lru 2059 * key <key_size> 2060 * mask <key_mask> 2061 * offset <key_offset> 2062 * buckets <n_buckets> 2063 * size <n_keys> 2064 * | lpm 2065 * ipv4 | ipv6 2066 * offset <ip_header_offset> 2067 * size <n_rules> 2068 * | stub 2069 * [action <table_action_profile_name>] 2070 */ 2071 static void 2072 cmd_pipeline_table(struct pmd_internals *softnic, 2073 char **tokens, 2074 uint32_t n_tokens, 2075 char *out, 2076 size_t out_size) 2077 { 2078 struct softnic_table_params p; 2079 char *pipeline_name; 2080 uint32_t t0; 2081 int status; 2082 2083 memset(&p, 0, sizeof(p)); 2084 2085 if (n_tokens < 5) { 2086 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2087 return; 2088 } 2089 2090 pipeline_name = tokens[1]; 2091 2092 if (strcmp(tokens[2], "table") != 0) { 2093 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 2094 return; 2095 } 2096 2097 if (strcmp(tokens[3], "match") != 0) { 2098 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2099 return; 2100 } 2101 2102 t0 = 4; 2103 if (strcmp(tokens[t0], "acl") == 0) { 2104 if (n_tokens < t0 + 6) { 2105 snprintf(out, out_size, MSG_ARG_MISMATCH, 2106 "pipeline table acl"); 2107 return; 2108 } 2109 2110 p.match_type = TABLE_ACL; 2111 2112 if (strcmp(tokens[t0 + 1], "ipv4") == 0) { 2113 p.match.acl.ip_version = 1; 2114 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { 2115 p.match.acl.ip_version = 0; 2116 } else { 2117 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2118 "ipv4 or ipv6"); 2119 return; 2120 } 2121 2122 if (strcmp(tokens[t0 + 2], "offset") != 0) { 2123 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2124 return; 2125 } 2126 2127 if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset, 2128 tokens[t0 + 3]) != 0) { 2129 snprintf(out, out_size, MSG_ARG_INVALID, 2130 "ip_header_offset"); 2131 return; 2132 } 2133 2134 if (strcmp(tokens[t0 + 4], "size") != 0) { 2135 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2136 return; 2137 } 2138 2139 if (softnic_parser_read_uint32(&p.match.acl.n_rules, 2140 tokens[t0 + 5]) != 0) { 2141 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 2142 return; 2143 } 2144 2145 t0 += 6; 2146 } else if (strcmp(tokens[t0], "array") == 0) { 2147 if (n_tokens < t0 + 5) { 2148 snprintf(out, out_size, MSG_ARG_MISMATCH, 2149 "pipeline table array"); 2150 return; 2151 } 2152 2153 p.match_type = TABLE_ARRAY; 2154 2155 if (strcmp(tokens[t0 + 1], "offset") != 0) { 2156 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2157 return; 2158 } 2159 2160 if (softnic_parser_read_uint32(&p.match.array.key_offset, 2161 tokens[t0 + 2]) != 0) { 2162 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2163 return; 2164 } 2165 2166 if (strcmp(tokens[t0 + 3], "size") != 0) { 2167 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2168 return; 2169 } 2170 2171 if (softnic_parser_read_uint32(&p.match.array.n_keys, 2172 tokens[t0 + 4]) != 0) { 2173 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 2174 return; 2175 } 2176 2177 t0 += 5; 2178 } else if (strcmp(tokens[t0], "hash") == 0) { 2179 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; 2180 2181 if (n_tokens < t0 + 12) { 2182 snprintf(out, out_size, MSG_ARG_MISMATCH, 2183 "pipeline table hash"); 2184 return; 2185 } 2186 2187 p.match_type = TABLE_HASH; 2188 2189 if (strcmp(tokens[t0 + 1], "ext") == 0) { 2190 p.match.hash.extendable_bucket = 1; 2191 } else if (strcmp(tokens[t0 + 1], "lru") == 0) { 2192 p.match.hash.extendable_bucket = 0; 2193 } else { 2194 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2195 "ext or lru"); 2196 return; 2197 } 2198 2199 if (strcmp(tokens[t0 + 2], "key") != 0) { 2200 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 2201 return; 2202 } 2203 2204 if ((softnic_parser_read_uint32(&p.match.hash.key_size, 2205 tokens[t0 + 3]) != 0) || 2206 p.match.hash.key_size == 0 || 2207 p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) { 2208 snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); 2209 return; 2210 } 2211 2212 if (strcmp(tokens[t0 + 4], "mask") != 0) { 2213 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 2214 return; 2215 } 2216 2217 if ((softnic_parse_hex_string(tokens[t0 + 5], 2218 p.match.hash.key_mask, &key_mask_size) != 0) || 2219 key_mask_size != p.match.hash.key_size) { 2220 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 2221 return; 2222 } 2223 2224 if (strcmp(tokens[t0 + 6], "offset") != 0) { 2225 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2226 return; 2227 } 2228 2229 if (softnic_parser_read_uint32(&p.match.hash.key_offset, 2230 tokens[t0 + 7]) != 0) { 2231 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2232 return; 2233 } 2234 2235 if (strcmp(tokens[t0 + 8], "buckets") != 0) { 2236 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); 2237 return; 2238 } 2239 2240 if (softnic_parser_read_uint32(&p.match.hash.n_buckets, 2241 tokens[t0 + 9]) != 0) { 2242 snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); 2243 return; 2244 } 2245 2246 if (strcmp(tokens[t0 + 10], "size") != 0) { 2247 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2248 return; 2249 } 2250 2251 if (softnic_parser_read_uint32(&p.match.hash.n_keys, 2252 tokens[t0 + 11]) != 0) { 2253 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 2254 return; 2255 } 2256 2257 t0 += 12; 2258 } else if (strcmp(tokens[t0], "lpm") == 0) { 2259 if (n_tokens < t0 + 6) { 2260 snprintf(out, out_size, MSG_ARG_MISMATCH, 2261 "pipeline table lpm"); 2262 return; 2263 } 2264 2265 p.match_type = TABLE_LPM; 2266 2267 if (strcmp(tokens[t0 + 1], "ipv4") == 0) { 2268 p.match.lpm.key_size = 4; 2269 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { 2270 p.match.lpm.key_size = 16; 2271 } else { 2272 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2273 "ipv4 or ipv6"); 2274 return; 2275 } 2276 2277 if (strcmp(tokens[t0 + 2], "offset") != 0) { 2278 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2279 return; 2280 } 2281 2282 if (softnic_parser_read_uint32(&p.match.lpm.key_offset, 2283 tokens[t0 + 3]) != 0) { 2284 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2285 return; 2286 } 2287 2288 if (strcmp(tokens[t0 + 4], "size") != 0) { 2289 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2290 return; 2291 } 2292 2293 if (softnic_parser_read_uint32(&p.match.lpm.n_rules, 2294 tokens[t0 + 5]) != 0) { 2295 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 2296 return; 2297 } 2298 2299 t0 += 6; 2300 } else if (strcmp(tokens[t0], "stub") == 0) { 2301 p.match_type = TABLE_STUB; 2302 2303 t0 += 1; 2304 } else { 2305 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 2306 return; 2307 } 2308 2309 if (n_tokens > t0 && 2310 (strcmp(tokens[t0], "action") == 0)) { 2311 if (n_tokens < t0 + 2) { 2312 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 2313 return; 2314 } 2315 2316 strcpy(p.action_profile_name, tokens[t0 + 1]); 2317 2318 t0 += 2; 2319 } 2320 2321 if (n_tokens > t0) { 2322 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2323 return; 2324 } 2325 2326 status = softnic_pipeline_table_create(softnic, pipeline_name, &p); 2327 if (status) { 2328 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2329 return; 2330 } 2331 } 2332 2333 /** 2334 * pipeline <pipeline_name> port in <port_id> table <table_id> 2335 */ 2336 static void 2337 cmd_pipeline_port_in_table(struct pmd_internals *softnic, 2338 char **tokens, 2339 uint32_t n_tokens, 2340 char *out, 2341 size_t out_size) 2342 { 2343 char *pipeline_name; 2344 uint32_t port_id, table_id; 2345 int status; 2346 2347 if (n_tokens != 7) { 2348 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2349 return; 2350 } 2351 2352 pipeline_name = tokens[1]; 2353 2354 if (strcmp(tokens[2], "port") != 0) { 2355 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2356 return; 2357 } 2358 2359 if (strcmp(tokens[3], "in") != 0) { 2360 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2361 return; 2362 } 2363 2364 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2365 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2366 return; 2367 } 2368 2369 if (strcmp(tokens[5], "table") != 0) { 2370 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 2371 return; 2372 } 2373 2374 if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) { 2375 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2376 return; 2377 } 2378 2379 status = softnic_pipeline_port_in_connect_to_table(softnic, 2380 pipeline_name, 2381 port_id, 2382 table_id); 2383 if (status) { 2384 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2385 return; 2386 } 2387 } 2388 2389 /** 2390 * pipeline <pipeline_name> port in <port_id> stats read [clear] 2391 */ 2392 2393 #define MSG_PIPELINE_PORT_IN_STATS \ 2394 "Pkts in: %" PRIu64 "\n" \ 2395 "Pkts dropped by AH: %" PRIu64 "\n" \ 2396 "Pkts dropped by other: %" PRIu64 "\n" 2397 2398 static void 2399 cmd_pipeline_port_in_stats(struct pmd_internals *softnic, 2400 char **tokens, 2401 uint32_t n_tokens, 2402 char *out, 2403 size_t out_size) 2404 { 2405 struct rte_pipeline_port_in_stats stats; 2406 char *pipeline_name; 2407 uint32_t port_id; 2408 int clear, status; 2409 2410 if (n_tokens != 7 && 2411 n_tokens != 8) { 2412 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2413 return; 2414 } 2415 2416 pipeline_name = tokens[1]; 2417 2418 if (strcmp(tokens[2], "port") != 0) { 2419 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2420 return; 2421 } 2422 2423 if (strcmp(tokens[3], "in") != 0) { 2424 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2425 return; 2426 } 2427 2428 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2429 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2430 return; 2431 } 2432 2433 if (strcmp(tokens[5], "stats") != 0) { 2434 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2435 return; 2436 } 2437 2438 if (strcmp(tokens[6], "read") != 0) { 2439 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2440 return; 2441 } 2442 2443 clear = 0; 2444 if (n_tokens == 8) { 2445 if (strcmp(tokens[7], "clear") != 0) { 2446 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2447 return; 2448 } 2449 2450 clear = 1; 2451 } 2452 2453 status = softnic_pipeline_port_in_stats_read(softnic, 2454 pipeline_name, 2455 port_id, 2456 &stats, 2457 clear); 2458 if (status) { 2459 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2460 return; 2461 } 2462 2463 snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, 2464 stats.stats.n_pkts_in, 2465 stats.n_pkts_dropped_by_ah, 2466 stats.stats.n_pkts_drop); 2467 } 2468 2469 /** 2470 * pipeline <pipeline_name> port in <port_id> enable 2471 */ 2472 static void 2473 cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic, 2474 char **tokens, 2475 uint32_t n_tokens, 2476 char *out, 2477 size_t out_size) 2478 { 2479 char *pipeline_name; 2480 uint32_t port_id; 2481 int status; 2482 2483 if (n_tokens != 6) { 2484 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2485 return; 2486 } 2487 2488 pipeline_name = tokens[1]; 2489 2490 if (strcmp(tokens[2], "port") != 0) { 2491 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2492 return; 2493 } 2494 2495 if (strcmp(tokens[3], "in") != 0) { 2496 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2497 return; 2498 } 2499 2500 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2501 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2502 return; 2503 } 2504 2505 if (strcmp(tokens[5], "enable") != 0) { 2506 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2507 return; 2508 } 2509 2510 status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id); 2511 if (status) { 2512 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2513 return; 2514 } 2515 } 2516 2517 /** 2518 * pipeline <pipeline_name> port in <port_id> disable 2519 */ 2520 static void 2521 cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic, 2522 char **tokens, 2523 uint32_t n_tokens, 2524 char *out, 2525 size_t out_size) 2526 { 2527 char *pipeline_name; 2528 uint32_t port_id; 2529 int status; 2530 2531 if (n_tokens != 6) { 2532 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2533 return; 2534 } 2535 2536 pipeline_name = tokens[1]; 2537 2538 if (strcmp(tokens[2], "port") != 0) { 2539 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2540 return; 2541 } 2542 2543 if (strcmp(tokens[3], "in") != 0) { 2544 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2545 return; 2546 } 2547 2548 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2549 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2550 return; 2551 } 2552 2553 if (strcmp(tokens[5], "disable") != 0) { 2554 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2555 return; 2556 } 2557 2558 status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id); 2559 if (status) { 2560 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2561 return; 2562 } 2563 } 2564 2565 /** 2566 * pipeline <pipeline_name> port out <port_id> stats read [clear] 2567 */ 2568 #define MSG_PIPELINE_PORT_OUT_STATS \ 2569 "Pkts in: %" PRIu64 "\n" \ 2570 "Pkts dropped by AH: %" PRIu64 "\n" \ 2571 "Pkts dropped by other: %" PRIu64 "\n" 2572 2573 static void 2574 cmd_pipeline_port_out_stats(struct pmd_internals *softnic, 2575 char **tokens, 2576 uint32_t n_tokens, 2577 char *out, 2578 size_t out_size) 2579 { 2580 struct rte_pipeline_port_out_stats stats; 2581 char *pipeline_name; 2582 uint32_t port_id; 2583 int clear, status; 2584 2585 if (n_tokens != 7 && 2586 n_tokens != 8) { 2587 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2588 return; 2589 } 2590 2591 pipeline_name = tokens[1]; 2592 2593 if (strcmp(tokens[2], "port") != 0) { 2594 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2595 return; 2596 } 2597 2598 if (strcmp(tokens[3], "out") != 0) { 2599 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 2600 return; 2601 } 2602 2603 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2604 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2605 return; 2606 } 2607 2608 if (strcmp(tokens[5], "stats") != 0) { 2609 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2610 return; 2611 } 2612 2613 if (strcmp(tokens[6], "read") != 0) { 2614 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2615 return; 2616 } 2617 2618 clear = 0; 2619 if (n_tokens == 8) { 2620 if (strcmp(tokens[7], "clear") != 0) { 2621 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2622 return; 2623 } 2624 2625 clear = 1; 2626 } 2627 2628 status = softnic_pipeline_port_out_stats_read(softnic, 2629 pipeline_name, 2630 port_id, 2631 &stats, 2632 clear); 2633 if (status) { 2634 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2635 return; 2636 } 2637 2638 snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, 2639 stats.stats.n_pkts_in, 2640 stats.n_pkts_dropped_by_ah, 2641 stats.stats.n_pkts_drop); 2642 } 2643 2644 /** 2645 * pipeline <pipeline_name> table <table_id> stats read [clear] 2646 */ 2647 #define MSG_PIPELINE_TABLE_STATS \ 2648 "Pkts in: %" PRIu64 "\n" \ 2649 "Pkts in with lookup miss: %" PRIu64 "\n" \ 2650 "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ 2651 "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ 2652 "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ 2653 "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" 2654 2655 static void 2656 cmd_pipeline_table_stats(struct pmd_internals *softnic, 2657 char **tokens, 2658 uint32_t n_tokens, 2659 char *out, 2660 size_t out_size) 2661 { 2662 struct rte_pipeline_table_stats stats; 2663 char *pipeline_name; 2664 uint32_t table_id; 2665 int clear, status; 2666 2667 if (n_tokens != 6 && 2668 n_tokens != 7) { 2669 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2670 return; 2671 } 2672 2673 pipeline_name = tokens[1]; 2674 2675 if (strcmp(tokens[2], "table") != 0) { 2676 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2677 return; 2678 } 2679 2680 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 2681 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2682 return; 2683 } 2684 2685 if (strcmp(tokens[4], "stats") != 0) { 2686 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2687 return; 2688 } 2689 2690 if (strcmp(tokens[5], "read") != 0) { 2691 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2692 return; 2693 } 2694 2695 clear = 0; 2696 if (n_tokens == 7) { 2697 if (strcmp(tokens[6], "clear") != 0) { 2698 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2699 return; 2700 } 2701 2702 clear = 1; 2703 } 2704 2705 status = softnic_pipeline_table_stats_read(softnic, 2706 pipeline_name, 2707 table_id, 2708 &stats, 2709 clear); 2710 if (status) { 2711 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2712 return; 2713 } 2714 2715 snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, 2716 stats.stats.n_pkts_in, 2717 stats.stats.n_pkts_lookup_miss, 2718 stats.n_pkts_dropped_by_lkp_hit_ah, 2719 stats.n_pkts_dropped_lkp_hit, 2720 stats.n_pkts_dropped_by_lkp_miss_ah, 2721 stats.n_pkts_dropped_lkp_miss); 2722 } 2723 2724 /** 2725 * <match> ::= 2726 * 2727 * match 2728 * acl 2729 * priority <priority> 2730 * ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth> 2731 * <sp0> <sp1> <dp0> <dp1> <proto> 2732 * | array <pos> 2733 * | hash 2734 * raw <key> 2735 * | ipv4_5tuple <sa> <da> <sp> <dp> <proto> 2736 * | ipv6_5tuple <sa> <da> <sp> <dp> <proto> 2737 * | ipv4_addr <addr> 2738 * | ipv6_addr <addr> 2739 * | qinq <svlan> <cvlan> 2740 * | lpm 2741 * ipv4 | ipv6 <addr> <depth> 2742 */ 2743 struct pkt_key_qinq { 2744 uint16_t ethertype_svlan; 2745 uint16_t svlan; 2746 uint16_t ethertype_cvlan; 2747 uint16_t cvlan; 2748 } __attribute__((__packed__)); 2749 2750 struct pkt_key_ipv4_5tuple { 2751 uint8_t time_to_live; 2752 uint8_t proto; 2753 uint16_t hdr_checksum; 2754 uint32_t sa; 2755 uint32_t da; 2756 uint16_t sp; 2757 uint16_t dp; 2758 } __attribute__((__packed__)); 2759 2760 struct pkt_key_ipv6_5tuple { 2761 uint16_t payload_length; 2762 uint8_t proto; 2763 uint8_t hop_limit; 2764 uint8_t sa[16]; 2765 uint8_t da[16]; 2766 uint16_t sp; 2767 uint16_t dp; 2768 } __attribute__((__packed__)); 2769 2770 struct pkt_key_ipv4_addr { 2771 uint32_t addr; 2772 } __attribute__((__packed__)); 2773 2774 struct pkt_key_ipv6_addr { 2775 uint8_t addr[16]; 2776 } __attribute__((__packed__)); 2777 2778 static uint32_t 2779 parse_match(char **tokens, 2780 uint32_t n_tokens, 2781 char *out, 2782 size_t out_size, 2783 struct softnic_table_rule_match *m) 2784 { 2785 memset(m, 0, sizeof(*m)); 2786 2787 if (n_tokens < 2) 2788 return 0; 2789 2790 if (strcmp(tokens[0], "match") != 0) { 2791 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2792 return 0; 2793 } 2794 2795 if (strcmp(tokens[1], "acl") == 0) { 2796 if (n_tokens < 14) { 2797 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2798 return 0; 2799 } 2800 2801 m->match_type = TABLE_ACL; 2802 2803 if (strcmp(tokens[2], "priority") != 0) { 2804 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); 2805 return 0; 2806 } 2807 2808 if (softnic_parser_read_uint32(&m->match.acl.priority, 2809 tokens[3]) != 0) { 2810 snprintf(out, out_size, MSG_ARG_INVALID, "priority"); 2811 return 0; 2812 } 2813 2814 if (strcmp(tokens[4], "ipv4") == 0) { 2815 struct in_addr saddr, daddr; 2816 2817 m->match.acl.ip_version = 1; 2818 2819 if (softnic_parse_ipv4_addr(tokens[5], &saddr) != 0) { 2820 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2821 return 0; 2822 } 2823 m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); 2824 2825 if (softnic_parse_ipv4_addr(tokens[7], &daddr) != 0) { 2826 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2827 return 0; 2828 } 2829 m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); 2830 } else if (strcmp(tokens[4], "ipv6") == 0) { 2831 struct in6_addr saddr, daddr; 2832 2833 m->match.acl.ip_version = 0; 2834 2835 if (softnic_parse_ipv6_addr(tokens[5], &saddr) != 0) { 2836 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2837 return 0; 2838 } 2839 memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); 2840 2841 if (softnic_parse_ipv6_addr(tokens[7], &daddr) != 0) { 2842 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2843 return 0; 2844 } 2845 memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); 2846 } else { 2847 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2848 "ipv4 or ipv6"); 2849 return 0; 2850 } 2851 2852 if (softnic_parser_read_uint32(&m->match.acl.sa_depth, 2853 tokens[6]) != 0) { 2854 snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); 2855 return 0; 2856 } 2857 2858 if (softnic_parser_read_uint32(&m->match.acl.da_depth, 2859 tokens[8]) != 0) { 2860 snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); 2861 return 0; 2862 } 2863 2864 if (softnic_parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { 2865 snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); 2866 return 0; 2867 } 2868 2869 if (softnic_parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { 2870 snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); 2871 return 0; 2872 } 2873 2874 if (softnic_parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { 2875 snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); 2876 return 0; 2877 } 2878 2879 if (softnic_parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { 2880 snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); 2881 return 0; 2882 } 2883 2884 if (softnic_parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { 2885 snprintf(out, out_size, MSG_ARG_INVALID, "proto"); 2886 return 0; 2887 } 2888 2889 m->match.acl.proto_mask = 0xff; 2890 2891 return 14; 2892 } /* acl */ 2893 2894 if (strcmp(tokens[1], "array") == 0) { 2895 if (n_tokens < 3) { 2896 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2897 return 0; 2898 } 2899 2900 m->match_type = TABLE_ARRAY; 2901 2902 if (softnic_parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { 2903 snprintf(out, out_size, MSG_ARG_INVALID, "pos"); 2904 return 0; 2905 } 2906 2907 return 3; 2908 } /* array */ 2909 2910 if (strcmp(tokens[1], "hash") == 0) { 2911 if (n_tokens < 3) { 2912 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2913 return 0; 2914 } 2915 2916 m->match_type = TABLE_HASH; 2917 2918 if (strcmp(tokens[2], "raw") == 0) { 2919 uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; 2920 2921 if (n_tokens < 4) { 2922 snprintf(out, out_size, MSG_ARG_MISMATCH, 2923 tokens[0]); 2924 return 0; 2925 } 2926 2927 if (softnic_parse_hex_string(tokens[3], 2928 m->match.hash.key, &key_size) != 0) { 2929 snprintf(out, out_size, MSG_ARG_INVALID, "key"); 2930 return 0; 2931 } 2932 2933 return 4; 2934 } /* hash raw */ 2935 2936 if (strcmp(tokens[2], "ipv4_5tuple") == 0) { 2937 struct pkt_key_ipv4_5tuple *ipv4 = 2938 (struct pkt_key_ipv4_5tuple *)m->match.hash.key; 2939 struct in_addr saddr, daddr; 2940 uint16_t sp, dp; 2941 uint8_t proto; 2942 2943 if (n_tokens < 8) { 2944 snprintf(out, out_size, MSG_ARG_MISMATCH, 2945 tokens[0]); 2946 return 0; 2947 } 2948 2949 if (softnic_parse_ipv4_addr(tokens[3], &saddr) != 0) { 2950 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2951 return 0; 2952 } 2953 2954 if (softnic_parse_ipv4_addr(tokens[4], &daddr) != 0) { 2955 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2956 return 0; 2957 } 2958 2959 if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { 2960 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 2961 return 0; 2962 } 2963 2964 if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { 2965 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 2966 return 0; 2967 } 2968 2969 if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { 2970 snprintf(out, out_size, MSG_ARG_INVALID, 2971 "proto"); 2972 return 0; 2973 } 2974 2975 ipv4->sa = saddr.s_addr; 2976 ipv4->da = daddr.s_addr; 2977 ipv4->sp = rte_cpu_to_be_16(sp); 2978 ipv4->dp = rte_cpu_to_be_16(dp); 2979 ipv4->proto = proto; 2980 2981 return 8; 2982 } /* hash ipv4_5tuple */ 2983 2984 if (strcmp(tokens[2], "ipv6_5tuple") == 0) { 2985 struct pkt_key_ipv6_5tuple *ipv6 = 2986 (struct pkt_key_ipv6_5tuple *)m->match.hash.key; 2987 struct in6_addr saddr, daddr; 2988 uint16_t sp, dp; 2989 uint8_t proto; 2990 2991 if (n_tokens < 8) { 2992 snprintf(out, out_size, MSG_ARG_MISMATCH, 2993 tokens[0]); 2994 return 0; 2995 } 2996 2997 if (softnic_parse_ipv6_addr(tokens[3], &saddr) != 0) { 2998 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2999 return 0; 3000 } 3001 3002 if (softnic_parse_ipv6_addr(tokens[4], &daddr) != 0) { 3003 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 3004 return 0; 3005 } 3006 3007 if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { 3008 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 3009 return 0; 3010 } 3011 3012 if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { 3013 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 3014 return 0; 3015 } 3016 3017 if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { 3018 snprintf(out, out_size, MSG_ARG_INVALID, 3019 "proto"); 3020 return 0; 3021 } 3022 3023 memcpy(ipv6->sa, saddr.s6_addr, 16); 3024 memcpy(ipv6->da, daddr.s6_addr, 16); 3025 ipv6->sp = rte_cpu_to_be_16(sp); 3026 ipv6->dp = rte_cpu_to_be_16(dp); 3027 ipv6->proto = proto; 3028 3029 return 8; 3030 } /* hash ipv6_5tuple */ 3031 3032 if (strcmp(tokens[2], "ipv4_addr") == 0) { 3033 struct pkt_key_ipv4_addr *ipv4_addr = 3034 (struct pkt_key_ipv4_addr *)m->match.hash.key; 3035 struct in_addr addr; 3036 3037 if (n_tokens < 4) { 3038 snprintf(out, out_size, MSG_ARG_MISMATCH, 3039 tokens[0]); 3040 return 0; 3041 } 3042 3043 if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { 3044 snprintf(out, out_size, MSG_ARG_INVALID, 3045 "addr"); 3046 return 0; 3047 } 3048 3049 ipv4_addr->addr = addr.s_addr; 3050 3051 return 4; 3052 } /* hash ipv4_addr */ 3053 3054 if (strcmp(tokens[2], "ipv6_addr") == 0) { 3055 struct pkt_key_ipv6_addr *ipv6_addr = 3056 (struct pkt_key_ipv6_addr *)m->match.hash.key; 3057 struct in6_addr addr; 3058 3059 if (n_tokens < 4) { 3060 snprintf(out, out_size, MSG_ARG_MISMATCH, 3061 tokens[0]); 3062 return 0; 3063 } 3064 3065 if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { 3066 snprintf(out, out_size, MSG_ARG_INVALID, 3067 "addr"); 3068 return 0; 3069 } 3070 3071 memcpy(ipv6_addr->addr, addr.s6_addr, 16); 3072 3073 return 4; 3074 } /* hash ipv6_5tuple */ 3075 3076 if (strcmp(tokens[2], "qinq") == 0) { 3077 struct pkt_key_qinq *qinq = 3078 (struct pkt_key_qinq *)m->match.hash.key; 3079 uint16_t svlan, cvlan; 3080 3081 if (n_tokens < 5) { 3082 snprintf(out, out_size, MSG_ARG_MISMATCH, 3083 tokens[0]); 3084 return 0; 3085 } 3086 3087 if ((softnic_parser_read_uint16(&svlan, tokens[3]) != 0) || 3088 svlan > 0xFFF) { 3089 snprintf(out, out_size, MSG_ARG_INVALID, 3090 "svlan"); 3091 return 0; 3092 } 3093 3094 if ((softnic_parser_read_uint16(&cvlan, tokens[4]) != 0) || 3095 cvlan > 0xFFF) { 3096 snprintf(out, out_size, MSG_ARG_INVALID, 3097 "cvlan"); 3098 return 0; 3099 } 3100 3101 qinq->svlan = rte_cpu_to_be_16(svlan); 3102 qinq->cvlan = rte_cpu_to_be_16(cvlan); 3103 3104 return 5; 3105 } /* hash qinq */ 3106 3107 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3108 return 0; 3109 } /* hash */ 3110 3111 if (strcmp(tokens[1], "lpm") == 0) { 3112 if (n_tokens < 5) { 3113 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3114 return 0; 3115 } 3116 3117 m->match_type = TABLE_LPM; 3118 3119 if (strcmp(tokens[2], "ipv4") == 0) { 3120 struct in_addr addr; 3121 3122 m->match.lpm.ip_version = 1; 3123 3124 if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { 3125 snprintf(out, out_size, MSG_ARG_INVALID, 3126 "addr"); 3127 return 0; 3128 } 3129 3130 m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr); 3131 } else if (strcmp(tokens[2], "ipv6") == 0) { 3132 struct in6_addr addr; 3133 3134 m->match.lpm.ip_version = 0; 3135 3136 if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { 3137 snprintf(out, out_size, MSG_ARG_INVALID, 3138 "addr"); 3139 return 0; 3140 } 3141 3142 memcpy(m->match.lpm.ipv6, addr.s6_addr, 16); 3143 } else { 3144 snprintf(out, out_size, MSG_ARG_MISMATCH, 3145 "ipv4 or ipv6"); 3146 return 0; 3147 } 3148 3149 if (softnic_parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) { 3150 snprintf(out, out_size, MSG_ARG_INVALID, "depth"); 3151 return 0; 3152 } 3153 3154 return 5; 3155 } /* lpm */ 3156 3157 snprintf(out, out_size, MSG_ARG_MISMATCH, 3158 "acl or array or hash or lpm"); 3159 return 0; 3160 } 3161 3162 /** 3163 * table_action ::= 3164 * 3165 * action 3166 * fwd 3167 * drop 3168 * | port <port_id> 3169 * | meta 3170 * | table <table_id> 3171 * [balance <out0> ... <out7>] 3172 * [meter 3173 * tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3174 * [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3175 * tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3176 * tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]] 3177 * [tm subport <subport_id> pipe <pipe_id>] 3178 * [encap 3179 * ether <da> <sa> 3180 * | vlan <da> <sa> <pcp> <dei> <vid> 3181 * | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid> 3182 * | mpls unicast | multicast 3183 * <da> <sa> 3184 * label0 <label> <tc> <ttl> 3185 * [label1 <label> <tc> <ttl> 3186 * [label2 <label> <tc> <ttl> 3187 * [label3 <label> <tc> <ttl>]]] 3188 * | pppoe <da> <sa> <session_id>] 3189 * [nat ipv4 | ipv6 <addr> <port>] 3190 * [ttl dec | keep] 3191 * [stats] 3192 * [time] 3193 * [tag <tag>] 3194 * [decap <n>] 3195 * 3196 * where: 3197 * <pa> ::= g | y | r | drop 3198 */ 3199 static uint32_t 3200 parse_table_action_fwd(char **tokens, 3201 uint32_t n_tokens, 3202 struct softnic_table_rule_action *a) 3203 { 3204 if (n_tokens == 0 || 3205 (strcmp(tokens[0], "fwd") != 0)) 3206 return 0; 3207 3208 tokens++; 3209 n_tokens--; 3210 3211 if (n_tokens && (strcmp(tokens[0], "drop") == 0)) { 3212 a->fwd.action = RTE_PIPELINE_ACTION_DROP; 3213 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3214 return 1 + 1; 3215 } 3216 3217 if (n_tokens && (strcmp(tokens[0], "port") == 0)) { 3218 uint32_t id; 3219 3220 if (n_tokens < 2 || 3221 softnic_parser_read_uint32(&id, tokens[1])) 3222 return 0; 3223 3224 a->fwd.action = RTE_PIPELINE_ACTION_PORT; 3225 a->fwd.id = id; 3226 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3227 return 1 + 2; 3228 } 3229 3230 if (n_tokens && (strcmp(tokens[0], "meta") == 0)) { 3231 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META; 3232 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3233 return 1 + 1; 3234 } 3235 3236 if (n_tokens && (strcmp(tokens[0], "table") == 0)) { 3237 uint32_t id; 3238 3239 if (n_tokens < 2 || 3240 softnic_parser_read_uint32(&id, tokens[1])) 3241 return 0; 3242 3243 a->fwd.action = RTE_PIPELINE_ACTION_TABLE; 3244 a->fwd.id = id; 3245 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3246 return 1 + 2; 3247 } 3248 3249 return 0; 3250 } 3251 3252 static uint32_t 3253 parse_table_action_balance(char **tokens, 3254 uint32_t n_tokens, 3255 struct softnic_table_rule_action *a) 3256 { 3257 uint32_t i; 3258 3259 if (n_tokens == 0 || 3260 (strcmp(tokens[0], "balance") != 0)) 3261 return 0; 3262 3263 tokens++; 3264 n_tokens--; 3265 3266 if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE) 3267 return 0; 3268 3269 for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++) 3270 if (softnic_parser_read_uint32(&a->lb.out[i], tokens[i]) != 0) 3271 return 0; 3272 3273 a->action_mask |= 1 << RTE_TABLE_ACTION_LB; 3274 return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE; 3275 } 3276 3277 static int 3278 parse_policer_action(char *token, enum rte_table_action_policer *a) 3279 { 3280 if (strcmp(token, "g") == 0) { 3281 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN; 3282 return 0; 3283 } 3284 3285 if (strcmp(token, "y") == 0) { 3286 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW; 3287 return 0; 3288 } 3289 3290 if (strcmp(token, "r") == 0) { 3291 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED; 3292 return 0; 3293 } 3294 3295 if (strcmp(token, "drop") == 0) { 3296 *a = RTE_TABLE_ACTION_POLICER_DROP; 3297 return 0; 3298 } 3299 3300 return -1; 3301 } 3302 3303 static uint32_t 3304 parse_table_action_meter_tc(char **tokens, 3305 uint32_t n_tokens, 3306 struct rte_table_action_mtr_tc_params *mtr) 3307 { 3308 if (n_tokens < 9 || 3309 strcmp(tokens[0], "meter") || 3310 softnic_parser_read_uint32(&mtr->meter_profile_id, tokens[1]) || 3311 strcmp(tokens[2], "policer") || 3312 strcmp(tokens[3], "g") || 3313 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) || 3314 strcmp(tokens[5], "y") || 3315 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) || 3316 strcmp(tokens[7], "r") || 3317 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED])) 3318 return 0; 3319 3320 return 9; 3321 } 3322 3323 static uint32_t 3324 parse_table_action_meter(char **tokens, 3325 uint32_t n_tokens, 3326 struct softnic_table_rule_action *a) 3327 { 3328 if (n_tokens == 0 || 3329 strcmp(tokens[0], "meter")) 3330 return 0; 3331 3332 tokens++; 3333 n_tokens--; 3334 3335 if (n_tokens < 10 || 3336 strcmp(tokens[0], "tc0") || 3337 (parse_table_action_meter_tc(tokens + 1, 3338 n_tokens - 1, 3339 &a->mtr.mtr[0]) == 0)) 3340 return 0; 3341 3342 tokens += 10; 3343 n_tokens -= 10; 3344 3345 if (n_tokens == 0 || 3346 strcmp(tokens[0], "tc1")) { 3347 a->mtr.tc_mask = 1; 3348 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 3349 return 1 + 10; 3350 } 3351 3352 if (n_tokens < 30 || 3353 (parse_table_action_meter_tc(tokens + 1, 3354 n_tokens - 1, &a->mtr.mtr[1]) == 0) || 3355 strcmp(tokens[10], "tc2") || 3356 (parse_table_action_meter_tc(tokens + 11, 3357 n_tokens - 11, &a->mtr.mtr[2]) == 0) || 3358 strcmp(tokens[20], "tc3") || 3359 (parse_table_action_meter_tc(tokens + 21, 3360 n_tokens - 21, &a->mtr.mtr[3]) == 0)) 3361 return 0; 3362 3363 a->mtr.tc_mask = 0xF; 3364 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 3365 return 1 + 10 + 3 * 10; 3366 } 3367 3368 static uint32_t 3369 parse_table_action_tm(char **tokens, 3370 uint32_t n_tokens, 3371 struct softnic_table_rule_action *a) 3372 { 3373 uint32_t subport_id, pipe_id; 3374 3375 if (n_tokens < 5 || 3376 strcmp(tokens[0], "tm") || 3377 strcmp(tokens[1], "subport") || 3378 softnic_parser_read_uint32(&subport_id, tokens[2]) || 3379 strcmp(tokens[3], "pipe") || 3380 softnic_parser_read_uint32(&pipe_id, tokens[4])) 3381 return 0; 3382 3383 a->tm.subport_id = subport_id; 3384 a->tm.pipe_id = pipe_id; 3385 a->action_mask |= 1 << RTE_TABLE_ACTION_TM; 3386 return 5; 3387 } 3388 3389 static uint32_t 3390 parse_table_action_encap(char **tokens, 3391 uint32_t n_tokens, 3392 struct softnic_table_rule_action *a) 3393 { 3394 if (n_tokens == 0 || 3395 strcmp(tokens[0], "encap")) 3396 return 0; 3397 3398 tokens++; 3399 n_tokens--; 3400 3401 /* ether */ 3402 if (n_tokens && (strcmp(tokens[0], "ether") == 0)) { 3403 if (n_tokens < 3 || 3404 softnic_parse_mac_addr(tokens[1], &a->encap.ether.ether.da) || 3405 softnic_parse_mac_addr(tokens[2], &a->encap.ether.ether.sa)) 3406 return 0; 3407 3408 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER; 3409 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3410 return 1 + 3; 3411 } 3412 3413 /* vlan */ 3414 if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) { 3415 uint32_t pcp, dei, vid; 3416 3417 if (n_tokens < 6 || 3418 softnic_parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) || 3419 softnic_parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) || 3420 softnic_parser_read_uint32(&pcp, tokens[3]) || 3421 pcp > 0x7 || 3422 softnic_parser_read_uint32(&dei, tokens[4]) || 3423 dei > 0x1 || 3424 softnic_parser_read_uint32(&vid, tokens[5]) || 3425 vid > 0xFFF) 3426 return 0; 3427 3428 a->encap.vlan.vlan.pcp = pcp & 0x7; 3429 a->encap.vlan.vlan.dei = dei & 0x1; 3430 a->encap.vlan.vlan.vid = vid & 0xFFF; 3431 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN; 3432 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3433 return 1 + 6; 3434 } 3435 3436 /* qinq */ 3437 if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) { 3438 uint32_t svlan_pcp, svlan_dei, svlan_vid; 3439 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid; 3440 3441 if (n_tokens < 9 || 3442 softnic_parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) || 3443 softnic_parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) || 3444 softnic_parser_read_uint32(&svlan_pcp, tokens[3]) || 3445 svlan_pcp > 0x7 || 3446 softnic_parser_read_uint32(&svlan_dei, tokens[4]) || 3447 svlan_dei > 0x1 || 3448 softnic_parser_read_uint32(&svlan_vid, tokens[5]) || 3449 svlan_vid > 0xFFF || 3450 softnic_parser_read_uint32(&cvlan_pcp, tokens[6]) || 3451 cvlan_pcp > 0x7 || 3452 softnic_parser_read_uint32(&cvlan_dei, tokens[7]) || 3453 cvlan_dei > 0x1 || 3454 softnic_parser_read_uint32(&cvlan_vid, tokens[8]) || 3455 cvlan_vid > 0xFFF) 3456 return 0; 3457 3458 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7; 3459 a->encap.qinq.svlan.dei = svlan_dei & 0x1; 3460 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF; 3461 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7; 3462 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1; 3463 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF; 3464 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ; 3465 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3466 return 1 + 9; 3467 } 3468 3469 /* mpls */ 3470 if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) { 3471 uint32_t label, tc, ttl; 3472 3473 if (n_tokens < 8) 3474 return 0; 3475 3476 if (strcmp(tokens[1], "unicast") == 0) 3477 a->encap.mpls.unicast = 1; 3478 else if (strcmp(tokens[1], "multicast") == 0) 3479 a->encap.mpls.unicast = 0; 3480 else 3481 return 0; 3482 3483 if (softnic_parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) || 3484 softnic_parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) || 3485 strcmp(tokens[4], "label0") || 3486 softnic_parser_read_uint32(&label, tokens[5]) || 3487 label > 0xFFFFF || 3488 softnic_parser_read_uint32(&tc, tokens[6]) || 3489 tc > 0x7 || 3490 softnic_parser_read_uint32(&ttl, tokens[7]) || 3491 ttl > 0x3F) 3492 return 0; 3493 3494 a->encap.mpls.mpls[0].label = label; 3495 a->encap.mpls.mpls[0].tc = tc; 3496 a->encap.mpls.mpls[0].ttl = ttl; 3497 3498 tokens += 8; 3499 n_tokens -= 8; 3500 3501 if (n_tokens == 0 || 3502 strcmp(tokens[0], "label1")) { 3503 a->encap.mpls.mpls_count = 1; 3504 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3505 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3506 return 1 + 8; 3507 } 3508 3509 if (n_tokens < 4 || 3510 softnic_parser_read_uint32(&label, tokens[1]) || 3511 label > 0xFFFFF || 3512 softnic_parser_read_uint32(&tc, tokens[2]) || 3513 tc > 0x7 || 3514 softnic_parser_read_uint32(&ttl, tokens[3]) || 3515 ttl > 0x3F) 3516 return 0; 3517 3518 a->encap.mpls.mpls[1].label = label; 3519 a->encap.mpls.mpls[1].tc = tc; 3520 a->encap.mpls.mpls[1].ttl = ttl; 3521 3522 tokens += 4; 3523 n_tokens -= 4; 3524 3525 if (n_tokens == 0 || 3526 strcmp(tokens[0], "label2")) { 3527 a->encap.mpls.mpls_count = 2; 3528 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3529 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3530 return 1 + 8 + 4; 3531 } 3532 3533 if (n_tokens < 4 || 3534 softnic_parser_read_uint32(&label, tokens[1]) || 3535 label > 0xFFFFF || 3536 softnic_parser_read_uint32(&tc, tokens[2]) || 3537 tc > 0x7 || 3538 softnic_parser_read_uint32(&ttl, tokens[3]) || 3539 ttl > 0x3F) 3540 return 0; 3541 3542 a->encap.mpls.mpls[2].label = label; 3543 a->encap.mpls.mpls[2].tc = tc; 3544 a->encap.mpls.mpls[2].ttl = ttl; 3545 3546 tokens += 4; 3547 n_tokens -= 4; 3548 3549 if (n_tokens == 0 || 3550 strcmp(tokens[0], "label3")) { 3551 a->encap.mpls.mpls_count = 3; 3552 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3553 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3554 return 1 + 8 + 4 + 4; 3555 } 3556 3557 if (n_tokens < 4 || 3558 softnic_parser_read_uint32(&label, tokens[1]) || 3559 label > 0xFFFFF || 3560 softnic_parser_read_uint32(&tc, tokens[2]) || 3561 tc > 0x7 || 3562 softnic_parser_read_uint32(&ttl, tokens[3]) || 3563 ttl > 0x3F) 3564 return 0; 3565 3566 a->encap.mpls.mpls[3].label = label; 3567 a->encap.mpls.mpls[3].tc = tc; 3568 a->encap.mpls.mpls[3].ttl = ttl; 3569 3570 a->encap.mpls.mpls_count = 4; 3571 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3572 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3573 return 1 + 8 + 4 + 4 + 4; 3574 } 3575 3576 /* pppoe */ 3577 if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) { 3578 if (n_tokens < 4 || 3579 softnic_parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) || 3580 softnic_parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) || 3581 softnic_parser_read_uint16(&a->encap.pppoe.pppoe.session_id, 3582 tokens[3])) 3583 return 0; 3584 3585 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE; 3586 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3587 return 1 + 4; 3588 } 3589 3590 return 0; 3591 } 3592 3593 static uint32_t 3594 parse_table_action_nat(char **tokens, 3595 uint32_t n_tokens, 3596 struct softnic_table_rule_action *a) 3597 { 3598 if (n_tokens < 4 || 3599 strcmp(tokens[0], "nat")) 3600 return 0; 3601 3602 if (strcmp(tokens[1], "ipv4") == 0) { 3603 struct in_addr addr; 3604 uint16_t port; 3605 3606 if (softnic_parse_ipv4_addr(tokens[2], &addr) || 3607 softnic_parser_read_uint16(&port, tokens[3])) 3608 return 0; 3609 3610 a->nat.ip_version = 1; 3611 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr); 3612 a->nat.port = port; 3613 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3614 return 4; 3615 } 3616 3617 if (strcmp(tokens[1], "ipv6") == 0) { 3618 struct in6_addr addr; 3619 uint16_t port; 3620 3621 if (softnic_parse_ipv6_addr(tokens[2], &addr) || 3622 softnic_parser_read_uint16(&port, tokens[3])) 3623 return 0; 3624 3625 a->nat.ip_version = 0; 3626 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16); 3627 a->nat.port = port; 3628 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3629 return 4; 3630 } 3631 3632 return 0; 3633 } 3634 3635 static uint32_t 3636 parse_table_action_ttl(char **tokens, 3637 uint32_t n_tokens, 3638 struct softnic_table_rule_action *a) 3639 { 3640 if (n_tokens < 2 || 3641 strcmp(tokens[0], "ttl")) 3642 return 0; 3643 3644 if (strcmp(tokens[1], "dec") == 0) 3645 a->ttl.decrement = 1; 3646 else if (strcmp(tokens[1], "keep") == 0) 3647 a->ttl.decrement = 0; 3648 else 3649 return 0; 3650 3651 a->action_mask |= 1 << RTE_TABLE_ACTION_TTL; 3652 return 2; 3653 } 3654 3655 static uint32_t 3656 parse_table_action_stats(char **tokens, 3657 uint32_t n_tokens, 3658 struct softnic_table_rule_action *a) 3659 { 3660 if (n_tokens < 1 || 3661 strcmp(tokens[0], "stats")) 3662 return 0; 3663 3664 a->stats.n_packets = 0; 3665 a->stats.n_bytes = 0; 3666 a->action_mask |= 1 << RTE_TABLE_ACTION_STATS; 3667 return 1; 3668 } 3669 3670 static uint32_t 3671 parse_table_action_time(char **tokens, 3672 uint32_t n_tokens, 3673 struct softnic_table_rule_action *a) 3674 { 3675 if (n_tokens < 1 || 3676 strcmp(tokens[0], "time")) 3677 return 0; 3678 3679 a->time.time = rte_rdtsc(); 3680 a->action_mask |= 1 << RTE_TABLE_ACTION_TIME; 3681 return 1; 3682 } 3683 3684 static uint32_t 3685 parse_table_action_tag(char **tokens, 3686 uint32_t n_tokens, 3687 struct softnic_table_rule_action *a) 3688 { 3689 if (n_tokens < 2 || 3690 strcmp(tokens[0], "tag")) 3691 return 0; 3692 3693 if (softnic_parser_read_uint32(&a->tag.tag, tokens[1])) 3694 return 0; 3695 3696 a->action_mask |= 1 << RTE_TABLE_ACTION_TAG; 3697 return 2; 3698 } 3699 3700 static uint32_t 3701 parse_table_action_decap(char **tokens, 3702 uint32_t n_tokens, 3703 struct softnic_table_rule_action *a) 3704 { 3705 if (n_tokens < 2 || 3706 strcmp(tokens[0], "decap")) 3707 return 0; 3708 3709 if (softnic_parser_read_uint16(&a->decap.n, tokens[1])) 3710 return 0; 3711 3712 a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP; 3713 return 2; 3714 } 3715 3716 static uint32_t 3717 parse_table_action(char **tokens, 3718 uint32_t n_tokens, 3719 char *out, 3720 size_t out_size, 3721 struct softnic_table_rule_action *a) 3722 { 3723 uint32_t n_tokens0 = n_tokens; 3724 3725 memset(a, 0, sizeof(*a)); 3726 3727 if (n_tokens < 2 || 3728 strcmp(tokens[0], "action")) 3729 return 0; 3730 3731 tokens++; 3732 n_tokens--; 3733 3734 if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) { 3735 uint32_t n; 3736 3737 n = parse_table_action_fwd(tokens, n_tokens, a); 3738 if (n == 0) { 3739 snprintf(out, out_size, MSG_ARG_INVALID, 3740 "action fwd"); 3741 return 0; 3742 } 3743 3744 tokens += n; 3745 n_tokens -= n; 3746 } 3747 3748 if (n_tokens && (strcmp(tokens[0], "balance") == 0)) { 3749 uint32_t n; 3750 3751 n = parse_table_action_balance(tokens, n_tokens, a); 3752 if (n == 0) { 3753 snprintf(out, out_size, MSG_ARG_INVALID, 3754 "action balance"); 3755 return 0; 3756 } 3757 3758 tokens += n; 3759 n_tokens -= n; 3760 } 3761 3762 if (n_tokens && (strcmp(tokens[0], "meter") == 0)) { 3763 uint32_t n; 3764 3765 n = parse_table_action_meter(tokens, n_tokens, a); 3766 if (n == 0) { 3767 snprintf(out, out_size, MSG_ARG_INVALID, 3768 "action meter"); 3769 return 0; 3770 } 3771 3772 tokens += n; 3773 n_tokens -= n; 3774 } 3775 3776 if (n_tokens && (strcmp(tokens[0], "tm") == 0)) { 3777 uint32_t n; 3778 3779 n = parse_table_action_tm(tokens, n_tokens, a); 3780 if (n == 0) { 3781 snprintf(out, out_size, MSG_ARG_INVALID, 3782 "action tm"); 3783 return 0; 3784 } 3785 3786 tokens += n; 3787 n_tokens -= n; 3788 } 3789 3790 if (n_tokens && (strcmp(tokens[0], "encap") == 0)) { 3791 uint32_t n; 3792 3793 n = parse_table_action_encap(tokens, n_tokens, a); 3794 if (n == 0) { 3795 snprintf(out, out_size, MSG_ARG_INVALID, 3796 "action encap"); 3797 return 0; 3798 } 3799 3800 tokens += n; 3801 n_tokens -= n; 3802 } 3803 3804 if (n_tokens && (strcmp(tokens[0], "nat") == 0)) { 3805 uint32_t n; 3806 3807 n = parse_table_action_nat(tokens, n_tokens, a); 3808 if (n == 0) { 3809 snprintf(out, out_size, MSG_ARG_INVALID, 3810 "action nat"); 3811 return 0; 3812 } 3813 3814 tokens += n; 3815 n_tokens -= n; 3816 } 3817 3818 if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) { 3819 uint32_t n; 3820 3821 n = parse_table_action_ttl(tokens, n_tokens, a); 3822 if (n == 0) { 3823 snprintf(out, out_size, MSG_ARG_INVALID, 3824 "action ttl"); 3825 return 0; 3826 } 3827 3828 tokens += n; 3829 n_tokens -= n; 3830 } 3831 3832 if (n_tokens && (strcmp(tokens[0], "stats") == 0)) { 3833 uint32_t n; 3834 3835 n = parse_table_action_stats(tokens, n_tokens, a); 3836 if (n == 0) { 3837 snprintf(out, out_size, MSG_ARG_INVALID, 3838 "action stats"); 3839 return 0; 3840 } 3841 3842 tokens += n; 3843 n_tokens -= n; 3844 } 3845 3846 if (n_tokens && (strcmp(tokens[0], "time") == 0)) { 3847 uint32_t n; 3848 3849 n = parse_table_action_time(tokens, n_tokens, a); 3850 if (n == 0) { 3851 snprintf(out, out_size, MSG_ARG_INVALID, 3852 "action time"); 3853 return 0; 3854 } 3855 3856 tokens += n; 3857 n_tokens -= n; 3858 } 3859 3860 if (n_tokens && (strcmp(tokens[0], "tag") == 0)) { 3861 uint32_t n; 3862 3863 n = parse_table_action_tag(tokens, n_tokens, a); 3864 if (n == 0) { 3865 snprintf(out, out_size, MSG_ARG_INVALID, 3866 "action tag"); 3867 return 0; 3868 } 3869 3870 tokens += n; 3871 n_tokens -= n; 3872 } 3873 3874 if (n_tokens && (strcmp(tokens[0], "decap") == 0)) { 3875 uint32_t n; 3876 3877 n = parse_table_action_decap(tokens, n_tokens, a); 3878 if (n == 0) { 3879 snprintf(out, out_size, MSG_ARG_INVALID, 3880 "action decap"); 3881 return 0; 3882 } 3883 3884 tokens += n; 3885 n_tokens -= n; 3886 } 3887 3888 if (n_tokens0 - n_tokens == 1) { 3889 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 3890 return 0; 3891 } 3892 3893 return n_tokens0 - n_tokens; 3894 } 3895 3896 /** 3897 * pipeline <pipeline_name> table <table_id> rule add 3898 * match <match> 3899 * action <table_action> 3900 */ 3901 static void 3902 cmd_softnic_pipeline_table_rule_add(struct pmd_internals *softnic, 3903 char **tokens, 3904 uint32_t n_tokens, 3905 char *out, 3906 size_t out_size) 3907 { 3908 struct softnic_table_rule_match m; 3909 struct softnic_table_rule_action a; 3910 char *pipeline_name; 3911 void *data; 3912 uint32_t table_id, t0, n_tokens_parsed; 3913 int status; 3914 3915 if (n_tokens < 8) { 3916 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3917 return; 3918 } 3919 3920 pipeline_name = tokens[1]; 3921 3922 if (strcmp(tokens[2], "table") != 0) { 3923 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 3924 return; 3925 } 3926 3927 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 3928 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 3929 return; 3930 } 3931 3932 if (strcmp(tokens[4], "rule") != 0) { 3933 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 3934 return; 3935 } 3936 3937 if (strcmp(tokens[5], "add") != 0) { 3938 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 3939 return; 3940 } 3941 3942 t0 = 6; 3943 3944 /* match */ 3945 n_tokens_parsed = parse_match(tokens + t0, 3946 n_tokens - t0, 3947 out, 3948 out_size, 3949 &m); 3950 if (n_tokens_parsed == 0) 3951 return; 3952 t0 += n_tokens_parsed; 3953 3954 /* action */ 3955 n_tokens_parsed = parse_table_action(tokens + t0, 3956 n_tokens - t0, 3957 out, 3958 out_size, 3959 &a); 3960 if (n_tokens_parsed == 0) 3961 return; 3962 t0 += n_tokens_parsed; 3963 3964 if (t0 != n_tokens) { 3965 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 3966 return; 3967 } 3968 3969 status = softnic_pipeline_table_rule_add(softnic, 3970 pipeline_name, 3971 table_id, 3972 &m, 3973 &a, 3974 &data); 3975 if (status) { 3976 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 3977 return; 3978 } 3979 } 3980 3981 /** 3982 * pipeline <pipeline_name> table <table_id> rule add 3983 * match 3984 * default 3985 * action 3986 * fwd 3987 * drop 3988 * | port <port_id> 3989 * | meta 3990 * | table <table_id> 3991 */ 3992 static void 3993 cmd_softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic, 3994 char **tokens, 3995 uint32_t n_tokens, 3996 char *out, 3997 size_t out_size) 3998 { 3999 struct softnic_table_rule_action action; 4000 void *data; 4001 char *pipeline_name; 4002 uint32_t table_id; 4003 int status; 4004 4005 if (n_tokens != 11 && 4006 n_tokens != 12) { 4007 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4008 return; 4009 } 4010 4011 pipeline_name = tokens[1]; 4012 4013 if (strcmp(tokens[2], "table") != 0) { 4014 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4015 return; 4016 } 4017 4018 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4019 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4020 return; 4021 } 4022 4023 if (strcmp(tokens[4], "rule") != 0) { 4024 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4025 return; 4026 } 4027 4028 if (strcmp(tokens[5], "add") != 0) { 4029 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4030 return; 4031 } 4032 4033 if (strcmp(tokens[6], "match") != 0) { 4034 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 4035 return; 4036 } 4037 4038 if (strcmp(tokens[7], "default") != 0) { 4039 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 4040 return; 4041 } 4042 4043 if (strcmp(tokens[8], "action") != 0) { 4044 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 4045 return; 4046 } 4047 4048 if (strcmp(tokens[9], "fwd") != 0) { 4049 snprintf(out, out_size, MSG_ARG_INVALID, "fwd"); 4050 return; 4051 } 4052 4053 action.action_mask = 1 << RTE_TABLE_ACTION_FWD; 4054 4055 if (strcmp(tokens[10], "drop") == 0) { 4056 if (n_tokens != 11) { 4057 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4058 return; 4059 } 4060 4061 action.fwd.action = RTE_PIPELINE_ACTION_DROP; 4062 } else if (strcmp(tokens[10], "port") == 0) { 4063 uint32_t id; 4064 4065 if (n_tokens != 12) { 4066 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4067 return; 4068 } 4069 4070 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) { 4071 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 4072 return; 4073 } 4074 4075 action.fwd.action = RTE_PIPELINE_ACTION_PORT; 4076 action.fwd.id = id; 4077 } else if (strcmp(tokens[10], "meta") == 0) { 4078 if (n_tokens != 11) { 4079 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4080 return; 4081 } 4082 4083 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META; 4084 } else if (strcmp(tokens[10], "table") == 0) { 4085 uint32_t id; 4086 4087 if (n_tokens != 12) { 4088 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4089 return; 4090 } 4091 4092 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) { 4093 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4094 return; 4095 } 4096 4097 action.fwd.action = RTE_PIPELINE_ACTION_TABLE; 4098 action.fwd.id = id; 4099 } else { 4100 snprintf(out, out_size, MSG_ARG_INVALID, 4101 "drop or port or meta or table"); 4102 return; 4103 } 4104 4105 status = softnic_pipeline_table_rule_add_default(softnic, 4106 pipeline_name, 4107 table_id, 4108 &action, 4109 &data); 4110 if (status) { 4111 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4112 return; 4113 } 4114 } 4115 4116 /** 4117 * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules> 4118 * 4119 * File <file_name>: 4120 * - line format: match <match> action <action> 4121 */ 4122 static int 4123 cli_rule_file_process(const char *file_name, 4124 size_t line_len_max, 4125 struct softnic_table_rule_match *m, 4126 struct softnic_table_rule_action *a, 4127 uint32_t *n_rules, 4128 uint32_t *line_number, 4129 char *out, 4130 size_t out_size); 4131 4132 static void 4133 cmd_softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic, 4134 char **tokens, 4135 uint32_t n_tokens, 4136 char *out, 4137 size_t out_size) 4138 { 4139 struct softnic_table_rule_match *match; 4140 struct softnic_table_rule_action *action; 4141 void **data; 4142 char *pipeline_name, *file_name; 4143 uint32_t table_id, n_rules, n_rules_parsed, line_number; 4144 int status; 4145 4146 if (n_tokens != 9) { 4147 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4148 return; 4149 } 4150 4151 pipeline_name = tokens[1]; 4152 4153 if (strcmp(tokens[2], "table") != 0) { 4154 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4155 return; 4156 } 4157 4158 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4159 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4160 return; 4161 } 4162 4163 if (strcmp(tokens[4], "rule") != 0) { 4164 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4165 return; 4166 } 4167 4168 if (strcmp(tokens[5], "add") != 0) { 4169 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4170 return; 4171 } 4172 4173 if (strcmp(tokens[6], "bulk") != 0) { 4174 snprintf(out, out_size, MSG_ARG_INVALID, "bulk"); 4175 return; 4176 } 4177 4178 file_name = tokens[7]; 4179 4180 if ((softnic_parser_read_uint32(&n_rules, tokens[8]) != 0) || 4181 n_rules == 0) { 4182 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 4183 return; 4184 } 4185 4186 /* Memory allocation. */ 4187 match = calloc(n_rules, sizeof(struct softnic_table_rule_match)); 4188 action = calloc(n_rules, sizeof(struct softnic_table_rule_action)); 4189 data = calloc(n_rules, sizeof(void *)); 4190 if (match == NULL || 4191 action == NULL || 4192 data == NULL) { 4193 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 4194 free(data); 4195 free(action); 4196 free(match); 4197 return; 4198 } 4199 4200 /* Load rule file */ 4201 n_rules_parsed = n_rules; 4202 status = cli_rule_file_process(file_name, 4203 1024, 4204 match, 4205 action, 4206 &n_rules_parsed, 4207 &line_number, 4208 out, 4209 out_size); 4210 if (status) { 4211 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 4212 free(data); 4213 free(action); 4214 free(match); 4215 return; 4216 } 4217 if (n_rules_parsed != n_rules) { 4218 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name); 4219 free(data); 4220 free(action); 4221 free(match); 4222 return; 4223 } 4224 4225 /* Rule bulk add */ 4226 status = softnic_pipeline_table_rule_add_bulk(softnic, 4227 pipeline_name, 4228 table_id, 4229 match, 4230 action, 4231 data, 4232 &n_rules); 4233 if (status) { 4234 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4235 free(data); 4236 free(action); 4237 free(match); 4238 return; 4239 } 4240 4241 /* Memory free */ 4242 free(data); 4243 free(action); 4244 free(match); 4245 } 4246 4247 /** 4248 * pipeline <pipeline_name> table <table_id> rule delete 4249 * match <match> 4250 */ 4251 static void 4252 cmd_softnic_pipeline_table_rule_delete(struct pmd_internals *softnic, 4253 char **tokens, 4254 uint32_t n_tokens, 4255 char *out, 4256 size_t out_size) 4257 { 4258 struct softnic_table_rule_match m; 4259 char *pipeline_name; 4260 uint32_t table_id, n_tokens_parsed, t0; 4261 int status; 4262 4263 if (n_tokens < 8) { 4264 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4265 return; 4266 } 4267 4268 pipeline_name = tokens[1]; 4269 4270 if (strcmp(tokens[2], "table") != 0) { 4271 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4272 return; 4273 } 4274 4275 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4276 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4277 return; 4278 } 4279 4280 if (strcmp(tokens[4], "rule") != 0) { 4281 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4282 return; 4283 } 4284 4285 if (strcmp(tokens[5], "delete") != 0) { 4286 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4287 return; 4288 } 4289 4290 t0 = 6; 4291 4292 /* match */ 4293 n_tokens_parsed = parse_match(tokens + t0, 4294 n_tokens - t0, 4295 out, 4296 out_size, 4297 &m); 4298 if (n_tokens_parsed == 0) 4299 return; 4300 t0 += n_tokens_parsed; 4301 4302 if (n_tokens != t0) { 4303 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4304 return; 4305 } 4306 4307 status = softnic_pipeline_table_rule_delete(softnic, 4308 pipeline_name, 4309 table_id, 4310 &m); 4311 if (status) { 4312 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4313 return; 4314 } 4315 } 4316 4317 /** 4318 * pipeline <pipeline_name> table <table_id> rule delete 4319 * match 4320 * default 4321 */ 4322 static void 4323 cmd_softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic, 4324 char **tokens, 4325 uint32_t n_tokens, 4326 char *out, 4327 size_t out_size) 4328 { 4329 char *pipeline_name; 4330 uint32_t table_id; 4331 int status; 4332 4333 if (n_tokens != 8) { 4334 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4335 return; 4336 } 4337 4338 pipeline_name = tokens[1]; 4339 4340 if (strcmp(tokens[2], "table") != 0) { 4341 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4342 return; 4343 } 4344 4345 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4346 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4347 return; 4348 } 4349 4350 if (strcmp(tokens[4], "rule") != 0) { 4351 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4352 return; 4353 } 4354 4355 if (strcmp(tokens[5], "delete") != 0) { 4356 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4357 return; 4358 } 4359 4360 if (strcmp(tokens[6], "match") != 0) { 4361 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 4362 return; 4363 } 4364 4365 if (strcmp(tokens[7], "default") != 0) { 4366 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 4367 return; 4368 } 4369 4370 status = softnic_pipeline_table_rule_delete_default(softnic, 4371 pipeline_name, 4372 table_id); 4373 if (status) { 4374 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4375 return; 4376 } 4377 } 4378 4379 /** 4380 * pipeline <pipeline_name> table <table_id> rule read stats [clear] 4381 */ 4382 static void 4383 cmd_softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic __rte_unused, 4384 char **tokens, 4385 uint32_t n_tokens __rte_unused, 4386 char *out, 4387 size_t out_size) 4388 { 4389 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 4390 } 4391 4392 /** 4393 * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id> 4394 * add srtcm cir <cir> cbs <cbs> ebs <ebs> 4395 * | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs> 4396 */ 4397 static void 4398 cmd_pipeline_table_meter_profile_add(struct pmd_internals *softnic, 4399 char **tokens, 4400 uint32_t n_tokens, 4401 char *out, 4402 size_t out_size) 4403 { 4404 struct rte_table_action_meter_profile p; 4405 char *pipeline_name; 4406 uint32_t table_id, meter_profile_id; 4407 int status; 4408 4409 if (n_tokens < 9) { 4410 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4411 return; 4412 } 4413 4414 pipeline_name = tokens[1]; 4415 4416 if (strcmp(tokens[2], "table") != 0) { 4417 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 4418 return; 4419 } 4420 4421 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4422 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4423 return; 4424 } 4425 4426 if (strcmp(tokens[4], "meter") != 0) { 4427 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 4428 return; 4429 } 4430 4431 if (strcmp(tokens[5], "profile") != 0) { 4432 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 4433 return; 4434 } 4435 4436 if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 4437 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 4438 return; 4439 } 4440 4441 if (strcmp(tokens[7], "add") != 0) { 4442 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4443 return; 4444 } 4445 4446 if (strcmp(tokens[8], "srtcm") == 0) { 4447 if (n_tokens != 15) { 4448 snprintf(out, out_size, MSG_ARG_MISMATCH, 4449 tokens[0]); 4450 return; 4451 } 4452 4453 p.alg = RTE_TABLE_ACTION_METER_SRTCM; 4454 4455 if (strcmp(tokens[9], "cir") != 0) { 4456 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 4457 return; 4458 } 4459 4460 if (softnic_parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) { 4461 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 4462 return; 4463 } 4464 4465 if (strcmp(tokens[11], "cbs") != 0) { 4466 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 4467 return; 4468 } 4469 4470 if (softnic_parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) { 4471 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 4472 return; 4473 } 4474 4475 if (strcmp(tokens[13], "ebs") != 0) { 4476 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs"); 4477 return; 4478 } 4479 4480 if (softnic_parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) { 4481 snprintf(out, out_size, MSG_ARG_INVALID, "ebs"); 4482 return; 4483 } 4484 } else if (strcmp(tokens[8], "trtcm") == 0) { 4485 if (n_tokens != 17) { 4486 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4487 return; 4488 } 4489 4490 p.alg = RTE_TABLE_ACTION_METER_TRTCM; 4491 4492 if (strcmp(tokens[9], "cir") != 0) { 4493 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 4494 return; 4495 } 4496 4497 if (softnic_parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) { 4498 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 4499 return; 4500 } 4501 4502 if (strcmp(tokens[11], "pir") != 0) { 4503 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 4504 return; 4505 } 4506 4507 if (softnic_parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) { 4508 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 4509 return; 4510 } 4511 if (strcmp(tokens[13], "cbs") != 0) { 4512 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 4513 return; 4514 } 4515 4516 if (softnic_parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) { 4517 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 4518 return; 4519 } 4520 4521 if (strcmp(tokens[15], "pbs") != 0) { 4522 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 4523 return; 4524 } 4525 4526 if (softnic_parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) { 4527 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 4528 return; 4529 } 4530 } else { 4531 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4532 return; 4533 } 4534 4535 status = softnic_pipeline_table_mtr_profile_add(softnic, 4536 pipeline_name, 4537 table_id, 4538 meter_profile_id, 4539 &p); 4540 if (status) { 4541 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4542 return; 4543 } 4544 } 4545 4546 /** 4547 * pipeline <pipeline_name> table <table_id> 4548 * meter profile <meter_profile_id> delete 4549 */ 4550 static void 4551 cmd_pipeline_table_meter_profile_delete(struct pmd_internals *softnic, 4552 char **tokens, 4553 uint32_t n_tokens, 4554 char *out, 4555 size_t out_size) 4556 { 4557 char *pipeline_name; 4558 uint32_t table_id, meter_profile_id; 4559 int status; 4560 4561 if (n_tokens != 8) { 4562 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4563 return; 4564 } 4565 4566 pipeline_name = tokens[1]; 4567 4568 if (strcmp(tokens[2], "table") != 0) { 4569 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 4570 return; 4571 } 4572 4573 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4574 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4575 return; 4576 } 4577 4578 if (strcmp(tokens[4], "meter") != 0) { 4579 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 4580 return; 4581 } 4582 4583 if (strcmp(tokens[5], "profile") != 0) { 4584 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 4585 return; 4586 } 4587 4588 if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 4589 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 4590 return; 4591 } 4592 4593 if (strcmp(tokens[7], "delete") != 0) { 4594 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4595 return; 4596 } 4597 4598 status = softnic_pipeline_table_mtr_profile_delete(softnic, 4599 pipeline_name, 4600 table_id, 4601 meter_profile_id); 4602 if (status) { 4603 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4604 return; 4605 } 4606 } 4607 4608 /** 4609 * pipeline <pipeline_name> table <table_id> rule read meter [clear] 4610 */ 4611 static void 4612 cmd_pipeline_table_rule_meter_read(struct pmd_internals *softnic __rte_unused, 4613 char **tokens, 4614 uint32_t n_tokens __rte_unused, 4615 char *out, 4616 size_t out_size) 4617 { 4618 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 4619 } 4620 4621 /** 4622 * pipeline <pipeline_name> table <table_id> dscp <file_name> 4623 * 4624 * File <file_name>: 4625 * - exactly 64 lines 4626 * - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r 4627 */ 4628 static int 4629 load_dscp_table(struct rte_table_action_dscp_table *dscp_table, 4630 const char *file_name, 4631 uint32_t *line_number) 4632 { 4633 FILE *f = NULL; 4634 uint32_t dscp, l; 4635 4636 /* Check input arguments */ 4637 if (dscp_table == NULL || 4638 file_name == NULL || 4639 line_number == NULL) { 4640 if (line_number) 4641 *line_number = 0; 4642 return -EINVAL; 4643 } 4644 4645 /* Open input file */ 4646 f = fopen(file_name, "r"); 4647 if (f == NULL) { 4648 *line_number = 0; 4649 return -EINVAL; 4650 } 4651 4652 /* Read file */ 4653 for (dscp = 0, l = 1; ; l++) { 4654 char line[64]; 4655 char *tokens[3]; 4656 enum rte_meter_color color; 4657 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens); 4658 4659 if (fgets(line, sizeof(line), f) == NULL) 4660 break; 4661 4662 if (is_comment(line)) 4663 continue; 4664 4665 if (softnic_parse_tokenize_string(line, tokens, &n_tokens)) { 4666 *line_number = l; 4667 fclose(f); 4668 return -EINVAL; 4669 } 4670 4671 if (n_tokens == 0) 4672 continue; 4673 4674 if (dscp >= RTE_DIM(dscp_table->entry) || 4675 n_tokens != RTE_DIM(tokens) || 4676 softnic_parser_read_uint32(&tc_id, tokens[0]) || 4677 tc_id >= RTE_TABLE_ACTION_TC_MAX || 4678 softnic_parser_read_uint32(&tc_queue_id, tokens[1]) || 4679 tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX || 4680 (strlen(tokens[2]) != 1)) { 4681 *line_number = l; 4682 fclose(f); 4683 return -EINVAL; 4684 } 4685 4686 switch (tokens[2][0]) { 4687 case 'g': 4688 case 'G': 4689 color = e_RTE_METER_GREEN; 4690 break; 4691 4692 case 'y': 4693 case 'Y': 4694 color = e_RTE_METER_YELLOW; 4695 break; 4696 4697 case 'r': 4698 case 'R': 4699 color = e_RTE_METER_RED; 4700 break; 4701 4702 default: 4703 *line_number = l; 4704 fclose(f); 4705 return -EINVAL; 4706 } 4707 4708 dscp_table->entry[dscp].tc_id = tc_id; 4709 dscp_table->entry[dscp].tc_queue_id = tc_queue_id; 4710 dscp_table->entry[dscp].color = color; 4711 dscp++; 4712 } 4713 4714 /* Close file */ 4715 fclose(f); 4716 return 0; 4717 } 4718 4719 static void 4720 cmd_pipeline_table_dscp(struct pmd_internals *softnic, 4721 char **tokens, 4722 uint32_t n_tokens, 4723 char *out, 4724 size_t out_size) 4725 { 4726 struct rte_table_action_dscp_table dscp_table; 4727 char *pipeline_name, *file_name; 4728 uint32_t table_id, line_number; 4729 int status; 4730 4731 if (n_tokens != 6) { 4732 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4733 return; 4734 } 4735 4736 pipeline_name = tokens[1]; 4737 4738 if (strcmp(tokens[2], "table") != 0) { 4739 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 4740 return; 4741 } 4742 4743 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4744 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4745 return; 4746 } 4747 4748 if (strcmp(tokens[4], "dscp") != 0) { 4749 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp"); 4750 return; 4751 } 4752 4753 file_name = tokens[5]; 4754 4755 status = load_dscp_table(&dscp_table, file_name, &line_number); 4756 if (status) { 4757 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 4758 return; 4759 } 4760 4761 status = softnic_pipeline_table_dscp_table_update(softnic, 4762 pipeline_name, 4763 table_id, 4764 UINT64_MAX, 4765 &dscp_table); 4766 if (status) { 4767 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4768 return; 4769 } 4770 } 4771 4772 /** 4773 * pipeline <pipeline_name> table <table_id> rule read ttl [clear] 4774 */ 4775 static void 4776 cmd_softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic __rte_unused, 4777 char **tokens, 4778 uint32_t n_tokens __rte_unused, 4779 char *out, 4780 size_t out_size) 4781 { 4782 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 4783 } 4784 4785 /** 4786 * thread <thread_id> pipeline <pipeline_name> enable 4787 */ 4788 static void 4789 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic, 4790 char **tokens, 4791 uint32_t n_tokens, 4792 char *out, 4793 size_t out_size) 4794 { 4795 char *pipeline_name; 4796 uint32_t thread_id; 4797 int status; 4798 4799 if (n_tokens != 5) { 4800 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4801 return; 4802 } 4803 4804 if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) { 4805 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 4806 return; 4807 } 4808 4809 if (strcmp(tokens[2], "pipeline") != 0) { 4810 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 4811 return; 4812 } 4813 4814 pipeline_name = tokens[3]; 4815 4816 if (strcmp(tokens[4], "enable") != 0) { 4817 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 4818 return; 4819 } 4820 4821 status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name); 4822 if (status) { 4823 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 4824 return; 4825 } 4826 } 4827 4828 /** 4829 * thread <thread_id> pipeline <pipeline_name> disable 4830 */ 4831 static void 4832 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic, 4833 char **tokens, 4834 uint32_t n_tokens, 4835 char *out, 4836 size_t out_size) 4837 { 4838 char *pipeline_name; 4839 uint32_t thread_id; 4840 int status; 4841 4842 if (n_tokens != 5) { 4843 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4844 return; 4845 } 4846 4847 if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) { 4848 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 4849 return; 4850 } 4851 4852 if (strcmp(tokens[2], "pipeline") != 0) { 4853 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 4854 return; 4855 } 4856 4857 pipeline_name = tokens[3]; 4858 4859 if (strcmp(tokens[4], "disable") != 0) { 4860 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 4861 return; 4862 } 4863 4864 status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name); 4865 if (status) { 4866 snprintf(out, out_size, MSG_CMD_FAIL, 4867 "thread pipeline disable"); 4868 return; 4869 } 4870 } 4871 4872 /** 4873 * flowapi map 4874 * group <group_id> 4875 * ingress | egress 4876 * pipeline <pipeline_name> 4877 * table <table_id> 4878 */ 4879 static void 4880 cmd_softnic_flowapi_map(struct pmd_internals *softnic, 4881 char **tokens, 4882 uint32_t n_tokens, 4883 char *out, 4884 size_t out_size) 4885 { 4886 char *pipeline_name; 4887 uint32_t group_id, table_id; 4888 int ingress, status; 4889 4890 if (n_tokens != 9) { 4891 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4892 return; 4893 } 4894 4895 if (strcmp(tokens[1], "map") != 0) { 4896 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "map"); 4897 return; 4898 } 4899 4900 if (strcmp(tokens[2], "group") != 0) { 4901 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group"); 4902 return; 4903 } 4904 4905 if (softnic_parser_read_uint32(&group_id, tokens[3]) != 0) { 4906 snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); 4907 return; 4908 } 4909 4910 if (strcmp(tokens[4], "ingress") == 0) { 4911 ingress = 1; 4912 } else if (strcmp(tokens[4], "egress") == 0) { 4913 ingress = 0; 4914 } else { 4915 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ingress | egress"); 4916 return; 4917 } 4918 4919 if (strcmp(tokens[5], "pipeline") != 0) { 4920 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 4921 return; 4922 } 4923 4924 pipeline_name = tokens[6]; 4925 4926 if (strcmp(tokens[7], "table") != 0) { 4927 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4928 return; 4929 } 4930 4931 if (softnic_parser_read_uint32(&table_id, tokens[8]) != 0) { 4932 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4933 return; 4934 } 4935 4936 status = flow_attr_map_set(softnic, 4937 group_id, 4938 ingress, 4939 pipeline_name, 4940 table_id); 4941 if (status) { 4942 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4943 return; 4944 } 4945 } 4946 4947 void 4948 softnic_cli_process(char *in, char *out, size_t out_size, void *arg) 4949 { 4950 char *tokens[CMD_MAX_TOKENS]; 4951 uint32_t n_tokens = RTE_DIM(tokens); 4952 struct pmd_internals *softnic = arg; 4953 int status; 4954 4955 if (is_comment(in)) 4956 return; 4957 4958 status = softnic_parse_tokenize_string(in, tokens, &n_tokens); 4959 if (status) { 4960 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 4961 return; 4962 } 4963 4964 if (n_tokens == 0) 4965 return; 4966 4967 if (strcmp(tokens[0], "mempool") == 0) { 4968 cmd_mempool(softnic, tokens, n_tokens, out, out_size); 4969 return; 4970 } 4971 4972 if (strcmp(tokens[0], "link") == 0) { 4973 cmd_link(softnic, tokens, n_tokens, out, out_size); 4974 return; 4975 } 4976 4977 if (strcmp(tokens[0], "swq") == 0) { 4978 cmd_swq(softnic, tokens, n_tokens, out, out_size); 4979 return; 4980 } 4981 4982 if (strcmp(tokens[0], "tmgr") == 0) { 4983 if (n_tokens == 2) { 4984 cmd_tmgr(softnic, tokens, n_tokens, out, out_size); 4985 return; 4986 } 4987 4988 if (n_tokens >= 3 && 4989 (strcmp(tokens[1], "shaper") == 0) && 4990 (strcmp(tokens[2], "profile") == 0)) { 4991 cmd_tmgr_shaper_profile(softnic, tokens, n_tokens, out, out_size); 4992 return; 4993 } 4994 4995 if (n_tokens >= 3 && 4996 (strcmp(tokens[1], "shared") == 0) && 4997 (strcmp(tokens[2], "shaper") == 0)) { 4998 cmd_tmgr_shared_shaper(softnic, tokens, n_tokens, out, out_size); 4999 return; 5000 } 5001 5002 if (n_tokens >= 2 && 5003 (strcmp(tokens[1], "node") == 0)) { 5004 cmd_tmgr_node(softnic, tokens, n_tokens, out, out_size); 5005 return; 5006 } 5007 5008 if (n_tokens >= 2 && 5009 (strcmp(tokens[1], "hierarchy-default") == 0)) { 5010 cmd_tmgr_hierarchy_default(softnic, tokens, n_tokens, out, out_size); 5011 return; 5012 } 5013 5014 if (n_tokens >= 3 && 5015 (strcmp(tokens[1], "hierarchy") == 0) && 5016 (strcmp(tokens[2], "commit") == 0)) { 5017 cmd_tmgr_hierarchy_commit(softnic, tokens, n_tokens, out, out_size); 5018 return; 5019 } 5020 } 5021 5022 if (strcmp(tokens[0], "tap") == 0) { 5023 cmd_tap(softnic, tokens, n_tokens, out, out_size); 5024 return; 5025 } 5026 5027 if (strcmp(tokens[0], "port") == 0) { 5028 cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size); 5029 return; 5030 } 5031 5032 if (strcmp(tokens[0], "table") == 0) { 5033 cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size); 5034 return; 5035 } 5036 5037 if (strcmp(tokens[0], "pipeline") == 0) { 5038 if (n_tokens >= 3 && 5039 (strcmp(tokens[2], "period") == 0)) { 5040 cmd_pipeline(softnic, tokens, n_tokens, out, out_size); 5041 return; 5042 } 5043 5044 if (n_tokens >= 5 && 5045 (strcmp(tokens[2], "port") == 0) && 5046 (strcmp(tokens[3], "in") == 0) && 5047 (strcmp(tokens[4], "bsz") == 0)) { 5048 cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size); 5049 return; 5050 } 5051 5052 if (n_tokens >= 5 && 5053 (strcmp(tokens[2], "port") == 0) && 5054 (strcmp(tokens[3], "out") == 0) && 5055 (strcmp(tokens[4], "bsz") == 0)) { 5056 cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size); 5057 return; 5058 } 5059 5060 if (n_tokens >= 4 && 5061 (strcmp(tokens[2], "table") == 0) && 5062 (strcmp(tokens[3], "match") == 0)) { 5063 cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size); 5064 return; 5065 } 5066 5067 if (n_tokens >= 6 && 5068 (strcmp(tokens[2], "port") == 0) && 5069 (strcmp(tokens[3], "in") == 0) && 5070 (strcmp(tokens[5], "table") == 0)) { 5071 cmd_pipeline_port_in_table(softnic, tokens, n_tokens, 5072 out, out_size); 5073 return; 5074 } 5075 5076 if (n_tokens >= 6 && 5077 (strcmp(tokens[2], "port") == 0) && 5078 (strcmp(tokens[3], "in") == 0) && 5079 (strcmp(tokens[5], "stats") == 0)) { 5080 cmd_pipeline_port_in_stats(softnic, tokens, n_tokens, 5081 out, out_size); 5082 return; 5083 } 5084 5085 if (n_tokens >= 6 && 5086 (strcmp(tokens[2], "port") == 0) && 5087 (strcmp(tokens[3], "in") == 0) && 5088 (strcmp(tokens[5], "enable") == 0)) { 5089 cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens, 5090 out, out_size); 5091 return; 5092 } 5093 5094 if (n_tokens >= 6 && 5095 (strcmp(tokens[2], "port") == 0) && 5096 (strcmp(tokens[3], "in") == 0) && 5097 (strcmp(tokens[5], "disable") == 0)) { 5098 cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens, 5099 out, out_size); 5100 return; 5101 } 5102 5103 if (n_tokens >= 6 && 5104 (strcmp(tokens[2], "port") == 0) && 5105 (strcmp(tokens[3], "out") == 0) && 5106 (strcmp(tokens[5], "stats") == 0)) { 5107 cmd_pipeline_port_out_stats(softnic, tokens, n_tokens, 5108 out, out_size); 5109 return; 5110 } 5111 5112 if (n_tokens >= 5 && 5113 (strcmp(tokens[2], "table") == 0) && 5114 (strcmp(tokens[4], "stats") == 0)) { 5115 cmd_pipeline_table_stats(softnic, tokens, n_tokens, 5116 out, out_size); 5117 return; 5118 } 5119 5120 if (n_tokens >= 7 && 5121 (strcmp(tokens[2], "table") == 0) && 5122 (strcmp(tokens[4], "rule") == 0) && 5123 (strcmp(tokens[5], "add") == 0) && 5124 (strcmp(tokens[6], "match") == 0)) { 5125 if (n_tokens >= 8 && 5126 (strcmp(tokens[7], "default") == 0)) { 5127 cmd_softnic_pipeline_table_rule_add_default(softnic, tokens, 5128 n_tokens, out, out_size); 5129 return; 5130 } 5131 5132 cmd_softnic_pipeline_table_rule_add(softnic, tokens, n_tokens, 5133 out, out_size); 5134 return; 5135 } 5136 5137 if (n_tokens >= 7 && 5138 (strcmp(tokens[2], "table") == 0) && 5139 (strcmp(tokens[4], "rule") == 0) && 5140 (strcmp(tokens[5], "add") == 0) && 5141 (strcmp(tokens[6], "bulk") == 0)) { 5142 cmd_softnic_pipeline_table_rule_add_bulk(softnic, tokens, 5143 n_tokens, out, out_size); 5144 return; 5145 } 5146 5147 if (n_tokens >= 7 && 5148 (strcmp(tokens[2], "table") == 0) && 5149 (strcmp(tokens[4], "rule") == 0) && 5150 (strcmp(tokens[5], "delete") == 0) && 5151 (strcmp(tokens[6], "match") == 0)) { 5152 if (n_tokens >= 8 && 5153 (strcmp(tokens[7], "default") == 0)) { 5154 cmd_softnic_pipeline_table_rule_delete_default(softnic, tokens, 5155 n_tokens, out, out_size); 5156 return; 5157 } 5158 5159 cmd_softnic_pipeline_table_rule_delete(softnic, tokens, n_tokens, 5160 out, out_size); 5161 return; 5162 } 5163 5164 if (n_tokens >= 7 && 5165 (strcmp(tokens[2], "table") == 0) && 5166 (strcmp(tokens[4], "rule") == 0) && 5167 (strcmp(tokens[5], "read") == 0) && 5168 (strcmp(tokens[6], "stats") == 0)) { 5169 cmd_softnic_pipeline_table_rule_stats_read(softnic, tokens, n_tokens, 5170 out, out_size); 5171 return; 5172 } 5173 5174 if (n_tokens >= 8 && 5175 (strcmp(tokens[2], "table") == 0) && 5176 (strcmp(tokens[4], "meter") == 0) && 5177 (strcmp(tokens[5], "profile") == 0) && 5178 (strcmp(tokens[7], "add") == 0)) { 5179 cmd_pipeline_table_meter_profile_add(softnic, tokens, n_tokens, 5180 out, out_size); 5181 return; 5182 } 5183 5184 if (n_tokens >= 8 && 5185 (strcmp(tokens[2], "table") == 0) && 5186 (strcmp(tokens[4], "meter") == 0) && 5187 (strcmp(tokens[5], "profile") == 0) && 5188 (strcmp(tokens[7], "delete") == 0)) { 5189 cmd_pipeline_table_meter_profile_delete(softnic, tokens, 5190 n_tokens, out, out_size); 5191 return; 5192 } 5193 5194 if (n_tokens >= 7 && 5195 (strcmp(tokens[2], "table") == 0) && 5196 (strcmp(tokens[4], "rule") == 0) && 5197 (strcmp(tokens[5], "read") == 0) && 5198 (strcmp(tokens[6], "meter") == 0)) { 5199 cmd_pipeline_table_rule_meter_read(softnic, tokens, n_tokens, 5200 out, out_size); 5201 return; 5202 } 5203 5204 if (n_tokens >= 5 && 5205 (strcmp(tokens[2], "table") == 0) && 5206 (strcmp(tokens[4], "dscp") == 0)) { 5207 cmd_pipeline_table_dscp(softnic, tokens, n_tokens, 5208 out, out_size); 5209 return; 5210 } 5211 5212 if (n_tokens >= 7 && 5213 (strcmp(tokens[2], "table") == 0) && 5214 (strcmp(tokens[4], "rule") == 0) && 5215 (strcmp(tokens[5], "read") == 0) && 5216 (strcmp(tokens[6], "ttl") == 0)) { 5217 cmd_softnic_pipeline_table_rule_ttl_read(softnic, tokens, n_tokens, 5218 out, out_size); 5219 return; 5220 } 5221 } 5222 5223 if (strcmp(tokens[0], "thread") == 0) { 5224 if (n_tokens >= 5 && 5225 (strcmp(tokens[4], "enable") == 0)) { 5226 cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens, 5227 out, out_size); 5228 return; 5229 } 5230 5231 if (n_tokens >= 5 && 5232 (strcmp(tokens[4], "disable") == 0)) { 5233 cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens, 5234 out, out_size); 5235 return; 5236 } 5237 } 5238 5239 if (strcmp(tokens[0], "flowapi") == 0) { 5240 cmd_softnic_flowapi_map(softnic, tokens, n_tokens, out, 5241 out_size); 5242 return; 5243 } 5244 5245 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 5246 } 5247 5248 int 5249 softnic_cli_script_process(struct pmd_internals *softnic, 5250 const char *file_name, 5251 size_t msg_in_len_max, 5252 size_t msg_out_len_max) 5253 { 5254 char *msg_in = NULL, *msg_out = NULL; 5255 FILE *f = NULL; 5256 5257 /* Check input arguments */ 5258 if (file_name == NULL || 5259 (strlen(file_name) == 0) || 5260 msg_in_len_max == 0 || 5261 msg_out_len_max == 0) 5262 return -EINVAL; 5263 5264 msg_in = malloc(msg_in_len_max + 1); 5265 msg_out = malloc(msg_out_len_max + 1); 5266 if (msg_in == NULL || 5267 msg_out == NULL) { 5268 free(msg_out); 5269 free(msg_in); 5270 return -ENOMEM; 5271 } 5272 5273 /* Open input file */ 5274 f = fopen(file_name, "r"); 5275 if (f == NULL) { 5276 free(msg_out); 5277 free(msg_in); 5278 return -EIO; 5279 } 5280 5281 /* Read file */ 5282 for ( ; ; ) { 5283 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 5284 break; 5285 5286 printf("%s", msg_in); 5287 msg_out[0] = 0; 5288 5289 softnic_cli_process(msg_in, 5290 msg_out, 5291 msg_out_len_max, 5292 softnic); 5293 5294 if (strlen(msg_out)) 5295 printf("%s", msg_out); 5296 } 5297 5298 /* Close file */ 5299 fclose(f); 5300 free(msg_out); 5301 free(msg_in); 5302 return 0; 5303 } 5304 5305 static int 5306 cli_rule_file_process(const char *file_name, 5307 size_t line_len_max, 5308 struct softnic_table_rule_match *m, 5309 struct softnic_table_rule_action *a, 5310 uint32_t *n_rules, 5311 uint32_t *line_number, 5312 char *out, 5313 size_t out_size) 5314 { 5315 FILE *f = NULL; 5316 char *line = NULL; 5317 uint32_t rule_id, line_id; 5318 int status = 0; 5319 5320 /* Check input arguments */ 5321 if (file_name == NULL || 5322 (strlen(file_name) == 0) || 5323 line_len_max == 0) { 5324 *line_number = 0; 5325 return -EINVAL; 5326 } 5327 5328 /* Memory allocation */ 5329 line = malloc(line_len_max + 1); 5330 if (line == NULL) { 5331 *line_number = 0; 5332 return -ENOMEM; 5333 } 5334 5335 /* Open file */ 5336 f = fopen(file_name, "r"); 5337 if (f == NULL) { 5338 *line_number = 0; 5339 free(line); 5340 return -EIO; 5341 } 5342 5343 /* Read file */ 5344 for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) { 5345 char *tokens[CMD_MAX_TOKENS]; 5346 uint32_t n_tokens, n_tokens_parsed, t0; 5347 5348 /* Read next line from file. */ 5349 if (fgets(line, line_len_max + 1, f) == NULL) 5350 break; 5351 5352 /* Comment. */ 5353 if (is_comment(line)) 5354 continue; 5355 5356 /* Parse line. */ 5357 n_tokens = RTE_DIM(tokens); 5358 status = softnic_parse_tokenize_string(line, tokens, &n_tokens); 5359 if (status) { 5360 status = -EINVAL; 5361 break; 5362 } 5363 5364 /* Empty line. */ 5365 if (n_tokens == 0) 5366 continue; 5367 t0 = 0; 5368 5369 /* Rule match. */ 5370 n_tokens_parsed = parse_match(tokens + t0, 5371 n_tokens - t0, 5372 out, 5373 out_size, 5374 &m[rule_id]); 5375 if (n_tokens_parsed == 0) { 5376 status = -EINVAL; 5377 break; 5378 } 5379 t0 += n_tokens_parsed; 5380 5381 /* Rule action. */ 5382 n_tokens_parsed = parse_table_action(tokens + t0, 5383 n_tokens - t0, 5384 out, 5385 out_size, 5386 &a[rule_id]); 5387 if (n_tokens_parsed == 0) { 5388 status = -EINVAL; 5389 break; 5390 } 5391 t0 += n_tokens_parsed; 5392 5393 /* Line completed. */ 5394 if (t0 < n_tokens) { 5395 status = -EINVAL; 5396 break; 5397 } 5398 5399 /* Increment rule count */ 5400 rule_id++; 5401 } 5402 5403 /* Close file */ 5404 fclose(f); 5405 5406 /* Memory free */ 5407 free(line); 5408 5409 *n_rules = rule_id; 5410 *line_number = line_id; 5411 return status; 5412 } 5413