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