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 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); 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 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); 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 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); 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 strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); 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 strlcpy(p.action_profile_name, tokens[t0 + 1], 2013 sizeof(p.action_profile_name)); 2014 2015 t0 += 2; 2016 } 2017 2018 enabled = 1; 2019 if (n_tokens > t0 && 2020 (strcmp(tokens[t0], "disabled") == 0)) { 2021 enabled = 0; 2022 2023 t0 += 1; 2024 } 2025 2026 if (n_tokens != t0) { 2027 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2028 return; 2029 } 2030 2031 status = softnic_pipeline_port_in_create(softnic, 2032 pipeline_name, 2033 &p, 2034 enabled); 2035 if (status) { 2036 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2037 return; 2038 } 2039 } 2040 2041 /** 2042 * pipeline <pipeline_name> port out 2043 * bsz <burst_size> 2044 * link <link_name> txq <txq_id> 2045 * | swq <swq_name> 2046 * | tmgr <tmgr_name> 2047 * | tap <tap_name> 2048 * | sink [file <file_name> pkts <max_n_pkts>] 2049 * | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset> 2050 */ 2051 static void 2052 cmd_pipeline_port_out(struct pmd_internals *softnic, 2053 char **tokens, 2054 uint32_t n_tokens, 2055 char *out, 2056 size_t out_size) 2057 { 2058 struct softnic_port_out_params p; 2059 char *pipeline_name; 2060 int status; 2061 2062 memset(&p, 0, sizeof(p)); 2063 2064 if (n_tokens < 7) { 2065 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2066 return; 2067 } 2068 2069 pipeline_name = tokens[1]; 2070 2071 if (strcmp(tokens[2], "port") != 0) { 2072 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2073 return; 2074 } 2075 2076 if (strcmp(tokens[3], "out") != 0) { 2077 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 2078 return; 2079 } 2080 2081 if (strcmp(tokens[4], "bsz") != 0) { 2082 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 2083 return; 2084 } 2085 2086 if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 2087 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 2088 return; 2089 } 2090 2091 if (strcmp(tokens[6], "link") == 0) { 2092 if (n_tokens != 10) { 2093 snprintf(out, out_size, MSG_ARG_MISMATCH, 2094 "pipeline port out link"); 2095 return; 2096 } 2097 2098 p.type = PORT_OUT_TXQ; 2099 2100 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); 2101 2102 if (strcmp(tokens[8], "txq") != 0) { 2103 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 2104 return; 2105 } 2106 2107 if (softnic_parser_read_uint16(&p.txq.queue_id, 2108 tokens[9]) != 0) { 2109 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 2110 return; 2111 } 2112 } else if (strcmp(tokens[6], "swq") == 0) { 2113 if (n_tokens != 8) { 2114 snprintf(out, out_size, MSG_ARG_MISMATCH, 2115 "pipeline port out swq"); 2116 return; 2117 } 2118 2119 p.type = PORT_OUT_SWQ; 2120 2121 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); 2122 } else if (strcmp(tokens[6], "tmgr") == 0) { 2123 if (n_tokens != 8) { 2124 snprintf(out, out_size, MSG_ARG_MISMATCH, 2125 "pipeline port out tmgr"); 2126 return; 2127 } 2128 2129 p.type = PORT_OUT_TMGR; 2130 2131 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); 2132 } else if (strcmp(tokens[6], "tap") == 0) { 2133 if (n_tokens != 8) { 2134 snprintf(out, out_size, MSG_ARG_MISMATCH, 2135 "pipeline port out tap"); 2136 return; 2137 } 2138 2139 p.type = PORT_OUT_TAP; 2140 2141 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); 2142 } else if (strcmp(tokens[6], "sink") == 0) { 2143 if ((n_tokens != 7) && (n_tokens != 11)) { 2144 snprintf(out, out_size, MSG_ARG_MISMATCH, 2145 "pipeline port out sink"); 2146 return; 2147 } 2148 2149 p.type = PORT_OUT_SINK; 2150 2151 if (n_tokens == 7) { 2152 p.sink.file_name = NULL; 2153 p.sink.max_n_pkts = 0; 2154 } else { 2155 if (strcmp(tokens[7], "file") != 0) { 2156 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2157 "file"); 2158 return; 2159 } 2160 2161 p.sink.file_name = tokens[8]; 2162 2163 if (strcmp(tokens[9], "pkts") != 0) { 2164 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); 2165 return; 2166 } 2167 2168 if (softnic_parser_read_uint32(&p.sink.max_n_pkts, 2169 tokens[10]) != 0) { 2170 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); 2171 return; 2172 } 2173 } 2174 } else if (strcmp(tokens[6], "cryptodev") == 0) { 2175 if (n_tokens != 12) { 2176 snprintf(out, out_size, MSG_ARG_MISMATCH, 2177 "pipeline port out cryptodev"); 2178 return; 2179 } 2180 2181 p.type = PORT_OUT_CRYPTODEV; 2182 2183 strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); 2184 2185 if (strcmp(tokens[8], "txq")) { 2186 snprintf(out, out_size, MSG_ARG_MISMATCH, 2187 "pipeline port out cryptodev"); 2188 return; 2189 } 2190 2191 if (softnic_parser_read_uint16(&p.cryptodev.queue_id, tokens[9]) 2192 != 0) { 2193 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 2194 return; 2195 } 2196 2197 if (strcmp(tokens[10], "offset")) { 2198 snprintf(out, out_size, MSG_ARG_MISMATCH, 2199 "pipeline port out cryptodev"); 2200 return; 2201 } 2202 2203 if (softnic_parser_read_uint32(&p.cryptodev.op_offset, 2204 tokens[11]) != 0) { 2205 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 2206 return; 2207 } 2208 } else { 2209 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 2210 return; 2211 } 2212 2213 status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p); 2214 if (status) { 2215 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2216 return; 2217 } 2218 } 2219 2220 /** 2221 * pipeline <pipeline_name> table 2222 * match 2223 * acl 2224 * ipv4 | ipv6 2225 * offset <ip_header_offset> 2226 * size <n_rules> 2227 * | array 2228 * offset <key_offset> 2229 * size <n_keys> 2230 * | hash 2231 * ext | lru 2232 * key <key_size> 2233 * mask <key_mask> 2234 * offset <key_offset> 2235 * buckets <n_buckets> 2236 * size <n_keys> 2237 * | lpm 2238 * ipv4 | ipv6 2239 * offset <ip_header_offset> 2240 * size <n_rules> 2241 * | stub 2242 * [action <table_action_profile_name>] 2243 */ 2244 static void 2245 cmd_pipeline_table(struct pmd_internals *softnic, 2246 char **tokens, 2247 uint32_t n_tokens, 2248 char *out, 2249 size_t out_size) 2250 { 2251 struct softnic_table_params p; 2252 char *pipeline_name; 2253 uint32_t t0; 2254 int status; 2255 2256 memset(&p, 0, sizeof(p)); 2257 2258 if (n_tokens < 5) { 2259 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2260 return; 2261 } 2262 2263 pipeline_name = tokens[1]; 2264 2265 if (strcmp(tokens[2], "table") != 0) { 2266 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 2267 return; 2268 } 2269 2270 if (strcmp(tokens[3], "match") != 0) { 2271 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2272 return; 2273 } 2274 2275 t0 = 4; 2276 if (strcmp(tokens[t0], "acl") == 0) { 2277 if (n_tokens < t0 + 6) { 2278 snprintf(out, out_size, MSG_ARG_MISMATCH, 2279 "pipeline table acl"); 2280 return; 2281 } 2282 2283 p.match_type = TABLE_ACL; 2284 2285 if (strcmp(tokens[t0 + 1], "ipv4") == 0) { 2286 p.match.acl.ip_version = 1; 2287 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { 2288 p.match.acl.ip_version = 0; 2289 } else { 2290 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2291 "ipv4 or ipv6"); 2292 return; 2293 } 2294 2295 if (strcmp(tokens[t0 + 2], "offset") != 0) { 2296 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2297 return; 2298 } 2299 2300 if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset, 2301 tokens[t0 + 3]) != 0) { 2302 snprintf(out, out_size, MSG_ARG_INVALID, 2303 "ip_header_offset"); 2304 return; 2305 } 2306 2307 if (strcmp(tokens[t0 + 4], "size") != 0) { 2308 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2309 return; 2310 } 2311 2312 if (softnic_parser_read_uint32(&p.match.acl.n_rules, 2313 tokens[t0 + 5]) != 0) { 2314 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 2315 return; 2316 } 2317 2318 t0 += 6; 2319 } else if (strcmp(tokens[t0], "array") == 0) { 2320 if (n_tokens < t0 + 5) { 2321 snprintf(out, out_size, MSG_ARG_MISMATCH, 2322 "pipeline table array"); 2323 return; 2324 } 2325 2326 p.match_type = TABLE_ARRAY; 2327 2328 if (strcmp(tokens[t0 + 1], "offset") != 0) { 2329 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2330 return; 2331 } 2332 2333 if (softnic_parser_read_uint32(&p.match.array.key_offset, 2334 tokens[t0 + 2]) != 0) { 2335 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2336 return; 2337 } 2338 2339 if (strcmp(tokens[t0 + 3], "size") != 0) { 2340 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2341 return; 2342 } 2343 2344 if (softnic_parser_read_uint32(&p.match.array.n_keys, 2345 tokens[t0 + 4]) != 0) { 2346 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 2347 return; 2348 } 2349 2350 t0 += 5; 2351 } else if (strcmp(tokens[t0], "hash") == 0) { 2352 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; 2353 2354 if (n_tokens < t0 + 12) { 2355 snprintf(out, out_size, MSG_ARG_MISMATCH, 2356 "pipeline table hash"); 2357 return; 2358 } 2359 2360 p.match_type = TABLE_HASH; 2361 2362 if (strcmp(tokens[t0 + 1], "ext") == 0) { 2363 p.match.hash.extendable_bucket = 1; 2364 } else if (strcmp(tokens[t0 + 1], "lru") == 0) { 2365 p.match.hash.extendable_bucket = 0; 2366 } else { 2367 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2368 "ext or lru"); 2369 return; 2370 } 2371 2372 if (strcmp(tokens[t0 + 2], "key") != 0) { 2373 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 2374 return; 2375 } 2376 2377 if ((softnic_parser_read_uint32(&p.match.hash.key_size, 2378 tokens[t0 + 3]) != 0) || 2379 p.match.hash.key_size == 0 || 2380 p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) { 2381 snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); 2382 return; 2383 } 2384 2385 if (strcmp(tokens[t0 + 4], "mask") != 0) { 2386 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 2387 return; 2388 } 2389 2390 if ((softnic_parse_hex_string(tokens[t0 + 5], 2391 p.match.hash.key_mask, &key_mask_size) != 0) || 2392 key_mask_size != p.match.hash.key_size) { 2393 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 2394 return; 2395 } 2396 2397 if (strcmp(tokens[t0 + 6], "offset") != 0) { 2398 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2399 return; 2400 } 2401 2402 if (softnic_parser_read_uint32(&p.match.hash.key_offset, 2403 tokens[t0 + 7]) != 0) { 2404 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2405 return; 2406 } 2407 2408 if (strcmp(tokens[t0 + 8], "buckets") != 0) { 2409 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); 2410 return; 2411 } 2412 2413 if (softnic_parser_read_uint32(&p.match.hash.n_buckets, 2414 tokens[t0 + 9]) != 0) { 2415 snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); 2416 return; 2417 } 2418 2419 if (strcmp(tokens[t0 + 10], "size") != 0) { 2420 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2421 return; 2422 } 2423 2424 if (softnic_parser_read_uint32(&p.match.hash.n_keys, 2425 tokens[t0 + 11]) != 0) { 2426 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 2427 return; 2428 } 2429 2430 t0 += 12; 2431 } else if (strcmp(tokens[t0], "lpm") == 0) { 2432 if (n_tokens < t0 + 6) { 2433 snprintf(out, out_size, MSG_ARG_MISMATCH, 2434 "pipeline table lpm"); 2435 return; 2436 } 2437 2438 p.match_type = TABLE_LPM; 2439 2440 if (strcmp(tokens[t0 + 1], "ipv4") == 0) { 2441 p.match.lpm.key_size = 4; 2442 } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { 2443 p.match.lpm.key_size = 16; 2444 } else { 2445 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2446 "ipv4 or ipv6"); 2447 return; 2448 } 2449 2450 if (strcmp(tokens[t0 + 2], "offset") != 0) { 2451 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2452 return; 2453 } 2454 2455 if (softnic_parser_read_uint32(&p.match.lpm.key_offset, 2456 tokens[t0 + 3]) != 0) { 2457 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2458 return; 2459 } 2460 2461 if (strcmp(tokens[t0 + 4], "size") != 0) { 2462 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2463 return; 2464 } 2465 2466 if (softnic_parser_read_uint32(&p.match.lpm.n_rules, 2467 tokens[t0 + 5]) != 0) { 2468 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 2469 return; 2470 } 2471 2472 t0 += 6; 2473 } else if (strcmp(tokens[t0], "stub") == 0) { 2474 p.match_type = TABLE_STUB; 2475 2476 t0 += 1; 2477 } else { 2478 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 2479 return; 2480 } 2481 2482 if (n_tokens > t0 && 2483 (strcmp(tokens[t0], "action") == 0)) { 2484 if (n_tokens < t0 + 2) { 2485 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 2486 return; 2487 } 2488 2489 strlcpy(p.action_profile_name, tokens[t0 + 1], 2490 sizeof(p.action_profile_name)); 2491 2492 t0 += 2; 2493 } 2494 2495 if (n_tokens > t0) { 2496 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2497 return; 2498 } 2499 2500 status = softnic_pipeline_table_create(softnic, pipeline_name, &p); 2501 if (status) { 2502 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2503 return; 2504 } 2505 } 2506 2507 /** 2508 * pipeline <pipeline_name> port in <port_id> table <table_id> 2509 */ 2510 static void 2511 cmd_pipeline_port_in_table(struct pmd_internals *softnic, 2512 char **tokens, 2513 uint32_t n_tokens, 2514 char *out, 2515 size_t out_size) 2516 { 2517 char *pipeline_name; 2518 uint32_t port_id, table_id; 2519 int status; 2520 2521 if (n_tokens != 7) { 2522 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2523 return; 2524 } 2525 2526 pipeline_name = tokens[1]; 2527 2528 if (strcmp(tokens[2], "port") != 0) { 2529 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2530 return; 2531 } 2532 2533 if (strcmp(tokens[3], "in") != 0) { 2534 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2535 return; 2536 } 2537 2538 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2539 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2540 return; 2541 } 2542 2543 if (strcmp(tokens[5], "table") != 0) { 2544 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 2545 return; 2546 } 2547 2548 if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) { 2549 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2550 return; 2551 } 2552 2553 status = softnic_pipeline_port_in_connect_to_table(softnic, 2554 pipeline_name, 2555 port_id, 2556 table_id); 2557 if (status) { 2558 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2559 return; 2560 } 2561 } 2562 2563 /** 2564 * pipeline <pipeline_name> port in <port_id> stats read [clear] 2565 */ 2566 2567 #define MSG_PIPELINE_PORT_IN_STATS \ 2568 "Pkts in: %" PRIu64 "\n" \ 2569 "Pkts dropped by AH: %" PRIu64 "\n" \ 2570 "Pkts dropped by other: %" PRIu64 "\n" 2571 2572 static void 2573 cmd_pipeline_port_in_stats(struct pmd_internals *softnic, 2574 char **tokens, 2575 uint32_t n_tokens, 2576 char *out, 2577 size_t out_size) 2578 { 2579 struct rte_pipeline_port_in_stats stats; 2580 char *pipeline_name; 2581 uint32_t port_id; 2582 int clear, status; 2583 2584 if (n_tokens != 7 && 2585 n_tokens != 8) { 2586 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2587 return; 2588 } 2589 2590 pipeline_name = tokens[1]; 2591 2592 if (strcmp(tokens[2], "port") != 0) { 2593 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2594 return; 2595 } 2596 2597 if (strcmp(tokens[3], "in") != 0) { 2598 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2599 return; 2600 } 2601 2602 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2603 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2604 return; 2605 } 2606 2607 if (strcmp(tokens[5], "stats") != 0) { 2608 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2609 return; 2610 } 2611 2612 if (strcmp(tokens[6], "read") != 0) { 2613 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2614 return; 2615 } 2616 2617 clear = 0; 2618 if (n_tokens == 8) { 2619 if (strcmp(tokens[7], "clear") != 0) { 2620 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2621 return; 2622 } 2623 2624 clear = 1; 2625 } 2626 2627 status = softnic_pipeline_port_in_stats_read(softnic, 2628 pipeline_name, 2629 port_id, 2630 &stats, 2631 clear); 2632 if (status) { 2633 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2634 return; 2635 } 2636 2637 snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, 2638 stats.stats.n_pkts_in, 2639 stats.n_pkts_dropped_by_ah, 2640 stats.stats.n_pkts_drop); 2641 } 2642 2643 /** 2644 * pipeline <pipeline_name> port in <port_id> enable 2645 */ 2646 static void 2647 cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic, 2648 char **tokens, 2649 uint32_t n_tokens, 2650 char *out, 2651 size_t out_size) 2652 { 2653 char *pipeline_name; 2654 uint32_t port_id; 2655 int status; 2656 2657 if (n_tokens != 6) { 2658 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2659 return; 2660 } 2661 2662 pipeline_name = tokens[1]; 2663 2664 if (strcmp(tokens[2], "port") != 0) { 2665 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2666 return; 2667 } 2668 2669 if (strcmp(tokens[3], "in") != 0) { 2670 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2671 return; 2672 } 2673 2674 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2675 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2676 return; 2677 } 2678 2679 if (strcmp(tokens[5], "enable") != 0) { 2680 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2681 return; 2682 } 2683 2684 status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id); 2685 if (status) { 2686 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2687 return; 2688 } 2689 } 2690 2691 /** 2692 * pipeline <pipeline_name> port in <port_id> disable 2693 */ 2694 static void 2695 cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic, 2696 char **tokens, 2697 uint32_t n_tokens, 2698 char *out, 2699 size_t out_size) 2700 { 2701 char *pipeline_name; 2702 uint32_t port_id; 2703 int status; 2704 2705 if (n_tokens != 6) { 2706 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2707 return; 2708 } 2709 2710 pipeline_name = tokens[1]; 2711 2712 if (strcmp(tokens[2], "port") != 0) { 2713 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2714 return; 2715 } 2716 2717 if (strcmp(tokens[3], "in") != 0) { 2718 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2719 return; 2720 } 2721 2722 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2723 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2724 return; 2725 } 2726 2727 if (strcmp(tokens[5], "disable") != 0) { 2728 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2729 return; 2730 } 2731 2732 status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id); 2733 if (status) { 2734 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2735 return; 2736 } 2737 } 2738 2739 /** 2740 * pipeline <pipeline_name> port out <port_id> stats read [clear] 2741 */ 2742 #define MSG_PIPELINE_PORT_OUT_STATS \ 2743 "Pkts in: %" PRIu64 "\n" \ 2744 "Pkts dropped by AH: %" PRIu64 "\n" \ 2745 "Pkts dropped by other: %" PRIu64 "\n" 2746 2747 static void 2748 cmd_pipeline_port_out_stats(struct pmd_internals *softnic, 2749 char **tokens, 2750 uint32_t n_tokens, 2751 char *out, 2752 size_t out_size) 2753 { 2754 struct rte_pipeline_port_out_stats stats; 2755 char *pipeline_name; 2756 uint32_t port_id; 2757 int clear, status; 2758 2759 if (n_tokens != 7 && 2760 n_tokens != 8) { 2761 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2762 return; 2763 } 2764 2765 pipeline_name = tokens[1]; 2766 2767 if (strcmp(tokens[2], "port") != 0) { 2768 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2769 return; 2770 } 2771 2772 if (strcmp(tokens[3], "out") != 0) { 2773 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 2774 return; 2775 } 2776 2777 if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { 2778 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2779 return; 2780 } 2781 2782 if (strcmp(tokens[5], "stats") != 0) { 2783 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2784 return; 2785 } 2786 2787 if (strcmp(tokens[6], "read") != 0) { 2788 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2789 return; 2790 } 2791 2792 clear = 0; 2793 if (n_tokens == 8) { 2794 if (strcmp(tokens[7], "clear") != 0) { 2795 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2796 return; 2797 } 2798 2799 clear = 1; 2800 } 2801 2802 status = softnic_pipeline_port_out_stats_read(softnic, 2803 pipeline_name, 2804 port_id, 2805 &stats, 2806 clear); 2807 if (status) { 2808 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2809 return; 2810 } 2811 2812 snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, 2813 stats.stats.n_pkts_in, 2814 stats.n_pkts_dropped_by_ah, 2815 stats.stats.n_pkts_drop); 2816 } 2817 2818 /** 2819 * pipeline <pipeline_name> table <table_id> stats read [clear] 2820 */ 2821 #define MSG_PIPELINE_TABLE_STATS \ 2822 "Pkts in: %" PRIu64 "\n" \ 2823 "Pkts in with lookup miss: %" PRIu64 "\n" \ 2824 "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ 2825 "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ 2826 "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ 2827 "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" 2828 2829 static void 2830 cmd_pipeline_table_stats(struct pmd_internals *softnic, 2831 char **tokens, 2832 uint32_t n_tokens, 2833 char *out, 2834 size_t out_size) 2835 { 2836 struct rte_pipeline_table_stats stats; 2837 char *pipeline_name; 2838 uint32_t table_id; 2839 int clear, status; 2840 2841 if (n_tokens != 6 && 2842 n_tokens != 7) { 2843 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2844 return; 2845 } 2846 2847 pipeline_name = tokens[1]; 2848 2849 if (strcmp(tokens[2], "table") != 0) { 2850 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2851 return; 2852 } 2853 2854 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 2855 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2856 return; 2857 } 2858 2859 if (strcmp(tokens[4], "stats") != 0) { 2860 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2861 return; 2862 } 2863 2864 if (strcmp(tokens[5], "read") != 0) { 2865 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2866 return; 2867 } 2868 2869 clear = 0; 2870 if (n_tokens == 7) { 2871 if (strcmp(tokens[6], "clear") != 0) { 2872 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2873 return; 2874 } 2875 2876 clear = 1; 2877 } 2878 2879 status = softnic_pipeline_table_stats_read(softnic, 2880 pipeline_name, 2881 table_id, 2882 &stats, 2883 clear); 2884 if (status) { 2885 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2886 return; 2887 } 2888 2889 snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, 2890 stats.stats.n_pkts_in, 2891 stats.stats.n_pkts_lookup_miss, 2892 stats.n_pkts_dropped_by_lkp_hit_ah, 2893 stats.n_pkts_dropped_lkp_hit, 2894 stats.n_pkts_dropped_by_lkp_miss_ah, 2895 stats.n_pkts_dropped_lkp_miss); 2896 } 2897 2898 /** 2899 * <match> ::= 2900 * 2901 * match 2902 * acl 2903 * priority <priority> 2904 * ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth> 2905 * <sp0> <sp1> <dp0> <dp1> <proto> 2906 * | array <pos> 2907 * | hash 2908 * raw <key> 2909 * | ipv4_5tuple <sa> <da> <sp> <dp> <proto> 2910 * | ipv6_5tuple <sa> <da> <sp> <dp> <proto> 2911 * | ipv4_addr <addr> 2912 * | ipv6_addr <addr> 2913 * | qinq <svlan> <cvlan> 2914 * | lpm 2915 * ipv4 | ipv6 <addr> <depth> 2916 */ 2917 struct pkt_key_qinq { 2918 uint16_t ethertype_svlan; 2919 uint16_t svlan; 2920 uint16_t ethertype_cvlan; 2921 uint16_t cvlan; 2922 } __attribute__((__packed__)); 2923 2924 struct pkt_key_ipv4_5tuple { 2925 uint8_t time_to_live; 2926 uint8_t proto; 2927 uint16_t hdr_checksum; 2928 uint32_t sa; 2929 uint32_t da; 2930 uint16_t sp; 2931 uint16_t dp; 2932 } __attribute__((__packed__)); 2933 2934 struct pkt_key_ipv6_5tuple { 2935 uint16_t payload_length; 2936 uint8_t proto; 2937 uint8_t hop_limit; 2938 uint8_t sa[16]; 2939 uint8_t da[16]; 2940 uint16_t sp; 2941 uint16_t dp; 2942 } __attribute__((__packed__)); 2943 2944 struct pkt_key_ipv4_addr { 2945 uint32_t addr; 2946 } __attribute__((__packed__)); 2947 2948 struct pkt_key_ipv6_addr { 2949 uint8_t addr[16]; 2950 } __attribute__((__packed__)); 2951 2952 static uint32_t 2953 parse_match(char **tokens, 2954 uint32_t n_tokens, 2955 char *out, 2956 size_t out_size, 2957 struct softnic_table_rule_match *m) 2958 { 2959 memset(m, 0, sizeof(*m)); 2960 2961 if (n_tokens < 2) 2962 return 0; 2963 2964 if (strcmp(tokens[0], "match") != 0) { 2965 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2966 return 0; 2967 } 2968 2969 if (strcmp(tokens[1], "acl") == 0) { 2970 if (n_tokens < 14) { 2971 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2972 return 0; 2973 } 2974 2975 m->match_type = TABLE_ACL; 2976 2977 if (strcmp(tokens[2], "priority") != 0) { 2978 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); 2979 return 0; 2980 } 2981 2982 if (softnic_parser_read_uint32(&m->match.acl.priority, 2983 tokens[3]) != 0) { 2984 snprintf(out, out_size, MSG_ARG_INVALID, "priority"); 2985 return 0; 2986 } 2987 2988 if (strcmp(tokens[4], "ipv4") == 0) { 2989 struct in_addr saddr, daddr; 2990 2991 m->match.acl.ip_version = 1; 2992 2993 if (softnic_parse_ipv4_addr(tokens[5], &saddr) != 0) { 2994 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2995 return 0; 2996 } 2997 m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); 2998 2999 if (softnic_parse_ipv4_addr(tokens[7], &daddr) != 0) { 3000 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 3001 return 0; 3002 } 3003 m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); 3004 } else if (strcmp(tokens[4], "ipv6") == 0) { 3005 struct in6_addr saddr, daddr; 3006 3007 m->match.acl.ip_version = 0; 3008 3009 if (softnic_parse_ipv6_addr(tokens[5], &saddr) != 0) { 3010 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 3011 return 0; 3012 } 3013 memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); 3014 3015 if (softnic_parse_ipv6_addr(tokens[7], &daddr) != 0) { 3016 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 3017 return 0; 3018 } 3019 memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); 3020 } else { 3021 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 3022 "ipv4 or ipv6"); 3023 return 0; 3024 } 3025 3026 if (softnic_parser_read_uint32(&m->match.acl.sa_depth, 3027 tokens[6]) != 0) { 3028 snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); 3029 return 0; 3030 } 3031 3032 if (softnic_parser_read_uint32(&m->match.acl.da_depth, 3033 tokens[8]) != 0) { 3034 snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); 3035 return 0; 3036 } 3037 3038 if (softnic_parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { 3039 snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); 3040 return 0; 3041 } 3042 3043 if (softnic_parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { 3044 snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); 3045 return 0; 3046 } 3047 3048 if (softnic_parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { 3049 snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); 3050 return 0; 3051 } 3052 3053 if (softnic_parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { 3054 snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); 3055 return 0; 3056 } 3057 3058 if (softnic_parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { 3059 snprintf(out, out_size, MSG_ARG_INVALID, "proto"); 3060 return 0; 3061 } 3062 3063 m->match.acl.proto_mask = 0xff; 3064 3065 return 14; 3066 } /* acl */ 3067 3068 if (strcmp(tokens[1], "array") == 0) { 3069 if (n_tokens < 3) { 3070 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3071 return 0; 3072 } 3073 3074 m->match_type = TABLE_ARRAY; 3075 3076 if (softnic_parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { 3077 snprintf(out, out_size, MSG_ARG_INVALID, "pos"); 3078 return 0; 3079 } 3080 3081 return 3; 3082 } /* array */ 3083 3084 if (strcmp(tokens[1], "hash") == 0) { 3085 if (n_tokens < 3) { 3086 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3087 return 0; 3088 } 3089 3090 m->match_type = TABLE_HASH; 3091 3092 if (strcmp(tokens[2], "raw") == 0) { 3093 uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; 3094 3095 if (n_tokens < 4) { 3096 snprintf(out, out_size, MSG_ARG_MISMATCH, 3097 tokens[0]); 3098 return 0; 3099 } 3100 3101 if (softnic_parse_hex_string(tokens[3], 3102 m->match.hash.key, &key_size) != 0) { 3103 snprintf(out, out_size, MSG_ARG_INVALID, "key"); 3104 return 0; 3105 } 3106 3107 return 4; 3108 } /* hash raw */ 3109 3110 if (strcmp(tokens[2], "ipv4_5tuple") == 0) { 3111 struct pkt_key_ipv4_5tuple *ipv4 = 3112 (struct pkt_key_ipv4_5tuple *)m->match.hash.key; 3113 struct in_addr saddr, daddr; 3114 uint16_t sp, dp; 3115 uint8_t proto; 3116 3117 if (n_tokens < 8) { 3118 snprintf(out, out_size, MSG_ARG_MISMATCH, 3119 tokens[0]); 3120 return 0; 3121 } 3122 3123 if (softnic_parse_ipv4_addr(tokens[3], &saddr) != 0) { 3124 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 3125 return 0; 3126 } 3127 3128 if (softnic_parse_ipv4_addr(tokens[4], &daddr) != 0) { 3129 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 3130 return 0; 3131 } 3132 3133 if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { 3134 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 3135 return 0; 3136 } 3137 3138 if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { 3139 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 3140 return 0; 3141 } 3142 3143 if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { 3144 snprintf(out, out_size, MSG_ARG_INVALID, 3145 "proto"); 3146 return 0; 3147 } 3148 3149 ipv4->sa = saddr.s_addr; 3150 ipv4->da = daddr.s_addr; 3151 ipv4->sp = rte_cpu_to_be_16(sp); 3152 ipv4->dp = rte_cpu_to_be_16(dp); 3153 ipv4->proto = proto; 3154 3155 return 8; 3156 } /* hash ipv4_5tuple */ 3157 3158 if (strcmp(tokens[2], "ipv6_5tuple") == 0) { 3159 struct pkt_key_ipv6_5tuple *ipv6 = 3160 (struct pkt_key_ipv6_5tuple *)m->match.hash.key; 3161 struct in6_addr saddr, daddr; 3162 uint16_t sp, dp; 3163 uint8_t proto; 3164 3165 if (n_tokens < 8) { 3166 snprintf(out, out_size, MSG_ARG_MISMATCH, 3167 tokens[0]); 3168 return 0; 3169 } 3170 3171 if (softnic_parse_ipv6_addr(tokens[3], &saddr) != 0) { 3172 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 3173 return 0; 3174 } 3175 3176 if (softnic_parse_ipv6_addr(tokens[4], &daddr) != 0) { 3177 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 3178 return 0; 3179 } 3180 3181 if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { 3182 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 3183 return 0; 3184 } 3185 3186 if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { 3187 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 3188 return 0; 3189 } 3190 3191 if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { 3192 snprintf(out, out_size, MSG_ARG_INVALID, 3193 "proto"); 3194 return 0; 3195 } 3196 3197 memcpy(ipv6->sa, saddr.s6_addr, 16); 3198 memcpy(ipv6->da, daddr.s6_addr, 16); 3199 ipv6->sp = rte_cpu_to_be_16(sp); 3200 ipv6->dp = rte_cpu_to_be_16(dp); 3201 ipv6->proto = proto; 3202 3203 return 8; 3204 } /* hash ipv6_5tuple */ 3205 3206 if (strcmp(tokens[2], "ipv4_addr") == 0) { 3207 struct pkt_key_ipv4_addr *ipv4_addr = 3208 (struct pkt_key_ipv4_addr *)m->match.hash.key; 3209 struct in_addr addr; 3210 3211 if (n_tokens < 4) { 3212 snprintf(out, out_size, MSG_ARG_MISMATCH, 3213 tokens[0]); 3214 return 0; 3215 } 3216 3217 if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { 3218 snprintf(out, out_size, MSG_ARG_INVALID, 3219 "addr"); 3220 return 0; 3221 } 3222 3223 ipv4_addr->addr = addr.s_addr; 3224 3225 return 4; 3226 } /* hash ipv4_addr */ 3227 3228 if (strcmp(tokens[2], "ipv6_addr") == 0) { 3229 struct pkt_key_ipv6_addr *ipv6_addr = 3230 (struct pkt_key_ipv6_addr *)m->match.hash.key; 3231 struct in6_addr addr; 3232 3233 if (n_tokens < 4) { 3234 snprintf(out, out_size, MSG_ARG_MISMATCH, 3235 tokens[0]); 3236 return 0; 3237 } 3238 3239 if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { 3240 snprintf(out, out_size, MSG_ARG_INVALID, 3241 "addr"); 3242 return 0; 3243 } 3244 3245 memcpy(ipv6_addr->addr, addr.s6_addr, 16); 3246 3247 return 4; 3248 } /* hash ipv6_5tuple */ 3249 3250 if (strcmp(tokens[2], "qinq") == 0) { 3251 struct pkt_key_qinq *qinq = 3252 (struct pkt_key_qinq *)m->match.hash.key; 3253 uint16_t svlan, cvlan; 3254 3255 if (n_tokens < 5) { 3256 snprintf(out, out_size, MSG_ARG_MISMATCH, 3257 tokens[0]); 3258 return 0; 3259 } 3260 3261 if ((softnic_parser_read_uint16(&svlan, tokens[3]) != 0) || 3262 svlan > 0xFFF) { 3263 snprintf(out, out_size, MSG_ARG_INVALID, 3264 "svlan"); 3265 return 0; 3266 } 3267 3268 if ((softnic_parser_read_uint16(&cvlan, tokens[4]) != 0) || 3269 cvlan > 0xFFF) { 3270 snprintf(out, out_size, MSG_ARG_INVALID, 3271 "cvlan"); 3272 return 0; 3273 } 3274 3275 qinq->svlan = rte_cpu_to_be_16(svlan); 3276 qinq->cvlan = rte_cpu_to_be_16(cvlan); 3277 3278 return 5; 3279 } /* hash qinq */ 3280 3281 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3282 return 0; 3283 } /* hash */ 3284 3285 if (strcmp(tokens[1], "lpm") == 0) { 3286 if (n_tokens < 5) { 3287 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 3288 return 0; 3289 } 3290 3291 m->match_type = TABLE_LPM; 3292 3293 if (strcmp(tokens[2], "ipv4") == 0) { 3294 struct in_addr addr; 3295 3296 m->match.lpm.ip_version = 1; 3297 3298 if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { 3299 snprintf(out, out_size, MSG_ARG_INVALID, 3300 "addr"); 3301 return 0; 3302 } 3303 3304 m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr); 3305 } else if (strcmp(tokens[2], "ipv6") == 0) { 3306 struct in6_addr addr; 3307 3308 m->match.lpm.ip_version = 0; 3309 3310 if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { 3311 snprintf(out, out_size, MSG_ARG_INVALID, 3312 "addr"); 3313 return 0; 3314 } 3315 3316 memcpy(m->match.lpm.ipv6, addr.s6_addr, 16); 3317 } else { 3318 snprintf(out, out_size, MSG_ARG_MISMATCH, 3319 "ipv4 or ipv6"); 3320 return 0; 3321 } 3322 3323 if (softnic_parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) { 3324 snprintf(out, out_size, MSG_ARG_INVALID, "depth"); 3325 return 0; 3326 } 3327 3328 return 5; 3329 } /* lpm */ 3330 3331 snprintf(out, out_size, MSG_ARG_MISMATCH, 3332 "acl or array or hash or lpm"); 3333 return 0; 3334 } 3335 3336 /** 3337 * table_action ::= 3338 * 3339 * action 3340 * fwd 3341 * drop 3342 * | port <port_id> 3343 * | meta 3344 * | table <table_id> 3345 * [balance <out0> ... <out7>] 3346 * [meter 3347 * tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3348 * [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3349 * tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3350 * tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]] 3351 * [tm subport <subport_id> pipe <pipe_id>] 3352 * [encap 3353 * ether <da> <sa> 3354 * | vlan <da> <sa> <pcp> <dei> <vid> 3355 * | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid> 3356 * | mpls unicast | multicast 3357 * <da> <sa> 3358 * label0 <label> <tc> <ttl> 3359 * [label1 <label> <tc> <ttl> 3360 * [label2 <label> <tc> <ttl> 3361 * [label3 <label> <tc> <ttl>]]] 3362 * | pppoe <da> <sa> <session_id>] 3363 * | vxlan ether <da> <sa> 3364 * [vlan <pcp> <dei> <vid>] 3365 * ipv4 <sa> <da> <dscp> <ttl> 3366 * | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> 3367 * udp <sp> <dp> 3368 * vxlan <vni>] 3369 * [nat ipv4 | ipv6 <addr> <port>] 3370 * [ttl dec | keep] 3371 * [stats] 3372 * [time] 3373 * [tag <tag>] 3374 * [decap <n>] 3375 * [sym_crypto 3376 * encrypt | decrypt 3377 * type 3378 * | cipher 3379 * cipher_algo <algo> cipher_key <key> cipher_iv <iv> 3380 * | cipher_auth 3381 * cipher_algo <algo> cipher_key <key> cipher_iv <iv> 3382 * auth_algo <algo> auth_key <key> digest_size <size> 3383 * | aead 3384 * aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad> 3385 * digest_size <size> 3386 * data_offset <data_offset>] 3387 * 3388 * where: 3389 * <pa> ::= g | y | r | drop 3390 */ 3391 static uint32_t 3392 parse_table_action_fwd(char **tokens, 3393 uint32_t n_tokens, 3394 struct softnic_table_rule_action *a) 3395 { 3396 if (n_tokens == 0 || 3397 (strcmp(tokens[0], "fwd") != 0)) 3398 return 0; 3399 3400 tokens++; 3401 n_tokens--; 3402 3403 if (n_tokens && (strcmp(tokens[0], "drop") == 0)) { 3404 a->fwd.action = RTE_PIPELINE_ACTION_DROP; 3405 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3406 return 1 + 1; 3407 } 3408 3409 if (n_tokens && (strcmp(tokens[0], "port") == 0)) { 3410 uint32_t id; 3411 3412 if (n_tokens < 2 || 3413 softnic_parser_read_uint32(&id, tokens[1])) 3414 return 0; 3415 3416 a->fwd.action = RTE_PIPELINE_ACTION_PORT; 3417 a->fwd.id = id; 3418 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3419 return 1 + 2; 3420 } 3421 3422 if (n_tokens && (strcmp(tokens[0], "meta") == 0)) { 3423 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META; 3424 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3425 return 1 + 1; 3426 } 3427 3428 if (n_tokens && (strcmp(tokens[0], "table") == 0)) { 3429 uint32_t id; 3430 3431 if (n_tokens < 2 || 3432 softnic_parser_read_uint32(&id, tokens[1])) 3433 return 0; 3434 3435 a->fwd.action = RTE_PIPELINE_ACTION_TABLE; 3436 a->fwd.id = id; 3437 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3438 return 1 + 2; 3439 } 3440 3441 return 0; 3442 } 3443 3444 static uint32_t 3445 parse_table_action_balance(char **tokens, 3446 uint32_t n_tokens, 3447 struct softnic_table_rule_action *a) 3448 { 3449 uint32_t i; 3450 3451 if (n_tokens == 0 || 3452 (strcmp(tokens[0], "balance") != 0)) 3453 return 0; 3454 3455 tokens++; 3456 n_tokens--; 3457 3458 if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE) 3459 return 0; 3460 3461 for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++) 3462 if (softnic_parser_read_uint32(&a->lb.out[i], tokens[i]) != 0) 3463 return 0; 3464 3465 a->action_mask |= 1 << RTE_TABLE_ACTION_LB; 3466 return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE; 3467 } 3468 3469 static int 3470 parse_policer_action(char *token, enum rte_table_action_policer *a) 3471 { 3472 if (strcmp(token, "g") == 0) { 3473 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN; 3474 return 0; 3475 } 3476 3477 if (strcmp(token, "y") == 0) { 3478 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW; 3479 return 0; 3480 } 3481 3482 if (strcmp(token, "r") == 0) { 3483 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED; 3484 return 0; 3485 } 3486 3487 if (strcmp(token, "drop") == 0) { 3488 *a = RTE_TABLE_ACTION_POLICER_DROP; 3489 return 0; 3490 } 3491 3492 return -1; 3493 } 3494 3495 static uint32_t 3496 parse_table_action_meter_tc(char **tokens, 3497 uint32_t n_tokens, 3498 struct rte_table_action_mtr_tc_params *mtr) 3499 { 3500 if (n_tokens < 9 || 3501 strcmp(tokens[0], "meter") || 3502 softnic_parser_read_uint32(&mtr->meter_profile_id, tokens[1]) || 3503 strcmp(tokens[2], "policer") || 3504 strcmp(tokens[3], "g") || 3505 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) || 3506 strcmp(tokens[5], "y") || 3507 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) || 3508 strcmp(tokens[7], "r") || 3509 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED])) 3510 return 0; 3511 3512 return 9; 3513 } 3514 3515 static uint32_t 3516 parse_table_action_meter(char **tokens, 3517 uint32_t n_tokens, 3518 struct softnic_table_rule_action *a) 3519 { 3520 if (n_tokens == 0 || 3521 strcmp(tokens[0], "meter")) 3522 return 0; 3523 3524 tokens++; 3525 n_tokens--; 3526 3527 if (n_tokens < 10 || 3528 strcmp(tokens[0], "tc0") || 3529 (parse_table_action_meter_tc(tokens + 1, 3530 n_tokens - 1, 3531 &a->mtr.mtr[0]) == 0)) 3532 return 0; 3533 3534 tokens += 10; 3535 n_tokens -= 10; 3536 3537 if (n_tokens == 0 || 3538 strcmp(tokens[0], "tc1")) { 3539 a->mtr.tc_mask = 1; 3540 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 3541 return 1 + 10; 3542 } 3543 3544 if (n_tokens < 30 || 3545 (parse_table_action_meter_tc(tokens + 1, 3546 n_tokens - 1, &a->mtr.mtr[1]) == 0) || 3547 strcmp(tokens[10], "tc2") || 3548 (parse_table_action_meter_tc(tokens + 11, 3549 n_tokens - 11, &a->mtr.mtr[2]) == 0) || 3550 strcmp(tokens[20], "tc3") || 3551 (parse_table_action_meter_tc(tokens + 21, 3552 n_tokens - 21, &a->mtr.mtr[3]) == 0)) 3553 return 0; 3554 3555 a->mtr.tc_mask = 0xF; 3556 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 3557 return 1 + 10 + 3 * 10; 3558 } 3559 3560 static uint32_t 3561 parse_table_action_tm(char **tokens, 3562 uint32_t n_tokens, 3563 struct softnic_table_rule_action *a) 3564 { 3565 uint32_t subport_id, pipe_id; 3566 3567 if (n_tokens < 5 || 3568 strcmp(tokens[0], "tm") || 3569 strcmp(tokens[1], "subport") || 3570 softnic_parser_read_uint32(&subport_id, tokens[2]) || 3571 strcmp(tokens[3], "pipe") || 3572 softnic_parser_read_uint32(&pipe_id, tokens[4])) 3573 return 0; 3574 3575 a->tm.subport_id = subport_id; 3576 a->tm.pipe_id = pipe_id; 3577 a->action_mask |= 1 << RTE_TABLE_ACTION_TM; 3578 return 5; 3579 } 3580 3581 static uint32_t 3582 parse_table_action_encap(char **tokens, 3583 uint32_t n_tokens, 3584 struct softnic_table_rule_action *a) 3585 { 3586 if (n_tokens == 0 || 3587 strcmp(tokens[0], "encap")) 3588 return 0; 3589 3590 tokens++; 3591 n_tokens--; 3592 3593 /* ether */ 3594 if (n_tokens && (strcmp(tokens[0], "ether") == 0)) { 3595 if (n_tokens < 3 || 3596 softnic_parse_mac_addr(tokens[1], &a->encap.ether.ether.da) || 3597 softnic_parse_mac_addr(tokens[2], &a->encap.ether.ether.sa)) 3598 return 0; 3599 3600 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER; 3601 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3602 return 1 + 3; 3603 } 3604 3605 /* vlan */ 3606 if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) { 3607 uint32_t pcp, dei, vid; 3608 3609 if (n_tokens < 6 || 3610 softnic_parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) || 3611 softnic_parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) || 3612 softnic_parser_read_uint32(&pcp, tokens[3]) || 3613 pcp > 0x7 || 3614 softnic_parser_read_uint32(&dei, tokens[4]) || 3615 dei > 0x1 || 3616 softnic_parser_read_uint32(&vid, tokens[5]) || 3617 vid > 0xFFF) 3618 return 0; 3619 3620 a->encap.vlan.vlan.pcp = pcp & 0x7; 3621 a->encap.vlan.vlan.dei = dei & 0x1; 3622 a->encap.vlan.vlan.vid = vid & 0xFFF; 3623 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN; 3624 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3625 return 1 + 6; 3626 } 3627 3628 /* qinq */ 3629 if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) { 3630 uint32_t svlan_pcp, svlan_dei, svlan_vid; 3631 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid; 3632 3633 if (n_tokens < 9 || 3634 softnic_parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) || 3635 softnic_parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) || 3636 softnic_parser_read_uint32(&svlan_pcp, tokens[3]) || 3637 svlan_pcp > 0x7 || 3638 softnic_parser_read_uint32(&svlan_dei, tokens[4]) || 3639 svlan_dei > 0x1 || 3640 softnic_parser_read_uint32(&svlan_vid, tokens[5]) || 3641 svlan_vid > 0xFFF || 3642 softnic_parser_read_uint32(&cvlan_pcp, tokens[6]) || 3643 cvlan_pcp > 0x7 || 3644 softnic_parser_read_uint32(&cvlan_dei, tokens[7]) || 3645 cvlan_dei > 0x1 || 3646 softnic_parser_read_uint32(&cvlan_vid, tokens[8]) || 3647 cvlan_vid > 0xFFF) 3648 return 0; 3649 3650 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7; 3651 a->encap.qinq.svlan.dei = svlan_dei & 0x1; 3652 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF; 3653 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7; 3654 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1; 3655 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF; 3656 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ; 3657 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3658 return 1 + 9; 3659 } 3660 3661 /* mpls */ 3662 if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) { 3663 uint32_t label, tc, ttl; 3664 3665 if (n_tokens < 8) 3666 return 0; 3667 3668 if (strcmp(tokens[1], "unicast") == 0) 3669 a->encap.mpls.unicast = 1; 3670 else if (strcmp(tokens[1], "multicast") == 0) 3671 a->encap.mpls.unicast = 0; 3672 else 3673 return 0; 3674 3675 if (softnic_parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) || 3676 softnic_parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) || 3677 strcmp(tokens[4], "label0") || 3678 softnic_parser_read_uint32(&label, tokens[5]) || 3679 label > 0xFFFFF || 3680 softnic_parser_read_uint32(&tc, tokens[6]) || 3681 tc > 0x7 || 3682 softnic_parser_read_uint32(&ttl, tokens[7]) || 3683 ttl > 0x3F) 3684 return 0; 3685 3686 a->encap.mpls.mpls[0].label = label; 3687 a->encap.mpls.mpls[0].tc = tc; 3688 a->encap.mpls.mpls[0].ttl = ttl; 3689 3690 tokens += 8; 3691 n_tokens -= 8; 3692 3693 if (n_tokens == 0 || 3694 strcmp(tokens[0], "label1")) { 3695 a->encap.mpls.mpls_count = 1; 3696 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3697 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3698 return 1 + 8; 3699 } 3700 3701 if (n_tokens < 4 || 3702 softnic_parser_read_uint32(&label, tokens[1]) || 3703 label > 0xFFFFF || 3704 softnic_parser_read_uint32(&tc, tokens[2]) || 3705 tc > 0x7 || 3706 softnic_parser_read_uint32(&ttl, tokens[3]) || 3707 ttl > 0x3F) 3708 return 0; 3709 3710 a->encap.mpls.mpls[1].label = label; 3711 a->encap.mpls.mpls[1].tc = tc; 3712 a->encap.mpls.mpls[1].ttl = ttl; 3713 3714 tokens += 4; 3715 n_tokens -= 4; 3716 3717 if (n_tokens == 0 || 3718 strcmp(tokens[0], "label2")) { 3719 a->encap.mpls.mpls_count = 2; 3720 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3721 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3722 return 1 + 8 + 4; 3723 } 3724 3725 if (n_tokens < 4 || 3726 softnic_parser_read_uint32(&label, tokens[1]) || 3727 label > 0xFFFFF || 3728 softnic_parser_read_uint32(&tc, tokens[2]) || 3729 tc > 0x7 || 3730 softnic_parser_read_uint32(&ttl, tokens[3]) || 3731 ttl > 0x3F) 3732 return 0; 3733 3734 a->encap.mpls.mpls[2].label = label; 3735 a->encap.mpls.mpls[2].tc = tc; 3736 a->encap.mpls.mpls[2].ttl = ttl; 3737 3738 tokens += 4; 3739 n_tokens -= 4; 3740 3741 if (n_tokens == 0 || 3742 strcmp(tokens[0], "label3")) { 3743 a->encap.mpls.mpls_count = 3; 3744 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3745 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3746 return 1 + 8 + 4 + 4; 3747 } 3748 3749 if (n_tokens < 4 || 3750 softnic_parser_read_uint32(&label, tokens[1]) || 3751 label > 0xFFFFF || 3752 softnic_parser_read_uint32(&tc, tokens[2]) || 3753 tc > 0x7 || 3754 softnic_parser_read_uint32(&ttl, tokens[3]) || 3755 ttl > 0x3F) 3756 return 0; 3757 3758 a->encap.mpls.mpls[3].label = label; 3759 a->encap.mpls.mpls[3].tc = tc; 3760 a->encap.mpls.mpls[3].ttl = ttl; 3761 3762 a->encap.mpls.mpls_count = 4; 3763 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3764 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3765 return 1 + 8 + 4 + 4 + 4; 3766 } 3767 3768 /* pppoe */ 3769 if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) { 3770 if (n_tokens < 4 || 3771 softnic_parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) || 3772 softnic_parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) || 3773 softnic_parser_read_uint16(&a->encap.pppoe.pppoe.session_id, 3774 tokens[3])) 3775 return 0; 3776 3777 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE; 3778 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3779 return 1 + 4; 3780 } 3781 3782 /* vxlan */ 3783 if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) { 3784 uint32_t n = 0; 3785 3786 n_tokens--; 3787 tokens++; 3788 n++; 3789 3790 /* ether <da> <sa> */ 3791 if ((n_tokens < 3) || 3792 strcmp(tokens[0], "ether") || 3793 softnic_parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) || 3794 softnic_parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa)) 3795 return 0; 3796 3797 n_tokens -= 3; 3798 tokens += 3; 3799 n += 3; 3800 3801 /* [vlan <pcp> <dei> <vid>] */ 3802 if (strcmp(tokens[0], "vlan") == 0) { 3803 uint32_t pcp, dei, vid; 3804 3805 if ((n_tokens < 4) || 3806 softnic_parser_read_uint32(&pcp, tokens[1]) || 3807 (pcp > 7) || 3808 softnic_parser_read_uint32(&dei, tokens[2]) || 3809 (dei > 1) || 3810 softnic_parser_read_uint32(&vid, tokens[3]) || 3811 (vid > 0xFFF)) 3812 return 0; 3813 3814 a->encap.vxlan.vlan.pcp = pcp; 3815 a->encap.vxlan.vlan.dei = dei; 3816 a->encap.vxlan.vlan.vid = vid; 3817 3818 n_tokens -= 4; 3819 tokens += 4; 3820 n += 4; 3821 } 3822 3823 /* ipv4 <sa> <da> <dscp> <ttl> 3824 | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */ 3825 if (strcmp(tokens[0], "ipv4") == 0) { 3826 struct in_addr sa, da; 3827 uint8_t dscp, ttl; 3828 3829 if ((n_tokens < 5) || 3830 softnic_parse_ipv4_addr(tokens[1], &sa) || 3831 softnic_parse_ipv4_addr(tokens[2], &da) || 3832 softnic_parser_read_uint8(&dscp, tokens[3]) || 3833 (dscp > 64) || 3834 softnic_parser_read_uint8(&ttl, tokens[4])) 3835 return 0; 3836 3837 a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr); 3838 a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr); 3839 a->encap.vxlan.ipv4.dscp = dscp; 3840 a->encap.vxlan.ipv4.ttl = ttl; 3841 3842 n_tokens -= 5; 3843 tokens += 5; 3844 n += 5; 3845 } else if (strcmp(tokens[0], "ipv6") == 0) { 3846 struct in6_addr sa, da; 3847 uint32_t flow_label; 3848 uint8_t dscp, hop_limit; 3849 3850 if ((n_tokens < 6) || 3851 softnic_parse_ipv6_addr(tokens[1], &sa) || 3852 softnic_parse_ipv6_addr(tokens[2], &da) || 3853 softnic_parser_read_uint32(&flow_label, tokens[3]) || 3854 softnic_parser_read_uint8(&dscp, tokens[4]) || 3855 (dscp > 64) || 3856 softnic_parser_read_uint8(&hop_limit, tokens[5])) 3857 return 0; 3858 3859 memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16); 3860 memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16); 3861 a->encap.vxlan.ipv6.flow_label = flow_label; 3862 a->encap.vxlan.ipv6.dscp = dscp; 3863 a->encap.vxlan.ipv6.hop_limit = hop_limit; 3864 3865 n_tokens -= 6; 3866 tokens += 6; 3867 n += 6; 3868 } else 3869 return 0; 3870 3871 /* udp <sp> <dp> */ 3872 if ((n_tokens < 3) || 3873 strcmp(tokens[0], "udp") || 3874 softnic_parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) || 3875 softnic_parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2])) 3876 return 0; 3877 3878 n_tokens -= 3; 3879 tokens += 3; 3880 n += 3; 3881 3882 /* vxlan <vni> */ 3883 if ((n_tokens < 2) || 3884 strcmp(tokens[0], "vxlan") || 3885 softnic_parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) || 3886 (a->encap.vxlan.vxlan.vni > 0xFFFFFF)) 3887 return 0; 3888 3889 n_tokens -= 2; 3890 tokens += 2; 3891 n += 2; 3892 3893 a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN; 3894 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3895 return 1 + n; 3896 } 3897 3898 return 0; 3899 } 3900 3901 static uint32_t 3902 parse_table_action_nat(char **tokens, 3903 uint32_t n_tokens, 3904 struct softnic_table_rule_action *a) 3905 { 3906 if (n_tokens < 4 || 3907 strcmp(tokens[0], "nat")) 3908 return 0; 3909 3910 if (strcmp(tokens[1], "ipv4") == 0) { 3911 struct in_addr addr; 3912 uint16_t port; 3913 3914 if (softnic_parse_ipv4_addr(tokens[2], &addr) || 3915 softnic_parser_read_uint16(&port, tokens[3])) 3916 return 0; 3917 3918 a->nat.ip_version = 1; 3919 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr); 3920 a->nat.port = port; 3921 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3922 return 4; 3923 } 3924 3925 if (strcmp(tokens[1], "ipv6") == 0) { 3926 struct in6_addr addr; 3927 uint16_t port; 3928 3929 if (softnic_parse_ipv6_addr(tokens[2], &addr) || 3930 softnic_parser_read_uint16(&port, tokens[3])) 3931 return 0; 3932 3933 a->nat.ip_version = 0; 3934 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16); 3935 a->nat.port = port; 3936 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3937 return 4; 3938 } 3939 3940 return 0; 3941 } 3942 3943 static uint32_t 3944 parse_table_action_ttl(char **tokens, 3945 uint32_t n_tokens, 3946 struct softnic_table_rule_action *a) 3947 { 3948 if (n_tokens < 2 || 3949 strcmp(tokens[0], "ttl")) 3950 return 0; 3951 3952 if (strcmp(tokens[1], "dec") == 0) 3953 a->ttl.decrement = 1; 3954 else if (strcmp(tokens[1], "keep") == 0) 3955 a->ttl.decrement = 0; 3956 else 3957 return 0; 3958 3959 a->action_mask |= 1 << RTE_TABLE_ACTION_TTL; 3960 return 2; 3961 } 3962 3963 static uint32_t 3964 parse_table_action_stats(char **tokens, 3965 uint32_t n_tokens, 3966 struct softnic_table_rule_action *a) 3967 { 3968 if (n_tokens < 1 || 3969 strcmp(tokens[0], "stats")) 3970 return 0; 3971 3972 a->stats.n_packets = 0; 3973 a->stats.n_bytes = 0; 3974 a->action_mask |= 1 << RTE_TABLE_ACTION_STATS; 3975 return 1; 3976 } 3977 3978 static uint32_t 3979 parse_table_action_time(char **tokens, 3980 uint32_t n_tokens, 3981 struct softnic_table_rule_action *a) 3982 { 3983 if (n_tokens < 1 || 3984 strcmp(tokens[0], "time")) 3985 return 0; 3986 3987 a->time.time = rte_rdtsc(); 3988 a->action_mask |= 1 << RTE_TABLE_ACTION_TIME; 3989 return 1; 3990 } 3991 3992 static void 3993 parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p) 3994 { 3995 struct rte_crypto_sym_xform *xform[2] = {NULL}; 3996 uint32_t i; 3997 3998 xform[0] = p->xform; 3999 if (xform[0]) 4000 xform[1] = xform[0]->next; 4001 4002 for (i = 0; i < 2; i++) { 4003 if (xform[i] == NULL) 4004 continue; 4005 4006 switch (xform[i]->type) { 4007 case RTE_CRYPTO_SYM_XFORM_CIPHER: 4008 if (xform[i]->cipher.key.data) 4009 free(xform[i]->cipher.key.data); 4010 if (p->cipher_auth.cipher_iv.val) 4011 free(p->cipher_auth.cipher_iv.val); 4012 if (p->cipher_auth.cipher_iv_update.val) 4013 free(p->cipher_auth.cipher_iv_update.val); 4014 break; 4015 case RTE_CRYPTO_SYM_XFORM_AUTH: 4016 if (xform[i]->auth.key.data) 4017 free(xform[i]->cipher.key.data); 4018 if (p->cipher_auth.auth_iv.val) 4019 free(p->cipher_auth.cipher_iv.val); 4020 if (p->cipher_auth.auth_iv_update.val) 4021 free(p->cipher_auth.cipher_iv_update.val); 4022 break; 4023 case RTE_CRYPTO_SYM_XFORM_AEAD: 4024 if (xform[i]->aead.key.data) 4025 free(xform[i]->cipher.key.data); 4026 if (p->aead.iv.val) 4027 free(p->aead.iv.val); 4028 if (p->aead.aad.val) 4029 free(p->aead.aad.val); 4030 break; 4031 default: 4032 continue; 4033 } 4034 } 4035 4036 } 4037 4038 static struct rte_crypto_sym_xform * 4039 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p, 4040 char **tokens, uint32_t n_tokens, uint32_t encrypt, 4041 uint32_t *used_n_tokens) 4042 { 4043 struct rte_crypto_sym_xform *xform_cipher; 4044 int status; 4045 size_t len; 4046 4047 if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") || 4048 strcmp(tokens[3], "cipher_key") || 4049 strcmp(tokens[5], "cipher_iv")) 4050 return NULL; 4051 4052 xform_cipher = calloc(1, sizeof(*xform_cipher)); 4053 if (xform_cipher == NULL) 4054 return NULL; 4055 4056 xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER; 4057 xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT : 4058 RTE_CRYPTO_CIPHER_OP_DECRYPT; 4059 4060 /* cipher_algo */ 4061 status = rte_cryptodev_get_cipher_algo_enum( 4062 &xform_cipher->cipher.algo, tokens[2]); 4063 if (status < 0) 4064 goto error_exit; 4065 4066 /* cipher_key */ 4067 len = strlen(tokens[4]); 4068 xform_cipher->cipher.key.data = calloc(1, len / 2 + 1); 4069 if (xform_cipher->cipher.key.data == NULL) 4070 goto error_exit; 4071 4072 status = softnic_parse_hex_string(tokens[4], 4073 xform_cipher->cipher.key.data, 4074 (uint32_t *)&len); 4075 if (status < 0) 4076 goto error_exit; 4077 4078 xform_cipher->cipher.key.length = (uint16_t)len; 4079 4080 /* cipher_iv */ 4081 len = strlen(tokens[6]); 4082 4083 p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1); 4084 if (p->cipher_auth.cipher_iv.val == NULL) 4085 goto error_exit; 4086 4087 status = softnic_parse_hex_string(tokens[6], 4088 p->cipher_auth.cipher_iv.val, 4089 (uint32_t *)&len); 4090 if (status < 0) 4091 goto error_exit; 4092 4093 xform_cipher->cipher.iv.length = (uint16_t)len; 4094 xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET; 4095 p->cipher_auth.cipher_iv.length = (uint32_t)len; 4096 *used_n_tokens = 7; 4097 4098 return xform_cipher; 4099 4100 error_exit: 4101 if (xform_cipher->cipher.key.data) 4102 free(xform_cipher->cipher.key.data); 4103 4104 if (p->cipher_auth.cipher_iv.val) { 4105 free(p->cipher_auth.cipher_iv.val); 4106 p->cipher_auth.cipher_iv.val = NULL; 4107 } 4108 4109 free(xform_cipher); 4110 4111 return NULL; 4112 } 4113 4114 static struct rte_crypto_sym_xform * 4115 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p, 4116 char **tokens, uint32_t n_tokens, uint32_t encrypt, 4117 uint32_t *used_n_tokens) 4118 { 4119 struct rte_crypto_sym_xform *xform_cipher; 4120 struct rte_crypto_sym_xform *xform_auth; 4121 int status; 4122 size_t len; 4123 4124 if (n_tokens < 13 || 4125 strcmp(tokens[7], "auth_algo") || 4126 strcmp(tokens[9], "auth_key") || 4127 strcmp(tokens[11], "digest_size")) 4128 return NULL; 4129 4130 xform_auth = calloc(1, sizeof(*xform_auth)); 4131 if (xform_auth == NULL) 4132 return NULL; 4133 4134 xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH; 4135 xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE : 4136 RTE_CRYPTO_AUTH_OP_VERIFY; 4137 4138 /* auth_algo */ 4139 status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo, 4140 tokens[8]); 4141 if (status < 0) 4142 goto error_exit; 4143 4144 /* auth_key */ 4145 len = strlen(tokens[10]); 4146 xform_auth->auth.key.data = calloc(1, len / 2 + 1); 4147 if (xform_auth->auth.key.data == NULL) 4148 goto error_exit; 4149 4150 status = softnic_parse_hex_string(tokens[10], 4151 xform_auth->auth.key.data, (uint32_t *)&len); 4152 if (status < 0) 4153 goto error_exit; 4154 4155 xform_auth->auth.key.length = (uint16_t)len; 4156 4157 if (strcmp(tokens[11], "digest_size")) 4158 goto error_exit; 4159 4160 status = softnic_parser_read_uint16(&xform_auth->auth.digest_length, 4161 tokens[12]); 4162 if (status < 0) 4163 goto error_exit; 4164 4165 xform_cipher = parse_table_action_cipher(p, tokens, 7, encrypt, 4166 used_n_tokens); 4167 if (xform_cipher == NULL) 4168 goto error_exit; 4169 4170 *used_n_tokens += 6; 4171 4172 if (encrypt) { 4173 xform_cipher->next = xform_auth; 4174 return xform_cipher; 4175 } else { 4176 xform_auth->next = xform_cipher; 4177 return xform_auth; 4178 } 4179 4180 error_exit: 4181 if (xform_auth->auth.key.data) 4182 free(xform_auth->auth.key.data); 4183 if (p->cipher_auth.auth_iv.val) { 4184 free(p->cipher_auth.auth_iv.val); 4185 p->cipher_auth.auth_iv.val = 0; 4186 } 4187 4188 free(xform_auth); 4189 4190 return NULL; 4191 } 4192 4193 static struct rte_crypto_sym_xform * 4194 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p, 4195 char **tokens, uint32_t n_tokens, uint32_t encrypt, 4196 uint32_t *used_n_tokens) 4197 { 4198 struct rte_crypto_sym_xform *xform_aead; 4199 int status; 4200 size_t len; 4201 4202 if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") || 4203 strcmp(tokens[3], "aead_key") || 4204 strcmp(tokens[5], "aead_iv") || 4205 strcmp(tokens[7], "aead_aad") || 4206 strcmp(tokens[9], "digest_size")) 4207 return NULL; 4208 4209 xform_aead = calloc(1, sizeof(*xform_aead)); 4210 if (xform_aead == NULL) 4211 return NULL; 4212 4213 xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD; 4214 xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT : 4215 RTE_CRYPTO_AEAD_OP_DECRYPT; 4216 4217 /* aead_algo */ 4218 status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo, 4219 tokens[2]); 4220 if (status < 0) 4221 goto error_exit; 4222 4223 /* aead_key */ 4224 len = strlen(tokens[4]); 4225 xform_aead->aead.key.data = calloc(1, len / 2 + 1); 4226 if (xform_aead->aead.key.data == NULL) 4227 goto error_exit; 4228 4229 status = softnic_parse_hex_string(tokens[4], xform_aead->aead.key.data, 4230 (uint32_t *)&len); 4231 if (status < 0) 4232 goto error_exit; 4233 4234 xform_aead->aead.key.length = (uint16_t)len; 4235 4236 /* aead_iv */ 4237 len = strlen(tokens[6]); 4238 p->aead.iv.val = calloc(1, len / 2 + 1); 4239 if (p->aead.iv.val == NULL) 4240 goto error_exit; 4241 4242 status = softnic_parse_hex_string(tokens[6], p->aead.iv.val, 4243 (uint32_t *)&len); 4244 if (status < 0) 4245 goto error_exit; 4246 4247 xform_aead->aead.iv.length = (uint16_t)len; 4248 xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET; 4249 p->aead.iv.length = (uint32_t)len; 4250 4251 /* aead_aad */ 4252 len = strlen(tokens[8]); 4253 p->aead.aad.val = calloc(1, len / 2 + 1); 4254 if (p->aead.aad.val == NULL) 4255 goto error_exit; 4256 4257 status = softnic_parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len); 4258 if (status < 0) 4259 goto error_exit; 4260 4261 xform_aead->aead.aad_length = (uint16_t)len; 4262 p->aead.aad.length = (uint32_t)len; 4263 4264 /* digest_size */ 4265 status = softnic_parser_read_uint16(&xform_aead->aead.digest_length, 4266 tokens[10]); 4267 if (status < 0) 4268 goto error_exit; 4269 4270 *used_n_tokens = 11; 4271 4272 return xform_aead; 4273 4274 error_exit: 4275 if (xform_aead->aead.key.data) 4276 free(xform_aead->aead.key.data); 4277 if (p->aead.iv.val) { 4278 free(p->aead.iv.val); 4279 p->aead.iv.val = NULL; 4280 } 4281 if (p->aead.aad.val) { 4282 free(p->aead.aad.val); 4283 p->aead.aad.val = NULL; 4284 } 4285 4286 free(xform_aead); 4287 4288 return NULL; 4289 } 4290 4291 4292 static uint32_t 4293 parse_table_action_sym_crypto(char **tokens, 4294 uint32_t n_tokens, 4295 struct softnic_table_rule_action *a) 4296 { 4297 struct rte_table_action_sym_crypto_params *p = &a->sym_crypto; 4298 struct rte_crypto_sym_xform *xform = NULL; 4299 uint32_t used_n_tokens; 4300 uint32_t encrypt; 4301 int status; 4302 4303 if ((n_tokens < 12) || 4304 strcmp(tokens[0], "sym_crypto") || 4305 strcmp(tokens[2], "type")) 4306 return 0; 4307 4308 memset(p, 0, sizeof(*p)); 4309 4310 if (strcmp(tokens[1], "encrypt") == 0) 4311 encrypt = 1; 4312 else 4313 encrypt = 0; 4314 4315 status = softnic_parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]); 4316 if (status < 0) 4317 return 0; 4318 4319 if (strcmp(tokens[3], "cipher") == 0) { 4320 tokens += 3; 4321 n_tokens -= 3; 4322 4323 xform = parse_table_action_cipher(p, tokens, n_tokens, encrypt, 4324 &used_n_tokens); 4325 } else if (strcmp(tokens[3], "cipher_auth") == 0) { 4326 tokens += 3; 4327 n_tokens -= 3; 4328 4329 xform = parse_table_action_cipher_auth(p, tokens, n_tokens, 4330 encrypt, &used_n_tokens); 4331 } else if (strcmp(tokens[3], "aead") == 0) { 4332 tokens += 3; 4333 n_tokens -= 3; 4334 4335 xform = parse_table_action_aead(p, tokens, n_tokens, encrypt, 4336 &used_n_tokens); 4337 } 4338 4339 if (xform == NULL) 4340 return 0; 4341 4342 p->xform = xform; 4343 4344 if (strcmp(tokens[used_n_tokens], "data_offset")) { 4345 parse_free_sym_crypto_param_data(p); 4346 return 0; 4347 } 4348 4349 a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO; 4350 4351 return used_n_tokens + 5; 4352 } 4353 4354 static uint32_t 4355 parse_table_action_tag(char **tokens, 4356 uint32_t n_tokens, 4357 struct softnic_table_rule_action *a) 4358 { 4359 if (n_tokens < 2 || 4360 strcmp(tokens[0], "tag")) 4361 return 0; 4362 4363 if (softnic_parser_read_uint32(&a->tag.tag, tokens[1])) 4364 return 0; 4365 4366 a->action_mask |= 1 << RTE_TABLE_ACTION_TAG; 4367 return 2; 4368 } 4369 4370 static uint32_t 4371 parse_table_action_decap(char **tokens, 4372 uint32_t n_tokens, 4373 struct softnic_table_rule_action *a) 4374 { 4375 if (n_tokens < 2 || 4376 strcmp(tokens[0], "decap")) 4377 return 0; 4378 4379 if (softnic_parser_read_uint16(&a->decap.n, tokens[1])) 4380 return 0; 4381 4382 a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP; 4383 return 2; 4384 } 4385 4386 static uint32_t 4387 parse_table_action(char **tokens, 4388 uint32_t n_tokens, 4389 char *out, 4390 size_t out_size, 4391 struct softnic_table_rule_action *a) 4392 { 4393 uint32_t n_tokens0 = n_tokens; 4394 4395 memset(a, 0, sizeof(*a)); 4396 4397 if (n_tokens < 2 || 4398 strcmp(tokens[0], "action")) 4399 return 0; 4400 4401 tokens++; 4402 n_tokens--; 4403 4404 if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) { 4405 uint32_t n; 4406 4407 n = parse_table_action_fwd(tokens, n_tokens, a); 4408 if (n == 0) { 4409 snprintf(out, out_size, MSG_ARG_INVALID, 4410 "action fwd"); 4411 return 0; 4412 } 4413 4414 tokens += n; 4415 n_tokens -= n; 4416 } 4417 4418 if (n_tokens && (strcmp(tokens[0], "balance") == 0)) { 4419 uint32_t n; 4420 4421 n = parse_table_action_balance(tokens, n_tokens, a); 4422 if (n == 0) { 4423 snprintf(out, out_size, MSG_ARG_INVALID, 4424 "action balance"); 4425 return 0; 4426 } 4427 4428 tokens += n; 4429 n_tokens -= n; 4430 } 4431 4432 if (n_tokens && (strcmp(tokens[0], "meter") == 0)) { 4433 uint32_t n; 4434 4435 n = parse_table_action_meter(tokens, n_tokens, a); 4436 if (n == 0) { 4437 snprintf(out, out_size, MSG_ARG_INVALID, 4438 "action meter"); 4439 return 0; 4440 } 4441 4442 tokens += n; 4443 n_tokens -= n; 4444 } 4445 4446 if (n_tokens && (strcmp(tokens[0], "tm") == 0)) { 4447 uint32_t n; 4448 4449 n = parse_table_action_tm(tokens, n_tokens, a); 4450 if (n == 0) { 4451 snprintf(out, out_size, MSG_ARG_INVALID, 4452 "action tm"); 4453 return 0; 4454 } 4455 4456 tokens += n; 4457 n_tokens -= n; 4458 } 4459 4460 if (n_tokens && (strcmp(tokens[0], "encap") == 0)) { 4461 uint32_t n; 4462 4463 n = parse_table_action_encap(tokens, n_tokens, a); 4464 if (n == 0) { 4465 snprintf(out, out_size, MSG_ARG_INVALID, 4466 "action encap"); 4467 return 0; 4468 } 4469 4470 tokens += n; 4471 n_tokens -= n; 4472 } 4473 4474 if (n_tokens && (strcmp(tokens[0], "nat") == 0)) { 4475 uint32_t n; 4476 4477 n = parse_table_action_nat(tokens, n_tokens, a); 4478 if (n == 0) { 4479 snprintf(out, out_size, MSG_ARG_INVALID, 4480 "action nat"); 4481 return 0; 4482 } 4483 4484 tokens += n; 4485 n_tokens -= n; 4486 } 4487 4488 if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) { 4489 uint32_t n; 4490 4491 n = parse_table_action_ttl(tokens, n_tokens, a); 4492 if (n == 0) { 4493 snprintf(out, out_size, MSG_ARG_INVALID, 4494 "action ttl"); 4495 return 0; 4496 } 4497 4498 tokens += n; 4499 n_tokens -= n; 4500 } 4501 4502 if (n_tokens && (strcmp(tokens[0], "stats") == 0)) { 4503 uint32_t n; 4504 4505 n = parse_table_action_stats(tokens, n_tokens, a); 4506 if (n == 0) { 4507 snprintf(out, out_size, MSG_ARG_INVALID, 4508 "action stats"); 4509 return 0; 4510 } 4511 4512 tokens += n; 4513 n_tokens -= n; 4514 } 4515 4516 if (n_tokens && (strcmp(tokens[0], "time") == 0)) { 4517 uint32_t n; 4518 4519 n = parse_table_action_time(tokens, n_tokens, a); 4520 if (n == 0) { 4521 snprintf(out, out_size, MSG_ARG_INVALID, 4522 "action time"); 4523 return 0; 4524 } 4525 4526 tokens += n; 4527 n_tokens -= n; 4528 } 4529 4530 if (n_tokens && (strcmp(tokens[0], "tag") == 0)) { 4531 uint32_t n; 4532 4533 n = parse_table_action_tag(tokens, n_tokens, a); 4534 if (n == 0) { 4535 snprintf(out, out_size, MSG_ARG_INVALID, 4536 "action tag"); 4537 return 0; 4538 } 4539 4540 tokens += n; 4541 n_tokens -= n; 4542 } 4543 4544 if (n_tokens && (strcmp(tokens[0], "decap") == 0)) { 4545 uint32_t n; 4546 4547 n = parse_table_action_decap(tokens, n_tokens, a); 4548 if (n == 0) { 4549 snprintf(out, out_size, MSG_ARG_INVALID, 4550 "action decap"); 4551 return 0; 4552 } 4553 4554 tokens += n; 4555 n_tokens -= n; 4556 } 4557 4558 if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) { 4559 uint32_t n; 4560 4561 n = parse_table_action_sym_crypto(tokens, n_tokens, a); 4562 if (n == 0) { 4563 snprintf(out, out_size, MSG_ARG_INVALID, 4564 "action sym_crypto"); 4565 } 4566 4567 tokens += n; 4568 n_tokens -= n; 4569 } 4570 4571 if (n_tokens0 - n_tokens == 1) { 4572 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 4573 return 0; 4574 } 4575 4576 return n_tokens0 - n_tokens; 4577 } 4578 4579 /** 4580 * pipeline <pipeline_name> table <table_id> rule add 4581 * match <match> 4582 * action <table_action> 4583 */ 4584 static void 4585 cmd_softnic_pipeline_table_rule_add(struct pmd_internals *softnic, 4586 char **tokens, 4587 uint32_t n_tokens, 4588 char *out, 4589 size_t out_size) 4590 { 4591 struct softnic_table_rule_match m; 4592 struct softnic_table_rule_action a; 4593 char *pipeline_name; 4594 void *data; 4595 uint32_t table_id, t0, n_tokens_parsed; 4596 int status; 4597 4598 if (n_tokens < 8) { 4599 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4600 return; 4601 } 4602 4603 pipeline_name = tokens[1]; 4604 4605 if (strcmp(tokens[2], "table") != 0) { 4606 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4607 return; 4608 } 4609 4610 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4611 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4612 return; 4613 } 4614 4615 if (strcmp(tokens[4], "rule") != 0) { 4616 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4617 return; 4618 } 4619 4620 if (strcmp(tokens[5], "add") != 0) { 4621 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4622 return; 4623 } 4624 4625 t0 = 6; 4626 4627 /* match */ 4628 n_tokens_parsed = parse_match(tokens + t0, 4629 n_tokens - t0, 4630 out, 4631 out_size, 4632 &m); 4633 if (n_tokens_parsed == 0) 4634 return; 4635 t0 += n_tokens_parsed; 4636 4637 /* action */ 4638 n_tokens_parsed = parse_table_action(tokens + t0, 4639 n_tokens - t0, 4640 out, 4641 out_size, 4642 &a); 4643 if (n_tokens_parsed == 0) 4644 return; 4645 t0 += n_tokens_parsed; 4646 4647 if (t0 != n_tokens) { 4648 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 4649 return; 4650 } 4651 4652 status = softnic_pipeline_table_rule_add(softnic, 4653 pipeline_name, 4654 table_id, 4655 &m, 4656 &a, 4657 &data); 4658 if (status) { 4659 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4660 return; 4661 } 4662 } 4663 4664 /** 4665 * pipeline <pipeline_name> table <table_id> rule add 4666 * match 4667 * default 4668 * action 4669 * fwd 4670 * drop 4671 * | port <port_id> 4672 * | meta 4673 * | table <table_id> 4674 */ 4675 static void 4676 cmd_softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic, 4677 char **tokens, 4678 uint32_t n_tokens, 4679 char *out, 4680 size_t out_size) 4681 { 4682 struct softnic_table_rule_action action; 4683 void *data; 4684 char *pipeline_name; 4685 uint32_t table_id; 4686 int status; 4687 4688 if (n_tokens != 11 && 4689 n_tokens != 12) { 4690 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4691 return; 4692 } 4693 4694 pipeline_name = tokens[1]; 4695 4696 if (strcmp(tokens[2], "table") != 0) { 4697 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4698 return; 4699 } 4700 4701 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4702 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4703 return; 4704 } 4705 4706 if (strcmp(tokens[4], "rule") != 0) { 4707 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4708 return; 4709 } 4710 4711 if (strcmp(tokens[5], "add") != 0) { 4712 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4713 return; 4714 } 4715 4716 if (strcmp(tokens[6], "match") != 0) { 4717 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 4718 return; 4719 } 4720 4721 if (strcmp(tokens[7], "default") != 0) { 4722 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 4723 return; 4724 } 4725 4726 if (strcmp(tokens[8], "action") != 0) { 4727 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 4728 return; 4729 } 4730 4731 if (strcmp(tokens[9], "fwd") != 0) { 4732 snprintf(out, out_size, MSG_ARG_INVALID, "fwd"); 4733 return; 4734 } 4735 4736 action.action_mask = 1 << RTE_TABLE_ACTION_FWD; 4737 4738 if (strcmp(tokens[10], "drop") == 0) { 4739 if (n_tokens != 11) { 4740 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4741 return; 4742 } 4743 4744 action.fwd.action = RTE_PIPELINE_ACTION_DROP; 4745 } else if (strcmp(tokens[10], "port") == 0) { 4746 uint32_t id; 4747 4748 if (n_tokens != 12) { 4749 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4750 return; 4751 } 4752 4753 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) { 4754 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 4755 return; 4756 } 4757 4758 action.fwd.action = RTE_PIPELINE_ACTION_PORT; 4759 action.fwd.id = id; 4760 } else if (strcmp(tokens[10], "meta") == 0) { 4761 if (n_tokens != 11) { 4762 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4763 return; 4764 } 4765 4766 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META; 4767 } else if (strcmp(tokens[10], "table") == 0) { 4768 uint32_t id; 4769 4770 if (n_tokens != 12) { 4771 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4772 return; 4773 } 4774 4775 if (softnic_parser_read_uint32(&id, tokens[11]) != 0) { 4776 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4777 return; 4778 } 4779 4780 action.fwd.action = RTE_PIPELINE_ACTION_TABLE; 4781 action.fwd.id = id; 4782 } else { 4783 snprintf(out, out_size, MSG_ARG_INVALID, 4784 "drop or port or meta or table"); 4785 return; 4786 } 4787 4788 status = softnic_pipeline_table_rule_add_default(softnic, 4789 pipeline_name, 4790 table_id, 4791 &action, 4792 &data); 4793 if (status) { 4794 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4795 return; 4796 } 4797 } 4798 4799 /** 4800 * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules> 4801 * 4802 * File <file_name>: 4803 * - line format: match <match> action <action> 4804 */ 4805 static int 4806 cli_rule_file_process(const char *file_name, 4807 size_t line_len_max, 4808 struct softnic_table_rule_match *m, 4809 struct softnic_table_rule_action *a, 4810 uint32_t *n_rules, 4811 uint32_t *line_number, 4812 char *out, 4813 size_t out_size); 4814 4815 static void 4816 cmd_softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic, 4817 char **tokens, 4818 uint32_t n_tokens, 4819 char *out, 4820 size_t out_size) 4821 { 4822 struct softnic_table_rule_match *match; 4823 struct softnic_table_rule_action *action; 4824 void **data; 4825 char *pipeline_name, *file_name; 4826 uint32_t table_id, n_rules, n_rules_parsed, line_number; 4827 int status; 4828 4829 if (n_tokens != 9) { 4830 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4831 return; 4832 } 4833 4834 pipeline_name = tokens[1]; 4835 4836 if (strcmp(tokens[2], "table") != 0) { 4837 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4838 return; 4839 } 4840 4841 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4842 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4843 return; 4844 } 4845 4846 if (strcmp(tokens[4], "rule") != 0) { 4847 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4848 return; 4849 } 4850 4851 if (strcmp(tokens[5], "add") != 0) { 4852 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4853 return; 4854 } 4855 4856 if (strcmp(tokens[6], "bulk") != 0) { 4857 snprintf(out, out_size, MSG_ARG_INVALID, "bulk"); 4858 return; 4859 } 4860 4861 file_name = tokens[7]; 4862 4863 if ((softnic_parser_read_uint32(&n_rules, tokens[8]) != 0) || 4864 n_rules == 0) { 4865 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 4866 return; 4867 } 4868 4869 /* Memory allocation. */ 4870 match = calloc(n_rules, sizeof(struct softnic_table_rule_match)); 4871 action = calloc(n_rules, sizeof(struct softnic_table_rule_action)); 4872 data = calloc(n_rules, sizeof(void *)); 4873 if (match == NULL || 4874 action == NULL || 4875 data == NULL) { 4876 snprintf(out, out_size, MSG_OUT_OF_MEMORY); 4877 free(data); 4878 free(action); 4879 free(match); 4880 return; 4881 } 4882 4883 /* Load rule file */ 4884 n_rules_parsed = n_rules; 4885 status = cli_rule_file_process(file_name, 4886 1024, 4887 match, 4888 action, 4889 &n_rules_parsed, 4890 &line_number, 4891 out, 4892 out_size); 4893 if (status) { 4894 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 4895 free(data); 4896 free(action); 4897 free(match); 4898 return; 4899 } 4900 if (n_rules_parsed != n_rules) { 4901 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name); 4902 free(data); 4903 free(action); 4904 free(match); 4905 return; 4906 } 4907 4908 /* Rule bulk add */ 4909 status = softnic_pipeline_table_rule_add_bulk(softnic, 4910 pipeline_name, 4911 table_id, 4912 match, 4913 action, 4914 data, 4915 &n_rules); 4916 if (status) { 4917 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4918 free(data); 4919 free(action); 4920 free(match); 4921 return; 4922 } 4923 4924 /* Memory free */ 4925 free(data); 4926 free(action); 4927 free(match); 4928 } 4929 4930 /** 4931 * pipeline <pipeline_name> table <table_id> rule delete 4932 * match <match> 4933 */ 4934 static void 4935 cmd_softnic_pipeline_table_rule_delete(struct pmd_internals *softnic, 4936 char **tokens, 4937 uint32_t n_tokens, 4938 char *out, 4939 size_t out_size) 4940 { 4941 struct softnic_table_rule_match m; 4942 char *pipeline_name; 4943 uint32_t table_id, n_tokens_parsed, t0; 4944 int status; 4945 4946 if (n_tokens < 8) { 4947 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4948 return; 4949 } 4950 4951 pipeline_name = tokens[1]; 4952 4953 if (strcmp(tokens[2], "table") != 0) { 4954 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4955 return; 4956 } 4957 4958 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 4959 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4960 return; 4961 } 4962 4963 if (strcmp(tokens[4], "rule") != 0) { 4964 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4965 return; 4966 } 4967 4968 if (strcmp(tokens[5], "delete") != 0) { 4969 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4970 return; 4971 } 4972 4973 t0 = 6; 4974 4975 /* match */ 4976 n_tokens_parsed = parse_match(tokens + t0, 4977 n_tokens - t0, 4978 out, 4979 out_size, 4980 &m); 4981 if (n_tokens_parsed == 0) 4982 return; 4983 t0 += n_tokens_parsed; 4984 4985 if (n_tokens != t0) { 4986 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4987 return; 4988 } 4989 4990 status = softnic_pipeline_table_rule_delete(softnic, 4991 pipeline_name, 4992 table_id, 4993 &m); 4994 if (status) { 4995 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4996 return; 4997 } 4998 } 4999 5000 /** 5001 * pipeline <pipeline_name> table <table_id> rule delete 5002 * match 5003 * default 5004 */ 5005 static void 5006 cmd_softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic, 5007 char **tokens, 5008 uint32_t n_tokens, 5009 char *out, 5010 size_t out_size) 5011 { 5012 char *pipeline_name; 5013 uint32_t table_id; 5014 int status; 5015 5016 if (n_tokens != 8) { 5017 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5018 return; 5019 } 5020 5021 pipeline_name = tokens[1]; 5022 5023 if (strcmp(tokens[2], "table") != 0) { 5024 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5025 return; 5026 } 5027 5028 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 5029 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5030 return; 5031 } 5032 5033 if (strcmp(tokens[4], "rule") != 0) { 5034 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5035 return; 5036 } 5037 5038 if (strcmp(tokens[5], "delete") != 0) { 5039 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 5040 return; 5041 } 5042 5043 if (strcmp(tokens[6], "match") != 0) { 5044 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 5045 return; 5046 } 5047 5048 if (strcmp(tokens[7], "default") != 0) { 5049 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 5050 return; 5051 } 5052 5053 status = softnic_pipeline_table_rule_delete_default(softnic, 5054 pipeline_name, 5055 table_id); 5056 if (status) { 5057 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5058 return; 5059 } 5060 } 5061 5062 /** 5063 * pipeline <pipeline_name> table <table_id> rule read stats [clear] 5064 */ 5065 static void 5066 cmd_softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic __rte_unused, 5067 char **tokens, 5068 uint32_t n_tokens __rte_unused, 5069 char *out, 5070 size_t out_size) 5071 { 5072 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 5073 } 5074 5075 /** 5076 * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id> 5077 * add srtcm cir <cir> cbs <cbs> ebs <ebs> 5078 * | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs> 5079 */ 5080 static void 5081 cmd_pipeline_table_meter_profile_add(struct pmd_internals *softnic, 5082 char **tokens, 5083 uint32_t n_tokens, 5084 char *out, 5085 size_t out_size) 5086 { 5087 struct rte_table_action_meter_profile p; 5088 char *pipeline_name; 5089 uint32_t table_id, meter_profile_id; 5090 int status; 5091 5092 if (n_tokens < 9) { 5093 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5094 return; 5095 } 5096 5097 pipeline_name = tokens[1]; 5098 5099 if (strcmp(tokens[2], "table") != 0) { 5100 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5101 return; 5102 } 5103 5104 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 5105 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5106 return; 5107 } 5108 5109 if (strcmp(tokens[4], "meter") != 0) { 5110 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5111 return; 5112 } 5113 5114 if (strcmp(tokens[5], "profile") != 0) { 5115 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 5116 return; 5117 } 5118 5119 if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 5120 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 5121 return; 5122 } 5123 5124 if (strcmp(tokens[7], "add") != 0) { 5125 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 5126 return; 5127 } 5128 5129 if (strcmp(tokens[8], "srtcm") == 0) { 5130 if (n_tokens != 15) { 5131 snprintf(out, out_size, MSG_ARG_MISMATCH, 5132 tokens[0]); 5133 return; 5134 } 5135 5136 p.alg = RTE_TABLE_ACTION_METER_SRTCM; 5137 5138 if (strcmp(tokens[9], "cir") != 0) { 5139 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 5140 return; 5141 } 5142 5143 if (softnic_parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) { 5144 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 5145 return; 5146 } 5147 5148 if (strcmp(tokens[11], "cbs") != 0) { 5149 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 5150 return; 5151 } 5152 5153 if (softnic_parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) { 5154 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 5155 return; 5156 } 5157 5158 if (strcmp(tokens[13], "ebs") != 0) { 5159 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs"); 5160 return; 5161 } 5162 5163 if (softnic_parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) { 5164 snprintf(out, out_size, MSG_ARG_INVALID, "ebs"); 5165 return; 5166 } 5167 } else if (strcmp(tokens[8], "trtcm") == 0) { 5168 if (n_tokens != 17) { 5169 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5170 return; 5171 } 5172 5173 p.alg = RTE_TABLE_ACTION_METER_TRTCM; 5174 5175 if (strcmp(tokens[9], "cir") != 0) { 5176 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 5177 return; 5178 } 5179 5180 if (softnic_parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) { 5181 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 5182 return; 5183 } 5184 5185 if (strcmp(tokens[11], "pir") != 0) { 5186 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 5187 return; 5188 } 5189 5190 if (softnic_parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) { 5191 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 5192 return; 5193 } 5194 if (strcmp(tokens[13], "cbs") != 0) { 5195 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 5196 return; 5197 } 5198 5199 if (softnic_parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) { 5200 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 5201 return; 5202 } 5203 5204 if (strcmp(tokens[15], "pbs") != 0) { 5205 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 5206 return; 5207 } 5208 5209 if (softnic_parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) { 5210 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 5211 return; 5212 } 5213 } else { 5214 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5215 return; 5216 } 5217 5218 status = softnic_pipeline_table_mtr_profile_add(softnic, 5219 pipeline_name, 5220 table_id, 5221 meter_profile_id, 5222 &p); 5223 if (status) { 5224 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5225 return; 5226 } 5227 } 5228 5229 /** 5230 * pipeline <pipeline_name> table <table_id> 5231 * meter profile <meter_profile_id> delete 5232 */ 5233 static void 5234 cmd_pipeline_table_meter_profile_delete(struct pmd_internals *softnic, 5235 char **tokens, 5236 uint32_t n_tokens, 5237 char *out, 5238 size_t out_size) 5239 { 5240 char *pipeline_name; 5241 uint32_t table_id, meter_profile_id; 5242 int status; 5243 5244 if (n_tokens != 8) { 5245 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5246 return; 5247 } 5248 5249 pipeline_name = tokens[1]; 5250 5251 if (strcmp(tokens[2], "table") != 0) { 5252 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5253 return; 5254 } 5255 5256 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 5257 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5258 return; 5259 } 5260 5261 if (strcmp(tokens[4], "meter") != 0) { 5262 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5263 return; 5264 } 5265 5266 if (strcmp(tokens[5], "profile") != 0) { 5267 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 5268 return; 5269 } 5270 5271 if (softnic_parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 5272 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 5273 return; 5274 } 5275 5276 if (strcmp(tokens[7], "delete") != 0) { 5277 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 5278 return; 5279 } 5280 5281 status = softnic_pipeline_table_mtr_profile_delete(softnic, 5282 pipeline_name, 5283 table_id, 5284 meter_profile_id); 5285 if (status) { 5286 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5287 return; 5288 } 5289 } 5290 5291 /** 5292 * pipeline <pipeline_name> table <table_id> rule read meter [clear] 5293 */ 5294 static void 5295 cmd_pipeline_table_rule_meter_read(struct pmd_internals *softnic __rte_unused, 5296 char **tokens, 5297 uint32_t n_tokens __rte_unused, 5298 char *out, 5299 size_t out_size) 5300 { 5301 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 5302 } 5303 5304 /** 5305 * pipeline <pipeline_name> table <table_id> dscp <file_name> 5306 * 5307 * File <file_name>: 5308 * - exactly 64 lines 5309 * - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r 5310 */ 5311 static int 5312 load_dscp_table(struct rte_table_action_dscp_table *dscp_table, 5313 const char *file_name, 5314 uint32_t *line_number) 5315 { 5316 FILE *f = NULL; 5317 uint32_t dscp, l; 5318 5319 /* Check input arguments */ 5320 if (dscp_table == NULL || 5321 file_name == NULL || 5322 line_number == NULL) { 5323 if (line_number) 5324 *line_number = 0; 5325 return -EINVAL; 5326 } 5327 5328 /* Open input file */ 5329 f = fopen(file_name, "r"); 5330 if (f == NULL) { 5331 *line_number = 0; 5332 return -EINVAL; 5333 } 5334 5335 /* Read file */ 5336 for (dscp = 0, l = 1; ; l++) { 5337 char line[64]; 5338 char *tokens[3]; 5339 enum rte_meter_color color; 5340 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens); 5341 5342 if (fgets(line, sizeof(line), f) == NULL) 5343 break; 5344 5345 if (is_comment(line)) 5346 continue; 5347 5348 if (softnic_parse_tokenize_string(line, tokens, &n_tokens)) { 5349 *line_number = l; 5350 fclose(f); 5351 return -EINVAL; 5352 } 5353 5354 if (n_tokens == 0) 5355 continue; 5356 5357 if (dscp >= RTE_DIM(dscp_table->entry) || 5358 n_tokens != RTE_DIM(tokens) || 5359 softnic_parser_read_uint32(&tc_id, tokens[0]) || 5360 tc_id >= RTE_TABLE_ACTION_TC_MAX || 5361 softnic_parser_read_uint32(&tc_queue_id, tokens[1]) || 5362 tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX || 5363 (strlen(tokens[2]) != 1)) { 5364 *line_number = l; 5365 fclose(f); 5366 return -EINVAL; 5367 } 5368 5369 switch (tokens[2][0]) { 5370 case 'g': 5371 case 'G': 5372 color = e_RTE_METER_GREEN; 5373 break; 5374 5375 case 'y': 5376 case 'Y': 5377 color = e_RTE_METER_YELLOW; 5378 break; 5379 5380 case 'r': 5381 case 'R': 5382 color = e_RTE_METER_RED; 5383 break; 5384 5385 default: 5386 *line_number = l; 5387 fclose(f); 5388 return -EINVAL; 5389 } 5390 5391 dscp_table->entry[dscp].tc_id = tc_id; 5392 dscp_table->entry[dscp].tc_queue_id = tc_queue_id; 5393 dscp_table->entry[dscp].color = color; 5394 dscp++; 5395 } 5396 5397 /* Close file */ 5398 fclose(f); 5399 return 0; 5400 } 5401 5402 static void 5403 cmd_pipeline_table_dscp(struct pmd_internals *softnic, 5404 char **tokens, 5405 uint32_t n_tokens, 5406 char *out, 5407 size_t out_size) 5408 { 5409 struct rte_table_action_dscp_table dscp_table; 5410 char *pipeline_name, *file_name; 5411 uint32_t table_id, line_number; 5412 int status; 5413 5414 if (n_tokens != 6) { 5415 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5416 return; 5417 } 5418 5419 pipeline_name = tokens[1]; 5420 5421 if (strcmp(tokens[2], "table") != 0) { 5422 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5423 return; 5424 } 5425 5426 if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { 5427 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5428 return; 5429 } 5430 5431 if (strcmp(tokens[4], "dscp") != 0) { 5432 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp"); 5433 return; 5434 } 5435 5436 file_name = tokens[5]; 5437 5438 status = load_dscp_table(&dscp_table, file_name, &line_number); 5439 if (status) { 5440 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 5441 return; 5442 } 5443 5444 status = softnic_pipeline_table_dscp_table_update(softnic, 5445 pipeline_name, 5446 table_id, 5447 UINT64_MAX, 5448 &dscp_table); 5449 if (status) { 5450 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5451 return; 5452 } 5453 } 5454 5455 /** 5456 * pipeline <pipeline_name> table <table_id> rule read ttl [clear] 5457 */ 5458 static void 5459 cmd_softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic __rte_unused, 5460 char **tokens, 5461 uint32_t n_tokens __rte_unused, 5462 char *out, 5463 size_t out_size) 5464 { 5465 snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]); 5466 } 5467 5468 /** 5469 * thread <thread_id> pipeline <pipeline_name> enable 5470 */ 5471 static void 5472 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic, 5473 char **tokens, 5474 uint32_t n_tokens, 5475 char *out, 5476 size_t out_size) 5477 { 5478 char *pipeline_name; 5479 uint32_t thread_id; 5480 int status; 5481 5482 if (n_tokens != 5) { 5483 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5484 return; 5485 } 5486 5487 if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) { 5488 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 5489 return; 5490 } 5491 5492 if (strcmp(tokens[2], "pipeline") != 0) { 5493 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5494 return; 5495 } 5496 5497 pipeline_name = tokens[3]; 5498 5499 if (strcmp(tokens[4], "enable") != 0) { 5500 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 5501 return; 5502 } 5503 5504 status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name); 5505 if (status) { 5506 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 5507 return; 5508 } 5509 } 5510 5511 /** 5512 * thread <thread_id> pipeline <pipeline_name> disable 5513 */ 5514 static void 5515 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic, 5516 char **tokens, 5517 uint32_t n_tokens, 5518 char *out, 5519 size_t out_size) 5520 { 5521 char *pipeline_name; 5522 uint32_t thread_id; 5523 int status; 5524 5525 if (n_tokens != 5) { 5526 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5527 return; 5528 } 5529 5530 if (softnic_parser_read_uint32(&thread_id, tokens[1]) != 0) { 5531 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 5532 return; 5533 } 5534 5535 if (strcmp(tokens[2], "pipeline") != 0) { 5536 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5537 return; 5538 } 5539 5540 pipeline_name = tokens[3]; 5541 5542 if (strcmp(tokens[4], "disable") != 0) { 5543 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 5544 return; 5545 } 5546 5547 status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name); 5548 if (status) { 5549 snprintf(out, out_size, MSG_CMD_FAIL, 5550 "thread pipeline disable"); 5551 return; 5552 } 5553 } 5554 5555 /** 5556 * flowapi map 5557 * group <group_id> 5558 * ingress | egress 5559 * pipeline <pipeline_name> 5560 * table <table_id> 5561 */ 5562 static void 5563 cmd_softnic_flowapi_map(struct pmd_internals *softnic, 5564 char **tokens, 5565 uint32_t n_tokens, 5566 char *out, 5567 size_t out_size) 5568 { 5569 char *pipeline_name; 5570 uint32_t group_id, table_id; 5571 int ingress, status; 5572 5573 if (n_tokens != 9) { 5574 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5575 return; 5576 } 5577 5578 if (strcmp(tokens[1], "map") != 0) { 5579 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "map"); 5580 return; 5581 } 5582 5583 if (strcmp(tokens[2], "group") != 0) { 5584 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group"); 5585 return; 5586 } 5587 5588 if (softnic_parser_read_uint32(&group_id, tokens[3]) != 0) { 5589 snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); 5590 return; 5591 } 5592 5593 if (strcmp(tokens[4], "ingress") == 0) { 5594 ingress = 1; 5595 } else if (strcmp(tokens[4], "egress") == 0) { 5596 ingress = 0; 5597 } else { 5598 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ingress | egress"); 5599 return; 5600 } 5601 5602 if (strcmp(tokens[5], "pipeline") != 0) { 5603 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5604 return; 5605 } 5606 5607 pipeline_name = tokens[6]; 5608 5609 if (strcmp(tokens[7], "table") != 0) { 5610 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5611 return; 5612 } 5613 5614 if (softnic_parser_read_uint32(&table_id, tokens[8]) != 0) { 5615 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5616 return; 5617 } 5618 5619 status = flow_attr_map_set(softnic, 5620 group_id, 5621 ingress, 5622 pipeline_name, 5623 table_id); 5624 if (status) { 5625 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5626 return; 5627 } 5628 } 5629 5630 void 5631 softnic_cli_process(char *in, char *out, size_t out_size, void *arg) 5632 { 5633 char *tokens[CMD_MAX_TOKENS]; 5634 uint32_t n_tokens = RTE_DIM(tokens); 5635 struct pmd_internals *softnic = arg; 5636 int status; 5637 5638 if (is_comment(in)) 5639 return; 5640 5641 status = softnic_parse_tokenize_string(in, tokens, &n_tokens); 5642 if (status) { 5643 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 5644 return; 5645 } 5646 5647 if (n_tokens == 0) 5648 return; 5649 5650 if (strcmp(tokens[0], "mempool") == 0) { 5651 cmd_mempool(softnic, tokens, n_tokens, out, out_size); 5652 return; 5653 } 5654 5655 if (strcmp(tokens[0], "link") == 0) { 5656 cmd_link(softnic, tokens, n_tokens, out, out_size); 5657 return; 5658 } 5659 5660 if (strcmp(tokens[0], "swq") == 0) { 5661 cmd_swq(softnic, tokens, n_tokens, out, out_size); 5662 return; 5663 } 5664 5665 if (strcmp(tokens[0], "tmgr") == 0) { 5666 if (n_tokens == 2) { 5667 cmd_tmgr(softnic, tokens, n_tokens, out, out_size); 5668 return; 5669 } 5670 5671 if (n_tokens >= 3 && 5672 (strcmp(tokens[1], "shaper") == 0) && 5673 (strcmp(tokens[2], "profile") == 0)) { 5674 cmd_tmgr_shaper_profile(softnic, tokens, n_tokens, out, out_size); 5675 return; 5676 } 5677 5678 if (n_tokens >= 3 && 5679 (strcmp(tokens[1], "shared") == 0) && 5680 (strcmp(tokens[2], "shaper") == 0)) { 5681 cmd_tmgr_shared_shaper(softnic, tokens, n_tokens, out, out_size); 5682 return; 5683 } 5684 5685 if (n_tokens >= 2 && 5686 (strcmp(tokens[1], "node") == 0)) { 5687 cmd_tmgr_node(softnic, tokens, n_tokens, out, out_size); 5688 return; 5689 } 5690 5691 if (n_tokens >= 2 && 5692 (strcmp(tokens[1], "hierarchy-default") == 0)) { 5693 cmd_tmgr_hierarchy_default(softnic, tokens, n_tokens, out, out_size); 5694 return; 5695 } 5696 5697 if (n_tokens >= 3 && 5698 (strcmp(tokens[1], "hierarchy") == 0) && 5699 (strcmp(tokens[2], "commit") == 0)) { 5700 cmd_tmgr_hierarchy_commit(softnic, tokens, n_tokens, out, out_size); 5701 return; 5702 } 5703 } 5704 5705 if (strcmp(tokens[0], "tap") == 0) { 5706 cmd_tap(softnic, tokens, n_tokens, out, out_size); 5707 return; 5708 } 5709 5710 if (strcmp(tokens[0], "cryptodev") == 0) { 5711 cmd_cryptodev(softnic, tokens, n_tokens, out, out_size); 5712 return; 5713 } 5714 5715 if (strcmp(tokens[0], "port") == 0) { 5716 cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size); 5717 return; 5718 } 5719 5720 if (strcmp(tokens[0], "table") == 0) { 5721 cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size); 5722 return; 5723 } 5724 5725 if (strcmp(tokens[0], "pipeline") == 0) { 5726 if (n_tokens >= 3 && 5727 (strcmp(tokens[2], "period") == 0)) { 5728 cmd_pipeline(softnic, tokens, n_tokens, out, out_size); 5729 return; 5730 } 5731 5732 if (n_tokens >= 5 && 5733 (strcmp(tokens[2], "port") == 0) && 5734 (strcmp(tokens[3], "in") == 0) && 5735 (strcmp(tokens[4], "bsz") == 0)) { 5736 cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size); 5737 return; 5738 } 5739 5740 if (n_tokens >= 5 && 5741 (strcmp(tokens[2], "port") == 0) && 5742 (strcmp(tokens[3], "out") == 0) && 5743 (strcmp(tokens[4], "bsz") == 0)) { 5744 cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size); 5745 return; 5746 } 5747 5748 if (n_tokens >= 4 && 5749 (strcmp(tokens[2], "table") == 0) && 5750 (strcmp(tokens[3], "match") == 0)) { 5751 cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size); 5752 return; 5753 } 5754 5755 if (n_tokens >= 6 && 5756 (strcmp(tokens[2], "port") == 0) && 5757 (strcmp(tokens[3], "in") == 0) && 5758 (strcmp(tokens[5], "table") == 0)) { 5759 cmd_pipeline_port_in_table(softnic, tokens, n_tokens, 5760 out, out_size); 5761 return; 5762 } 5763 5764 if (n_tokens >= 6 && 5765 (strcmp(tokens[2], "port") == 0) && 5766 (strcmp(tokens[3], "in") == 0) && 5767 (strcmp(tokens[5], "stats") == 0)) { 5768 cmd_pipeline_port_in_stats(softnic, tokens, n_tokens, 5769 out, out_size); 5770 return; 5771 } 5772 5773 if (n_tokens >= 6 && 5774 (strcmp(tokens[2], "port") == 0) && 5775 (strcmp(tokens[3], "in") == 0) && 5776 (strcmp(tokens[5], "enable") == 0)) { 5777 cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens, 5778 out, out_size); 5779 return; 5780 } 5781 5782 if (n_tokens >= 6 && 5783 (strcmp(tokens[2], "port") == 0) && 5784 (strcmp(tokens[3], "in") == 0) && 5785 (strcmp(tokens[5], "disable") == 0)) { 5786 cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens, 5787 out, out_size); 5788 return; 5789 } 5790 5791 if (n_tokens >= 6 && 5792 (strcmp(tokens[2], "port") == 0) && 5793 (strcmp(tokens[3], "out") == 0) && 5794 (strcmp(tokens[5], "stats") == 0)) { 5795 cmd_pipeline_port_out_stats(softnic, tokens, n_tokens, 5796 out, out_size); 5797 return; 5798 } 5799 5800 if (n_tokens >= 5 && 5801 (strcmp(tokens[2], "table") == 0) && 5802 (strcmp(tokens[4], "stats") == 0)) { 5803 cmd_pipeline_table_stats(softnic, tokens, n_tokens, 5804 out, out_size); 5805 return; 5806 } 5807 5808 if (n_tokens >= 7 && 5809 (strcmp(tokens[2], "table") == 0) && 5810 (strcmp(tokens[4], "rule") == 0) && 5811 (strcmp(tokens[5], "add") == 0) && 5812 (strcmp(tokens[6], "match") == 0)) { 5813 if (n_tokens >= 8 && 5814 (strcmp(tokens[7], "default") == 0)) { 5815 cmd_softnic_pipeline_table_rule_add_default(softnic, tokens, 5816 n_tokens, out, out_size); 5817 return; 5818 } 5819 5820 cmd_softnic_pipeline_table_rule_add(softnic, tokens, n_tokens, 5821 out, out_size); 5822 return; 5823 } 5824 5825 if (n_tokens >= 7 && 5826 (strcmp(tokens[2], "table") == 0) && 5827 (strcmp(tokens[4], "rule") == 0) && 5828 (strcmp(tokens[5], "add") == 0) && 5829 (strcmp(tokens[6], "bulk") == 0)) { 5830 cmd_softnic_pipeline_table_rule_add_bulk(softnic, tokens, 5831 n_tokens, out, out_size); 5832 return; 5833 } 5834 5835 if (n_tokens >= 7 && 5836 (strcmp(tokens[2], "table") == 0) && 5837 (strcmp(tokens[4], "rule") == 0) && 5838 (strcmp(tokens[5], "delete") == 0) && 5839 (strcmp(tokens[6], "match") == 0)) { 5840 if (n_tokens >= 8 && 5841 (strcmp(tokens[7], "default") == 0)) { 5842 cmd_softnic_pipeline_table_rule_delete_default(softnic, tokens, 5843 n_tokens, out, out_size); 5844 return; 5845 } 5846 5847 cmd_softnic_pipeline_table_rule_delete(softnic, tokens, n_tokens, 5848 out, out_size); 5849 return; 5850 } 5851 5852 if (n_tokens >= 7 && 5853 (strcmp(tokens[2], "table") == 0) && 5854 (strcmp(tokens[4], "rule") == 0) && 5855 (strcmp(tokens[5], "read") == 0) && 5856 (strcmp(tokens[6], "stats") == 0)) { 5857 cmd_softnic_pipeline_table_rule_stats_read(softnic, tokens, n_tokens, 5858 out, out_size); 5859 return; 5860 } 5861 5862 if (n_tokens >= 8 && 5863 (strcmp(tokens[2], "table") == 0) && 5864 (strcmp(tokens[4], "meter") == 0) && 5865 (strcmp(tokens[5], "profile") == 0) && 5866 (strcmp(tokens[7], "add") == 0)) { 5867 cmd_pipeline_table_meter_profile_add(softnic, tokens, n_tokens, 5868 out, out_size); 5869 return; 5870 } 5871 5872 if (n_tokens >= 8 && 5873 (strcmp(tokens[2], "table") == 0) && 5874 (strcmp(tokens[4], "meter") == 0) && 5875 (strcmp(tokens[5], "profile") == 0) && 5876 (strcmp(tokens[7], "delete") == 0)) { 5877 cmd_pipeline_table_meter_profile_delete(softnic, tokens, 5878 n_tokens, out, out_size); 5879 return; 5880 } 5881 5882 if (n_tokens >= 7 && 5883 (strcmp(tokens[2], "table") == 0) && 5884 (strcmp(tokens[4], "rule") == 0) && 5885 (strcmp(tokens[5], "read") == 0) && 5886 (strcmp(tokens[6], "meter") == 0)) { 5887 cmd_pipeline_table_rule_meter_read(softnic, tokens, n_tokens, 5888 out, out_size); 5889 return; 5890 } 5891 5892 if (n_tokens >= 5 && 5893 (strcmp(tokens[2], "table") == 0) && 5894 (strcmp(tokens[4], "dscp") == 0)) { 5895 cmd_pipeline_table_dscp(softnic, tokens, n_tokens, 5896 out, out_size); 5897 return; 5898 } 5899 5900 if (n_tokens >= 7 && 5901 (strcmp(tokens[2], "table") == 0) && 5902 (strcmp(tokens[4], "rule") == 0) && 5903 (strcmp(tokens[5], "read") == 0) && 5904 (strcmp(tokens[6], "ttl") == 0)) { 5905 cmd_softnic_pipeline_table_rule_ttl_read(softnic, tokens, n_tokens, 5906 out, out_size); 5907 return; 5908 } 5909 } 5910 5911 if (strcmp(tokens[0], "thread") == 0) { 5912 if (n_tokens >= 5 && 5913 (strcmp(tokens[4], "enable") == 0)) { 5914 cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens, 5915 out, out_size); 5916 return; 5917 } 5918 5919 if (n_tokens >= 5 && 5920 (strcmp(tokens[4], "disable") == 0)) { 5921 cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens, 5922 out, out_size); 5923 return; 5924 } 5925 } 5926 5927 if (strcmp(tokens[0], "flowapi") == 0) { 5928 cmd_softnic_flowapi_map(softnic, tokens, n_tokens, out, 5929 out_size); 5930 return; 5931 } 5932 5933 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 5934 } 5935 5936 int 5937 softnic_cli_script_process(struct pmd_internals *softnic, 5938 const char *file_name, 5939 size_t msg_in_len_max, 5940 size_t msg_out_len_max) 5941 { 5942 char *msg_in = NULL, *msg_out = NULL; 5943 FILE *f = NULL; 5944 5945 /* Check input arguments */ 5946 if (file_name == NULL || 5947 (strlen(file_name) == 0) || 5948 msg_in_len_max == 0 || 5949 msg_out_len_max == 0) 5950 return -EINVAL; 5951 5952 msg_in = malloc(msg_in_len_max + 1); 5953 msg_out = malloc(msg_out_len_max + 1); 5954 if (msg_in == NULL || 5955 msg_out == NULL) { 5956 free(msg_out); 5957 free(msg_in); 5958 return -ENOMEM; 5959 } 5960 5961 /* Open input file */ 5962 f = fopen(file_name, "r"); 5963 if (f == NULL) { 5964 free(msg_out); 5965 free(msg_in); 5966 return -EIO; 5967 } 5968 5969 /* Read file */ 5970 for ( ; ; ) { 5971 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 5972 break; 5973 5974 printf("%s", msg_in); 5975 msg_out[0] = 0; 5976 5977 softnic_cli_process(msg_in, 5978 msg_out, 5979 msg_out_len_max, 5980 softnic); 5981 5982 if (strlen(msg_out)) 5983 printf("%s", msg_out); 5984 } 5985 5986 /* Close file */ 5987 fclose(f); 5988 free(msg_out); 5989 free(msg_in); 5990 return 0; 5991 } 5992 5993 static int 5994 cli_rule_file_process(const char *file_name, 5995 size_t line_len_max, 5996 struct softnic_table_rule_match *m, 5997 struct softnic_table_rule_action *a, 5998 uint32_t *n_rules, 5999 uint32_t *line_number, 6000 char *out, 6001 size_t out_size) 6002 { 6003 FILE *f = NULL; 6004 char *line = NULL; 6005 uint32_t rule_id, line_id; 6006 int status = 0; 6007 6008 /* Check input arguments */ 6009 if (file_name == NULL || 6010 (strlen(file_name) == 0) || 6011 line_len_max == 0) { 6012 *line_number = 0; 6013 return -EINVAL; 6014 } 6015 6016 /* Memory allocation */ 6017 line = malloc(line_len_max + 1); 6018 if (line == NULL) { 6019 *line_number = 0; 6020 return -ENOMEM; 6021 } 6022 6023 /* Open file */ 6024 f = fopen(file_name, "r"); 6025 if (f == NULL) { 6026 *line_number = 0; 6027 free(line); 6028 return -EIO; 6029 } 6030 6031 /* Read file */ 6032 for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) { 6033 char *tokens[CMD_MAX_TOKENS]; 6034 uint32_t n_tokens, n_tokens_parsed, t0; 6035 6036 /* Read next line from file. */ 6037 if (fgets(line, line_len_max + 1, f) == NULL) 6038 break; 6039 6040 /* Comment. */ 6041 if (is_comment(line)) 6042 continue; 6043 6044 /* Parse line. */ 6045 n_tokens = RTE_DIM(tokens); 6046 status = softnic_parse_tokenize_string(line, tokens, &n_tokens); 6047 if (status) { 6048 status = -EINVAL; 6049 break; 6050 } 6051 6052 /* Empty line. */ 6053 if (n_tokens == 0) 6054 continue; 6055 t0 = 0; 6056 6057 /* Rule match. */ 6058 n_tokens_parsed = parse_match(tokens + t0, 6059 n_tokens - t0, 6060 out, 6061 out_size, 6062 &m[rule_id]); 6063 if (n_tokens_parsed == 0) { 6064 status = -EINVAL; 6065 break; 6066 } 6067 t0 += n_tokens_parsed; 6068 6069 /* Rule action. */ 6070 n_tokens_parsed = parse_table_action(tokens + t0, 6071 n_tokens - t0, 6072 out, 6073 out_size, 6074 &a[rule_id]); 6075 if (n_tokens_parsed == 0) { 6076 status = -EINVAL; 6077 break; 6078 } 6079 t0 += n_tokens_parsed; 6080 6081 /* Line completed. */ 6082 if (t0 < n_tokens) { 6083 status = -EINVAL; 6084 break; 6085 } 6086 6087 /* Increment rule count */ 6088 rule_id++; 6089 } 6090 6091 /* Close file */ 6092 fclose(f); 6093 6094 /* Memory free */ 6095 free(line); 6096 6097 *n_rules = rule_id; 6098 *line_number = line_id; 6099 return status; 6100 } 6101