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