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