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