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