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