1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2018 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include <rte_common.h> 11 #include <rte_cycles.h> 12 #include <rte_ethdev.h> 13 14 #include "cli.h" 15 16 #include "cryptodev.h" 17 #include "link.h" 18 #include "mempool.h" 19 #include "parser.h" 20 #include "pipeline.h" 21 #include "swq.h" 22 #include "tap.h" 23 #include "thread.h" 24 #include "tmgr.h" 25 26 #ifndef CMD_MAX_TOKENS 27 #define CMD_MAX_TOKENS 256 28 #endif 29 30 #define MSG_OUT_OF_MEMORY "Not enough memory.\n" 31 #define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n" 32 #define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n" 33 #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n" 34 #define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n" 35 #define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\".\n" 36 #define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n" 37 #define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n" 38 #define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n" 39 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n" 40 #define MSG_CMD_FAIL "Command \"%s\" failed.\n" 41 42 static int 43 is_comment(char *in) 44 { 45 if ((strlen(in) && index("!#%;", in[0])) || 46 (strncmp(in, "//", 2) == 0) || 47 (strncmp(in, "--", 2) == 0)) 48 return 1; 49 50 return 0; 51 } 52 53 static const char cmd_mempool_help[] = 54 "mempool <mempool_name>\n" 55 " buffer <buffer_size>\n" 56 " pool <pool_size>\n" 57 " cache <cache_size>\n" 58 " cpu <cpu_id>\n"; 59 60 static void 61 cmd_mempool(char **tokens, 62 uint32_t n_tokens, 63 char *out, 64 size_t out_size) 65 { 66 struct mempool_params p; 67 char *name; 68 struct mempool *mempool; 69 70 if (n_tokens != 10) { 71 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 72 return; 73 } 74 75 name = tokens[1]; 76 77 if (strcmp(tokens[2], "buffer") != 0) { 78 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer"); 79 return; 80 } 81 82 if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) { 83 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size"); 84 return; 85 } 86 87 if (strcmp(tokens[4], "pool") != 0) { 88 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool"); 89 return; 90 } 91 92 if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) { 93 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size"); 94 return; 95 } 96 97 if (strcmp(tokens[6], "cache") != 0) { 98 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); 99 return; 100 } 101 102 if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) { 103 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); 104 return; 105 } 106 107 if (strcmp(tokens[8], "cpu") != 0) { 108 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 109 return; 110 } 111 112 if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) { 113 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 114 return; 115 } 116 117 mempool = mempool_create(name, &p); 118 if (mempool == NULL) { 119 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 120 return; 121 } 122 } 123 124 static const char cmd_link_help[] = 125 "link <link_name>\n" 126 " dev <device_name> | port <port_id>\n" 127 " rxq <n_queues> <queue_size> <mempool_name>\n" 128 " txq <n_queues> <queue_size>\n" 129 " promiscuous on | off\n" 130 " [rss <qid_0> ... <qid_n>]\n"; 131 132 static void 133 cmd_link(char **tokens, 134 uint32_t n_tokens, 135 char *out, 136 size_t out_size) 137 { 138 struct link_params p; 139 struct link_params_rss rss; 140 struct link *link; 141 char *name; 142 143 memset(&p, 0, sizeof(p)); 144 145 if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) { 146 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 147 return; 148 } 149 name = tokens[1]; 150 151 if (strcmp(tokens[2], "dev") == 0) 152 p.dev_name = tokens[3]; 153 else if (strcmp(tokens[2], "port") == 0) { 154 p.dev_name = NULL; 155 156 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) { 157 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 158 return; 159 } 160 } else { 161 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port"); 162 return; 163 } 164 165 if (strcmp(tokens[4], "rxq") != 0) { 166 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 167 return; 168 } 169 170 if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) { 171 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 172 return; 173 } 174 if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) { 175 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 176 return; 177 } 178 179 p.rx.mempool_name = tokens[7]; 180 181 if (strcmp(tokens[8], "txq") != 0) { 182 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 183 return; 184 } 185 186 if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) { 187 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues"); 188 return; 189 } 190 191 if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) { 192 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size"); 193 return; 194 } 195 196 if (strcmp(tokens[11], "promiscuous") != 0) { 197 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous"); 198 return; 199 } 200 201 if (strcmp(tokens[12], "on") == 0) 202 p.promiscuous = 1; 203 else if (strcmp(tokens[12], "off") == 0) 204 p.promiscuous = 0; 205 else { 206 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off"); 207 return; 208 } 209 210 /* RSS */ 211 p.rx.rss = NULL; 212 if (n_tokens > 13) { 213 uint32_t queue_id, i; 214 215 if (strcmp(tokens[13], "rss") != 0) { 216 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss"); 217 return; 218 } 219 220 p.rx.rss = &rss; 221 222 rss.n_queues = 0; 223 for (i = 14; i < n_tokens; i++) { 224 if (parser_read_uint32(&queue_id, tokens[i]) != 0) { 225 snprintf(out, out_size, MSG_ARG_INVALID, 226 "queue_id"); 227 return; 228 } 229 230 rss.queue_id[rss.n_queues] = queue_id; 231 rss.n_queues++; 232 } 233 } 234 235 link = link_create(name, &p); 236 if (link == NULL) { 237 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 238 return; 239 } 240 } 241 242 /* Print the link stats and info */ 243 static void 244 print_link_info(struct link *link, char *out, size_t out_size) 245 { 246 struct rte_eth_stats stats; 247 struct rte_ether_addr mac_addr; 248 struct rte_eth_link eth_link; 249 uint16_t mtu; 250 int ret; 251 252 memset(&stats, 0, sizeof(stats)); 253 rte_eth_stats_get(link->port_id, &stats); 254 255 ret = rte_eth_macaddr_get(link->port_id, &mac_addr); 256 if (ret != 0) { 257 snprintf(out, out_size, "\n%s: MAC address get failed: %s", 258 link->name, rte_strerror(-ret)); 259 return; 260 } 261 262 ret = rte_eth_link_get(link->port_id, ð_link); 263 if (ret < 0) { 264 snprintf(out, out_size, "\n%s: link get failed: %s", 265 link->name, rte_strerror(-ret)); 266 return; 267 } 268 269 rte_eth_dev_get_mtu(link->port_id, &mtu); 270 271 snprintf(out, out_size, 272 "\n" 273 "%s: flags=<%s> mtu %u\n" 274 "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n" 275 "\tport# %u speed %s\n" 276 "\tRX packets %" PRIu64" bytes %" PRIu64"\n" 277 "\tRX errors %" PRIu64" missed %" PRIu64" no-mbuf %" PRIu64"\n" 278 "\tTX packets %" PRIu64" bytes %" PRIu64"\n" 279 "\tTX errors %" PRIu64"\n", 280 link->name, 281 eth_link.link_status == 0 ? "DOWN" : "UP", 282 mtu, 283 RTE_ETHER_ADDR_BYTES(&mac_addr), 284 link->n_rxq, 285 link->n_txq, 286 link->port_id, 287 rte_eth_link_speed_to_str(eth_link.link_speed), 288 stats.ipackets, 289 stats.ibytes, 290 stats.ierrors, 291 stats.imissed, 292 stats.rx_nombuf, 293 stats.opackets, 294 stats.obytes, 295 stats.oerrors); 296 } 297 298 /* 299 * link show [<link_name>] 300 */ 301 static void 302 cmd_link_show(char **tokens, uint32_t n_tokens, char *out, size_t out_size) 303 { 304 struct link *link; 305 char *link_name; 306 307 if (n_tokens != 2 && n_tokens != 3) { 308 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 309 return; 310 } 311 312 if (n_tokens == 2) { 313 link = link_next(NULL); 314 315 while (link != NULL) { 316 out_size = out_size - strlen(out); 317 out = &out[strlen(out)]; 318 319 print_link_info(link, out, out_size); 320 link = link_next(link); 321 } 322 } else { 323 out_size = out_size - strlen(out); 324 out = &out[strlen(out)]; 325 326 link_name = tokens[2]; 327 link = link_find(link_name); 328 329 if (link == NULL) { 330 snprintf(out, out_size, MSG_ARG_INVALID, 331 "Link does not exist"); 332 return; 333 } 334 print_link_info(link, out, out_size); 335 } 336 } 337 338 static const char cmd_swq_help[] = 339 "swq <swq_name>\n" 340 " size <size>\n" 341 " cpu <cpu_id>\n"; 342 343 static void 344 cmd_swq(char **tokens, 345 uint32_t n_tokens, 346 char *out, 347 size_t out_size) 348 { 349 struct swq_params p; 350 char *name; 351 struct swq *swq; 352 353 if (n_tokens != 6) { 354 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 355 return; 356 } 357 358 name = tokens[1]; 359 360 if (strcmp(tokens[2], "size") != 0) { 361 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 362 return; 363 } 364 365 if (parser_read_uint32(&p.size, tokens[3]) != 0) { 366 snprintf(out, out_size, MSG_ARG_INVALID, "size"); 367 return; 368 } 369 370 if (strcmp(tokens[4], "cpu") != 0) { 371 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 372 return; 373 } 374 375 if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) { 376 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 377 return; 378 } 379 380 swq = swq_create(name, &p); 381 if (swq == NULL) { 382 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 383 return; 384 } 385 } 386 387 static const char cmd_tmgr_subport_profile_help[] = 388 "tmgr subport profile\n" 389 " <tb_rate> <tb_size>\n" 390 " <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> <tc4_rate>" 391 " <tc5_rate> <tc6_rate> <tc7_rate> <tc8_rate>" 392 " <tc9_rate> <tc10_rate> <tc11_rate> <tc12_rate>\n" 393 " <tc_period>\n"; 394 395 static void 396 cmd_tmgr_subport_profile(char **tokens, 397 uint32_t n_tokens, 398 char *out, 399 size_t out_size) 400 { 401 struct rte_sched_subport_profile_params subport_profile; 402 int status, i; 403 404 if (n_tokens != 19) { 405 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 406 return; 407 } 408 409 if (parser_read_uint64(&subport_profile.tb_rate, tokens[3]) != 0) { 410 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); 411 return; 412 } 413 414 if (parser_read_uint64(&subport_profile.tb_size, tokens[4]) != 0) { 415 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); 416 return; 417 } 418 419 for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) 420 if (parser_read_uint64(&subport_profile.tc_rate[i], 421 tokens[5 + i]) != 0) { 422 snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate"); 423 return; 424 } 425 426 if (parser_read_uint64(&subport_profile.tc_period, tokens[18]) != 0) { 427 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period"); 428 return; 429 } 430 431 status = tmgr_subport_profile_add(&subport_profile); 432 if (status != 0) { 433 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 434 return; 435 } 436 } 437 438 static const char cmd_tmgr_pipe_profile_help[] = 439 "tmgr pipe profile\n" 440 " <tb_rate> <tb_size>\n" 441 " <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> <tc4_rate>" 442 " <tc5_rate> <tc6_rate> <tc7_rate> <tc8_rate>" 443 " <tc9_rate> <tc10_rate> <tc11_rate> <tc12_rate>\n" 444 " <tc_period>\n" 445 " <tc_ov_weight>\n" 446 " <wrr_weight0..3>\n"; 447 448 static void 449 cmd_tmgr_pipe_profile(char **tokens, 450 uint32_t n_tokens, 451 char *out, 452 size_t out_size) 453 { 454 struct rte_sched_pipe_params p; 455 int status, i; 456 457 if (n_tokens != 24) { 458 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 459 return; 460 } 461 462 if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) { 463 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); 464 return; 465 } 466 467 if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) { 468 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); 469 return; 470 } 471 472 for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) 473 if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) { 474 snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate"); 475 return; 476 } 477 478 if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) { 479 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period"); 480 return; 481 } 482 483 if (parser_read_uint8(&p.tc_ov_weight, tokens[19]) != 0) { 484 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight"); 485 return; 486 } 487 488 for (i = 0; i < RTE_SCHED_BE_QUEUES_PER_PIPE; i++) 489 if (parser_read_uint8(&p.wrr_weights[i], tokens[20 + i]) != 0) { 490 snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights"); 491 return; 492 } 493 494 status = tmgr_pipe_profile_add(&p); 495 if (status != 0) { 496 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 497 return; 498 } 499 } 500 501 static const char cmd_tmgr_help[] = 502 "tmgr <tmgr_name>\n" 503 " rate <rate>\n" 504 " spp <n_subports_per_port>\n" 505 " pps <n_pipes_per_subport>\n" 506 " fo <frame_overhead>\n" 507 " mtu <mtu>\n" 508 " cpu <cpu_id>\n"; 509 510 static void 511 cmd_tmgr(char **tokens, 512 uint32_t n_tokens, 513 char *out, 514 size_t out_size) 515 { 516 struct tmgr_port_params p; 517 char *name; 518 struct tmgr_port *tmgr_port; 519 520 if (n_tokens != 14) { 521 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 522 return; 523 } 524 525 name = tokens[1]; 526 527 if (strcmp(tokens[2], "rate") != 0) { 528 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate"); 529 return; 530 } 531 532 if (parser_read_uint64(&p.rate, tokens[3]) != 0) { 533 snprintf(out, out_size, MSG_ARG_INVALID, "rate"); 534 return; 535 } 536 537 if (strcmp(tokens[4], "spp") != 0) { 538 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 539 return; 540 } 541 542 if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) { 543 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); 544 return; 545 } 546 547 if (strcmp(tokens[6], "pps") != 0) { 548 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 549 return; 550 } 551 552 if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) { 553 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); 554 return; 555 } 556 557 if (strcmp(tokens[8], "fo") != 0) { 558 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo"); 559 return; 560 } 561 562 if (parser_read_uint32(&p.frame_overhead, tokens[9]) != 0) { 563 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead"); 564 return; 565 } 566 567 if (strcmp(tokens[10], "mtu") != 0) { 568 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu"); 569 return; 570 } 571 572 if (parser_read_uint32(&p.mtu, tokens[11]) != 0) { 573 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 574 return; 575 } 576 577 if (strcmp(tokens[12], "cpu") != 0) { 578 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 579 return; 580 } 581 582 if (parser_read_uint32(&p.cpu_id, tokens[13]) != 0) { 583 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 584 return; 585 } 586 587 tmgr_port = tmgr_port_create(name, &p); 588 if (tmgr_port == NULL) { 589 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 590 return; 591 } 592 } 593 594 static const char cmd_tmgr_subport_help[] = 595 "tmgr <tmgr_name> subport <subport_id>\n" 596 " profile <subport_profile_id>\n"; 597 598 static void 599 cmd_tmgr_subport(char **tokens, 600 uint32_t n_tokens, 601 char *out, 602 size_t out_size) 603 { 604 uint32_t subport_id, subport_profile_id; 605 int status; 606 char *name; 607 608 if (n_tokens != 6) { 609 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 610 return; 611 } 612 613 name = tokens[1]; 614 615 if (parser_read_uint32(&subport_id, tokens[3]) != 0) { 616 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id"); 617 return; 618 } 619 620 if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) { 621 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id"); 622 return; 623 } 624 625 status = tmgr_subport_config(name, subport_id, subport_profile_id); 626 if (status) { 627 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 628 return; 629 } 630 } 631 632 633 static const char cmd_tmgr_subport_pipe_help[] = 634 "tmgr <tmgr_name> subport <subport_id> pipe\n" 635 " from <pipe_id_first> to <pipe_id_last>\n" 636 " profile <pipe_profile_id>\n"; 637 638 static void 639 cmd_tmgr_subport_pipe(char **tokens, 640 uint32_t n_tokens, 641 char *out, 642 size_t out_size) 643 { 644 uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id; 645 int status; 646 char *name; 647 648 if (n_tokens != 11) { 649 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 650 return; 651 } 652 653 name = tokens[1]; 654 655 if (parser_read_uint32(&subport_id, tokens[3]) != 0) { 656 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id"); 657 return; 658 } 659 660 if (strcmp(tokens[4], "pipe") != 0) { 661 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe"); 662 return; 663 } 664 665 if (strcmp(tokens[5], "from") != 0) { 666 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from"); 667 return; 668 } 669 670 if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) { 671 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first"); 672 return; 673 } 674 675 if (strcmp(tokens[7], "to") != 0) { 676 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to"); 677 return; 678 } 679 680 if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) { 681 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last"); 682 return; 683 } 684 685 if (strcmp(tokens[9], "profile") != 0) { 686 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 687 return; 688 } 689 690 if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) { 691 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id"); 692 return; 693 } 694 695 status = tmgr_pipe_config(name, subport_id, pipe_id_first, 696 pipe_id_last, pipe_profile_id); 697 if (status) { 698 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 699 return; 700 } 701 } 702 703 704 static const char cmd_tap_help[] = 705 "tap <tap_name>\n"; 706 707 static void 708 cmd_tap(char **tokens, 709 uint32_t n_tokens, 710 char *out, 711 size_t out_size) 712 { 713 char *name; 714 struct tap *tap; 715 716 if (n_tokens != 2) { 717 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 718 return; 719 } 720 721 name = tokens[1]; 722 723 tap = tap_create(name); 724 if (tap == NULL) { 725 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 726 return; 727 } 728 } 729 730 731 static const char cmd_cryptodev_help[] = 732 "cryptodev <cryptodev_name>\n" 733 " dev <device_name> | dev_id <device_id>\n" 734 " queue <n_queues> <queue_size>\n" 735 " max_sessions <n_sessions>"; 736 737 static void 738 cmd_cryptodev(char **tokens, 739 uint32_t n_tokens, 740 char *out, 741 size_t out_size) 742 { 743 struct cryptodev_params params; 744 char *name; 745 746 memset(¶ms, 0, sizeof(params)); 747 if (n_tokens != 9) { 748 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 749 return; 750 } 751 752 name = tokens[1]; 753 754 if (strcmp(tokens[2], "dev") == 0) 755 params.dev_name = tokens[3]; 756 else if (strcmp(tokens[2], "dev_id") == 0) { 757 if (parser_read_uint32(¶ms.dev_id, tokens[3]) < 0) { 758 snprintf(out, out_size, MSG_ARG_INVALID, 759 "dev_id"); 760 return; 761 } 762 } else { 763 snprintf(out, out_size, MSG_ARG_INVALID, 764 "cryptodev"); 765 return; 766 } 767 768 if (strcmp(tokens[4], "queue")) { 769 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 770 "queue"); 771 return; 772 } 773 774 if (parser_read_uint32(¶ms.n_queues, tokens[5]) < 0) { 775 snprintf(out, out_size, MSG_ARG_INVALID, 776 "q"); 777 return; 778 } 779 780 if (parser_read_uint32(¶ms.queue_size, tokens[6]) < 0) { 781 snprintf(out, out_size, MSG_ARG_INVALID, 782 "queue_size"); 783 return; 784 } 785 786 if (strcmp(tokens[7], "max_sessions")) { 787 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 788 "max_sessions"); 789 return; 790 } 791 792 if (parser_read_uint32(¶ms.session_pool_size, tokens[8]) < 0) { 793 snprintf(out, out_size, MSG_ARG_INVALID, 794 "queue_size"); 795 return; 796 } 797 798 if (cryptodev_create(name, ¶ms) == NULL) { 799 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 800 return; 801 } 802 } 803 804 static const char cmd_port_in_action_profile_help[] = 805 "port in action profile <profile_name>\n" 806 " [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]\n" 807 " [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]\n"; 808 809 static void 810 cmd_port_in_action_profile(char **tokens, 811 uint32_t n_tokens, 812 char *out, 813 size_t out_size) 814 { 815 struct port_in_action_profile_params p; 816 struct port_in_action_profile *ap; 817 char *name; 818 uint32_t t0; 819 820 memset(&p, 0, sizeof(p)); 821 822 if (n_tokens < 5) { 823 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 824 return; 825 } 826 827 if (strcmp(tokens[1], "in") != 0) { 828 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 829 return; 830 } 831 832 if (strcmp(tokens[2], "action") != 0) { 833 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); 834 return; 835 } 836 837 if (strcmp(tokens[3], "profile") != 0) { 838 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 839 return; 840 } 841 842 name = tokens[4]; 843 844 t0 = 5; 845 846 if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) { 847 uint32_t size; 848 849 if (n_tokens < t0 + 10) { 850 snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter"); 851 return; 852 } 853 854 if (strcmp(tokens[t0 + 1], "match") == 0) 855 p.fltr.filter_on_match = 1; 856 else if (strcmp(tokens[t0 + 1], "mismatch") == 0) 857 p.fltr.filter_on_match = 0; 858 else { 859 snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch"); 860 return; 861 } 862 863 if (strcmp(tokens[t0 + 2], "offset") != 0) { 864 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 865 return; 866 } 867 868 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) { 869 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 870 return; 871 } 872 873 if (strcmp(tokens[t0 + 4], "mask") != 0) { 874 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 875 return; 876 } 877 878 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; 879 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) || 880 (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) { 881 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 882 return; 883 } 884 885 if (strcmp(tokens[t0 + 6], "key") != 0) { 886 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 887 return; 888 } 889 890 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; 891 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) || 892 (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) { 893 snprintf(out, out_size, MSG_ARG_INVALID, "key_value"); 894 return; 895 } 896 897 if (strcmp(tokens[t0 + 8], "port") != 0) { 898 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 899 return; 900 } 901 902 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) { 903 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 904 return; 905 } 906 907 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR; 908 t0 += 10; 909 } /* filter */ 910 911 if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) { 912 uint32_t i; 913 914 if (n_tokens < t0 + 22) { 915 snprintf(out, out_size, MSG_ARG_MISMATCH, 916 "port in action profile balance"); 917 return; 918 } 919 920 if (strcmp(tokens[t0 + 1], "offset") != 0) { 921 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 922 return; 923 } 924 925 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { 926 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 927 return; 928 } 929 930 if (strcmp(tokens[t0 + 3], "mask") != 0) { 931 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 932 return; 933 } 934 935 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; 936 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) { 937 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 938 return; 939 } 940 941 if (strcmp(tokens[t0 + 5], "port") != 0) { 942 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 943 return; 944 } 945 946 for (i = 0; i < 16; i++) 947 if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) { 948 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 949 return; 950 } 951 952 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB; 953 t0 += 22; 954 } /* balance */ 955 956 if (t0 < n_tokens) { 957 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 958 return; 959 } 960 961 ap = port_in_action_profile_create(name, &p); 962 if (ap == NULL) { 963 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 964 return; 965 } 966 } 967 968 969 static const char cmd_table_action_profile_help[] = 970 "table action profile <profile_name>\n" 971 " ipv4 | ipv6\n" 972 " offset <ip_offset>\n" 973 " fwd\n" 974 " [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]\n" 975 " [meter srtcm | trtcm\n" 976 " tc <n_tc>\n" 977 " stats none | pkts | bytes | both]\n" 978 " [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]\n" 979 " [encap ether | vlan | qinq | mpls | pppoe | qinq_pppoe \n" 980 " vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off]\n" 981 " [nat src | dst\n" 982 " proto udp | tcp]\n" 983 " [ttl drop | fwd\n" 984 " stats none | pkts]\n" 985 " [stats pkts | bytes | both]\n" 986 " [time]\n" 987 " [sym_crypto dev <CRYPTODEV_NAME> offset <op_offset>]\n" 988 " [tag]\n" 989 " [decap]\n"; 990 991 static void 992 cmd_table_action_profile(char **tokens, 993 uint32_t n_tokens, 994 char *out, 995 size_t out_size) 996 { 997 struct table_action_profile_params p; 998 struct table_action_profile *ap; 999 char *name; 1000 uint32_t t0; 1001 1002 memset(&p, 0, sizeof(p)); 1003 1004 if (n_tokens < 8) { 1005 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1006 return; 1007 } 1008 1009 if (strcmp(tokens[1], "action") != 0) { 1010 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); 1011 return; 1012 } 1013 1014 if (strcmp(tokens[2], "profile") != 0) { 1015 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 1016 return; 1017 } 1018 1019 name = tokens[3]; 1020 1021 if (strcmp(tokens[4], "ipv4") == 0) 1022 p.common.ip_version = 1; 1023 else if (strcmp(tokens[4], "ipv6") == 0) 1024 p.common.ip_version = 0; 1025 else { 1026 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6"); 1027 return; 1028 } 1029 1030 if (strcmp(tokens[5], "offset") != 0) { 1031 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1032 return; 1033 } 1034 1035 if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) { 1036 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset"); 1037 return; 1038 } 1039 1040 if (strcmp(tokens[7], "fwd") != 0) { 1041 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); 1042 return; 1043 } 1044 1045 p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; 1046 1047 t0 = 8; 1048 if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) { 1049 if (n_tokens < t0 + 7) { 1050 snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance"); 1051 return; 1052 } 1053 1054 if (strcmp(tokens[t0 + 1], "offset") != 0) { 1055 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1056 return; 1057 } 1058 1059 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { 1060 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1061 return; 1062 } 1063 1064 if (strcmp(tokens[t0 + 3], "mask") != 0) { 1065 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 1066 return; 1067 } 1068 1069 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; 1070 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) { 1071 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 1072 return; 1073 } 1074 1075 if (strcmp(tokens[t0 + 5], "outoffset") != 0) { 1076 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); 1077 return; 1078 } 1079 1080 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) { 1081 snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); 1082 return; 1083 } 1084 1085 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; 1086 t0 += 7; 1087 } /* balance */ 1088 1089 if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) { 1090 if (n_tokens < t0 + 6) { 1091 snprintf(out, out_size, MSG_ARG_MISMATCH, 1092 "table action profile meter"); 1093 return; 1094 } 1095 1096 if (strcmp(tokens[t0 + 1], "srtcm") == 0) 1097 p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM; 1098 else if (strcmp(tokens[t0 + 1], "trtcm") == 0) 1099 p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM; 1100 else { 1101 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1102 "srtcm or trtcm"); 1103 return; 1104 } 1105 1106 if (strcmp(tokens[t0 + 2], "tc") != 0) { 1107 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); 1108 return; 1109 } 1110 1111 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) { 1112 snprintf(out, out_size, MSG_ARG_INVALID, "n_tc"); 1113 return; 1114 } 1115 1116 if (strcmp(tokens[t0 + 4], "stats") != 0) { 1117 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1118 return; 1119 } 1120 1121 if (strcmp(tokens[t0 + 5], "none") == 0) { 1122 p.mtr.n_packets_enabled = 0; 1123 p.mtr.n_bytes_enabled = 0; 1124 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) { 1125 p.mtr.n_packets_enabled = 1; 1126 p.mtr.n_bytes_enabled = 0; 1127 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) { 1128 p.mtr.n_packets_enabled = 0; 1129 p.mtr.n_bytes_enabled = 1; 1130 } else if (strcmp(tokens[t0 + 5], "both") == 0) { 1131 p.mtr.n_packets_enabled = 1; 1132 p.mtr.n_bytes_enabled = 1; 1133 } else { 1134 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1135 "none or pkts or bytes or both"); 1136 return; 1137 } 1138 1139 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR; 1140 t0 += 6; 1141 } /* meter */ 1142 1143 if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) { 1144 if (n_tokens < t0 + 5) { 1145 snprintf(out, out_size, MSG_ARG_MISMATCH, 1146 "table action profile tm"); 1147 return; 1148 } 1149 1150 if (strcmp(tokens[t0 + 1], "spp") != 0) { 1151 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); 1152 return; 1153 } 1154 1155 if (parser_read_uint32(&p.tm.n_subports_per_port, 1156 tokens[t0 + 2]) != 0) { 1157 snprintf(out, out_size, MSG_ARG_INVALID, 1158 "n_subports_per_port"); 1159 return; 1160 } 1161 1162 if (strcmp(tokens[t0 + 3], "pps") != 0) { 1163 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); 1164 return; 1165 } 1166 1167 if (parser_read_uint32(&p.tm.n_pipes_per_subport, 1168 tokens[t0 + 4]) != 0) { 1169 snprintf(out, out_size, MSG_ARG_INVALID, 1170 "n_pipes_per_subport"); 1171 return; 1172 } 1173 1174 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; 1175 t0 += 5; 1176 } /* tm */ 1177 1178 if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) { 1179 uint32_t n_extra_tokens = 0; 1180 1181 if (n_tokens < t0 + 2) { 1182 snprintf(out, out_size, MSG_ARG_MISMATCH, 1183 "action profile encap"); 1184 return; 1185 } 1186 1187 if (strcmp(tokens[t0 + 1], "ether") == 0) 1188 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER; 1189 else if (strcmp(tokens[t0 + 1], "vlan") == 0) 1190 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN; 1191 else if (strcmp(tokens[t0 + 1], "qinq") == 0) 1192 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ; 1193 else if (strcmp(tokens[t0 + 1], "mpls") == 0) 1194 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; 1195 else if (strcmp(tokens[t0 + 1], "pppoe") == 0) 1196 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; 1197 else if (strcmp(tokens[t0 + 1], "vxlan") == 0) { 1198 if (n_tokens < t0 + 2 + 5) { 1199 snprintf(out, out_size, MSG_ARG_MISMATCH, 1200 "action profile encap vxlan"); 1201 return; 1202 } 1203 1204 if (strcmp(tokens[t0 + 2], "offset") != 0) { 1205 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1206 "vxlan: offset"); 1207 return; 1208 } 1209 1210 if (parser_read_uint32(&p.encap.vxlan.data_offset, 1211 tokens[t0 + 2 + 1]) != 0) { 1212 snprintf(out, out_size, MSG_ARG_INVALID, 1213 "vxlan: ether_offset"); 1214 return; 1215 } 1216 1217 if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0) 1218 p.encap.vxlan.ip_version = 1; 1219 else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0) 1220 p.encap.vxlan.ip_version = 0; 1221 else { 1222 snprintf(out, out_size, MSG_ARG_INVALID, 1223 "vxlan: ipv4 or ipv6"); 1224 return; 1225 } 1226 1227 if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) { 1228 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1229 "vxlan: vlan"); 1230 return; 1231 } 1232 1233 if (strcmp(tokens[t0 + 2 + 4], "on") == 0) 1234 p.encap.vxlan.vlan = 1; 1235 else if (strcmp(tokens[t0 + 2 + 4], "off") == 0) 1236 p.encap.vxlan.vlan = 0; 1237 else { 1238 snprintf(out, out_size, MSG_ARG_INVALID, 1239 "vxlan: on or off"); 1240 return; 1241 } 1242 1243 p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN; 1244 n_extra_tokens = 5; 1245 } else if (strcmp(tokens[t0 + 1], "qinq_pppoe") == 0) 1246 p.encap.encap_mask = 1247 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ_PPPOE; 1248 else { 1249 snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); 1250 return; 1251 } 1252 1253 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; 1254 t0 += 2 + n_extra_tokens; 1255 } /* encap */ 1256 1257 if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) { 1258 if (n_tokens < t0 + 4) { 1259 snprintf(out, out_size, MSG_ARG_MISMATCH, 1260 "table action profile nat"); 1261 return; 1262 } 1263 1264 if (strcmp(tokens[t0 + 1], "src") == 0) 1265 p.nat.source_nat = 1; 1266 else if (strcmp(tokens[t0 + 1], "dst") == 0) 1267 p.nat.source_nat = 0; 1268 else { 1269 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1270 "src or dst"); 1271 return; 1272 } 1273 1274 if (strcmp(tokens[t0 + 2], "proto") != 0) { 1275 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); 1276 return; 1277 } 1278 1279 if (strcmp(tokens[t0 + 3], "tcp") == 0) 1280 p.nat.proto = 0x06; 1281 else if (strcmp(tokens[t0 + 3], "udp") == 0) 1282 p.nat.proto = 0x11; 1283 else { 1284 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1285 "tcp or udp"); 1286 return; 1287 } 1288 1289 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT; 1290 t0 += 4; 1291 } /* nat */ 1292 1293 if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) { 1294 if (n_tokens < t0 + 4) { 1295 snprintf(out, out_size, MSG_ARG_MISMATCH, 1296 "table action profile ttl"); 1297 return; 1298 } 1299 1300 if (strcmp(tokens[t0 + 1], "drop") == 0) 1301 p.ttl.drop = 1; 1302 else if (strcmp(tokens[t0 + 1], "fwd") == 0) 1303 p.ttl.drop = 0; 1304 else { 1305 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1306 "drop or fwd"); 1307 return; 1308 } 1309 1310 if (strcmp(tokens[t0 + 2], "stats") != 0) { 1311 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 1312 return; 1313 } 1314 1315 if (strcmp(tokens[t0 + 3], "none") == 0) 1316 p.ttl.n_packets_enabled = 0; 1317 else if (strcmp(tokens[t0 + 3], "pkts") == 0) 1318 p.ttl.n_packets_enabled = 1; 1319 else { 1320 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1321 "none or pkts"); 1322 return; 1323 } 1324 1325 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL; 1326 t0 += 4; 1327 } /* ttl */ 1328 1329 if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) { 1330 if (n_tokens < t0 + 2) { 1331 snprintf(out, out_size, MSG_ARG_MISMATCH, 1332 "table action profile stats"); 1333 return; 1334 } 1335 1336 if (strcmp(tokens[t0 + 1], "pkts") == 0) { 1337 p.stats.n_packets_enabled = 1; 1338 p.stats.n_bytes_enabled = 0; 1339 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) { 1340 p.stats.n_packets_enabled = 0; 1341 p.stats.n_bytes_enabled = 1; 1342 } else if (strcmp(tokens[t0 + 1], "both") == 0) { 1343 p.stats.n_packets_enabled = 1; 1344 p.stats.n_bytes_enabled = 1; 1345 } else { 1346 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1347 "pkts or bytes or both"); 1348 return; 1349 } 1350 1351 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS; 1352 t0 += 2; 1353 } /* stats */ 1354 1355 if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) { 1356 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME; 1357 t0 += 1; 1358 } /* time */ 1359 1360 if ((t0 < n_tokens) && (strcmp(tokens[t0], "sym_crypto") == 0)) { 1361 struct cryptodev *cryptodev; 1362 1363 if (n_tokens < t0 + 5 || 1364 strcmp(tokens[t0 + 1], "dev") || 1365 strcmp(tokens[t0 + 3], "offset")) { 1366 snprintf(out, out_size, MSG_ARG_MISMATCH, 1367 "table action profile sym_crypto"); 1368 return; 1369 } 1370 1371 cryptodev = cryptodev_find(tokens[t0 + 2]); 1372 if (cryptodev == NULL) { 1373 snprintf(out, out_size, MSG_ARG_INVALID, 1374 "table action profile sym_crypto"); 1375 return; 1376 } 1377 1378 p.sym_crypto.cryptodev_id = cryptodev->dev_id; 1379 1380 if (parser_read_uint32(&p.sym_crypto.op_offset, 1381 tokens[t0 + 4]) != 0) { 1382 snprintf(out, out_size, MSG_ARG_INVALID, 1383 "table action profile sym_crypto"); 1384 return; 1385 } 1386 1387 p.sym_crypto.mp_create = cryptodev->mp_create; 1388 p.sym_crypto.mp_init = cryptodev->mp_init; 1389 1390 p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO; 1391 1392 t0 += 5; 1393 } /* sym_crypto */ 1394 1395 if ((t0 < n_tokens) && (strcmp(tokens[t0], "tag") == 0)) { 1396 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG; 1397 t0 += 1; 1398 } /* tag */ 1399 1400 if ((t0 < n_tokens) && (strcmp(tokens[t0], "decap") == 0)) { 1401 p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP; 1402 t0 += 1; 1403 } /* decap */ 1404 1405 if (t0 < n_tokens) { 1406 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1407 return; 1408 } 1409 1410 ap = table_action_profile_create(name, &p); 1411 if (ap == NULL) { 1412 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1413 return; 1414 } 1415 } 1416 1417 static const char cmd_pipeline_help[] = 1418 "pipeline <pipeline_name>\n" 1419 " period <timer_period_ms>\n" 1420 " offset_port_id <offset_port_id>\n" 1421 " cpu <cpu_id>\n"; 1422 1423 static void 1424 cmd_pipeline(char **tokens, 1425 uint32_t n_tokens, 1426 char *out, 1427 size_t out_size) 1428 { 1429 struct pipeline_params p; 1430 char *name; 1431 struct pipeline *pipeline; 1432 1433 if (n_tokens != 8) { 1434 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1435 return; 1436 } 1437 1438 name = tokens[1]; 1439 1440 if (strcmp(tokens[2], "period") != 0) { 1441 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); 1442 return; 1443 } 1444 1445 if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) { 1446 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); 1447 return; 1448 } 1449 1450 if (strcmp(tokens[4], "offset_port_id") != 0) { 1451 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); 1452 return; 1453 } 1454 1455 if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) { 1456 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); 1457 return; 1458 } 1459 1460 if (strcmp(tokens[6], "cpu") != 0) { 1461 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); 1462 return; 1463 } 1464 1465 if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) { 1466 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); 1467 return; 1468 } 1469 1470 pipeline = pipeline_create(name, &p); 1471 if (pipeline == NULL) { 1472 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1473 return; 1474 } 1475 } 1476 1477 static const char cmd_pipeline_port_in_help[] = 1478 "pipeline <pipeline_name> port in\n" 1479 " bsz <burst_size>\n" 1480 " link <link_name> rxq <queue_id>\n" 1481 " | swq <swq_name>\n" 1482 " | tmgr <tmgr_name>\n" 1483 " | tap <tap_name> mempool <mempool_name> mtu <mtu>\n" 1484 " | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>\n" 1485 " | cryptodev <cryptodev_name> rxq <queue_id>\n" 1486 " [action <port_in_action_profile_name>]\n" 1487 " [disabled]\n"; 1488 1489 static void 1490 cmd_pipeline_port_in(char **tokens, 1491 uint32_t n_tokens, 1492 char *out, 1493 size_t out_size) 1494 { 1495 struct port_in_params p; 1496 char *pipeline_name; 1497 uint32_t t0; 1498 int enabled, status; 1499 1500 if (n_tokens < 7) { 1501 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1502 return; 1503 } 1504 1505 pipeline_name = tokens[1]; 1506 1507 if (strcmp(tokens[2], "port") != 0) { 1508 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1509 return; 1510 } 1511 1512 if (strcmp(tokens[3], "in") != 0) { 1513 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 1514 return; 1515 } 1516 1517 if (strcmp(tokens[4], "bsz") != 0) { 1518 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 1519 return; 1520 } 1521 1522 if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 1523 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 1524 return; 1525 } 1526 1527 t0 = 6; 1528 1529 if (strcmp(tokens[t0], "link") == 0) { 1530 if (n_tokens < t0 + 4) { 1531 snprintf(out, out_size, MSG_ARG_MISMATCH, 1532 "pipeline port in link"); 1533 return; 1534 } 1535 1536 p.type = PORT_IN_RXQ; 1537 1538 p.dev_name = tokens[t0 + 1]; 1539 1540 if (strcmp(tokens[t0 + 2], "rxq") != 0) { 1541 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); 1542 return; 1543 } 1544 1545 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) { 1546 snprintf(out, out_size, MSG_ARG_INVALID, 1547 "queue_id"); 1548 return; 1549 } 1550 t0 += 4; 1551 } else if (strcmp(tokens[t0], "swq") == 0) { 1552 if (n_tokens < t0 + 2) { 1553 snprintf(out, out_size, MSG_ARG_MISMATCH, 1554 "pipeline port in swq"); 1555 return; 1556 } 1557 1558 p.type = PORT_IN_SWQ; 1559 1560 p.dev_name = tokens[t0 + 1]; 1561 1562 t0 += 2; 1563 } else if (strcmp(tokens[t0], "tmgr") == 0) { 1564 if (n_tokens < t0 + 2) { 1565 snprintf(out, out_size, MSG_ARG_MISMATCH, 1566 "pipeline port in tmgr"); 1567 return; 1568 } 1569 1570 p.type = PORT_IN_TMGR; 1571 1572 p.dev_name = tokens[t0 + 1]; 1573 1574 t0 += 2; 1575 } else if (strcmp(tokens[t0], "tap") == 0) { 1576 if (n_tokens < t0 + 6) { 1577 snprintf(out, out_size, MSG_ARG_MISMATCH, 1578 "pipeline port in tap"); 1579 return; 1580 } 1581 1582 p.type = PORT_IN_TAP; 1583 1584 p.dev_name = tokens[t0 + 1]; 1585 1586 if (strcmp(tokens[t0 + 2], "mempool") != 0) { 1587 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1588 "mempool"); 1589 return; 1590 } 1591 1592 p.tap.mempool_name = tokens[t0 + 3]; 1593 1594 if (strcmp(tokens[t0 + 4], "mtu") != 0) { 1595 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1596 "mtu"); 1597 return; 1598 } 1599 1600 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) { 1601 snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); 1602 return; 1603 } 1604 1605 t0 += 6; 1606 } else if (strcmp(tokens[t0], "source") == 0) { 1607 if (n_tokens < t0 + 6) { 1608 snprintf(out, out_size, MSG_ARG_MISMATCH, 1609 "pipeline port in source"); 1610 return; 1611 } 1612 1613 p.type = PORT_IN_SOURCE; 1614 1615 p.dev_name = NULL; 1616 1617 if (strcmp(tokens[t0 + 1], "mempool") != 0) { 1618 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1619 "mempool"); 1620 return; 1621 } 1622 1623 p.source.mempool_name = tokens[t0 + 2]; 1624 1625 if (strcmp(tokens[t0 + 3], "file") != 0) { 1626 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1627 "file"); 1628 return; 1629 } 1630 1631 p.source.file_name = tokens[t0 + 4]; 1632 1633 if (strcmp(tokens[t0 + 5], "bpp") != 0) { 1634 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1635 "bpp"); 1636 return; 1637 } 1638 1639 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) { 1640 snprintf(out, out_size, MSG_ARG_INVALID, 1641 "n_bytes_per_pkt"); 1642 return; 1643 } 1644 1645 t0 += 7; 1646 } else if (strcmp(tokens[t0], "cryptodev") == 0) { 1647 if (n_tokens < t0 + 3) { 1648 snprintf(out, out_size, MSG_ARG_MISMATCH, 1649 "pipeline port in cryptodev"); 1650 return; 1651 } 1652 1653 p.type = PORT_IN_CRYPTODEV; 1654 1655 p.dev_name = tokens[t0 + 1]; 1656 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) { 1657 snprintf(out, out_size, MSG_ARG_INVALID, 1658 "rxq"); 1659 return; 1660 } 1661 1662 p.cryptodev.arg_callback = NULL; 1663 p.cryptodev.f_callback = NULL; 1664 1665 t0 += 4; 1666 } else { 1667 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1668 return; 1669 } 1670 1671 p.action_profile_name = NULL; 1672 if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) { 1673 if (n_tokens < t0 + 2) { 1674 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 1675 return; 1676 } 1677 1678 p.action_profile_name = tokens[t0 + 1]; 1679 1680 t0 += 2; 1681 } 1682 1683 enabled = 1; 1684 if ((n_tokens > t0) && 1685 (strcmp(tokens[t0], "disabled") == 0)) { 1686 enabled = 0; 1687 1688 t0 += 1; 1689 } 1690 1691 if (n_tokens != t0) { 1692 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1693 return; 1694 } 1695 1696 status = pipeline_port_in_create(pipeline_name, 1697 &p, enabled); 1698 if (status) { 1699 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1700 return; 1701 } 1702 } 1703 1704 static const char cmd_pipeline_port_out_help[] = 1705 "pipeline <pipeline_name> port out\n" 1706 " bsz <burst_size>\n" 1707 " link <link_name> txq <txq_id>\n" 1708 " | swq <swq_name>\n" 1709 " | tmgr <tmgr_name>\n" 1710 " | tap <tap_name>\n" 1711 " | sink [file <file_name> pkts <max_n_pkts>]\n" 1712 " | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset>\n"; 1713 1714 static void 1715 cmd_pipeline_port_out(char **tokens, 1716 uint32_t n_tokens, 1717 char *out, 1718 size_t out_size) 1719 { 1720 struct port_out_params p; 1721 char *pipeline_name; 1722 int status; 1723 1724 memset(&p, 0, sizeof(p)); 1725 1726 if (n_tokens < 7) { 1727 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1728 return; 1729 } 1730 1731 pipeline_name = tokens[1]; 1732 1733 if (strcmp(tokens[2], "port") != 0) { 1734 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 1735 return; 1736 } 1737 1738 if (strcmp(tokens[3], "out") != 0) { 1739 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 1740 return; 1741 } 1742 1743 if (strcmp(tokens[4], "bsz") != 0) { 1744 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); 1745 return; 1746 } 1747 1748 if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { 1749 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 1750 return; 1751 } 1752 1753 if (strcmp(tokens[6], "link") == 0) { 1754 if (n_tokens != 10) { 1755 snprintf(out, out_size, MSG_ARG_MISMATCH, 1756 "pipeline port out link"); 1757 return; 1758 } 1759 1760 p.type = PORT_OUT_TXQ; 1761 1762 p.dev_name = tokens[7]; 1763 1764 if (strcmp(tokens[8], "txq") != 0) { 1765 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); 1766 return; 1767 } 1768 1769 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) { 1770 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 1771 return; 1772 } 1773 } else if (strcmp(tokens[6], "swq") == 0) { 1774 if (n_tokens != 8) { 1775 snprintf(out, out_size, MSG_ARG_MISMATCH, 1776 "pipeline port out swq"); 1777 return; 1778 } 1779 1780 p.type = PORT_OUT_SWQ; 1781 1782 p.dev_name = tokens[7]; 1783 } else if (strcmp(tokens[6], "tmgr") == 0) { 1784 if (n_tokens != 8) { 1785 snprintf(out, out_size, MSG_ARG_MISMATCH, 1786 "pipeline port out tmgr"); 1787 return; 1788 } 1789 1790 p.type = PORT_OUT_TMGR; 1791 1792 p.dev_name = tokens[7]; 1793 } else if (strcmp(tokens[6], "tap") == 0) { 1794 if (n_tokens != 8) { 1795 snprintf(out, out_size, MSG_ARG_MISMATCH, 1796 "pipeline port out tap"); 1797 return; 1798 } 1799 1800 p.type = PORT_OUT_TAP; 1801 1802 p.dev_name = tokens[7]; 1803 } else if (strcmp(tokens[6], "sink") == 0) { 1804 if ((n_tokens != 7) && (n_tokens != 11)) { 1805 snprintf(out, out_size, MSG_ARG_MISMATCH, 1806 "pipeline port out sink"); 1807 return; 1808 } 1809 1810 p.type = PORT_OUT_SINK; 1811 1812 p.dev_name = NULL; 1813 1814 if (n_tokens == 7) { 1815 p.sink.file_name = NULL; 1816 p.sink.max_n_pkts = 0; 1817 } else { 1818 if (strcmp(tokens[7], "file") != 0) { 1819 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1820 "file"); 1821 return; 1822 } 1823 1824 p.sink.file_name = tokens[8]; 1825 1826 if (strcmp(tokens[9], "pkts") != 0) { 1827 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); 1828 return; 1829 } 1830 1831 if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) { 1832 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); 1833 return; 1834 } 1835 } 1836 1837 } else if (strcmp(tokens[6], "cryptodev") == 0) { 1838 if (n_tokens != 12) { 1839 snprintf(out, out_size, MSG_ARG_MISMATCH, 1840 "pipeline port out cryptodev"); 1841 return; 1842 } 1843 1844 p.type = PORT_OUT_CRYPTODEV; 1845 1846 p.dev_name = tokens[7]; 1847 1848 if (strcmp(tokens[8], "txq")) { 1849 snprintf(out, out_size, MSG_ARG_MISMATCH, 1850 "pipeline port out cryptodev"); 1851 return; 1852 } 1853 1854 if (parser_read_uint16(&p.cryptodev.queue_id, tokens[9]) 1855 != 0) { 1856 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 1857 return; 1858 } 1859 1860 if (strcmp(tokens[10], "offset")) { 1861 snprintf(out, out_size, MSG_ARG_MISMATCH, 1862 "pipeline port out cryptodev"); 1863 return; 1864 } 1865 1866 if (parser_read_uint32(&p.cryptodev.op_offset, tokens[11]) 1867 != 0) { 1868 snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); 1869 return; 1870 } 1871 } else { 1872 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 1873 return; 1874 } 1875 1876 status = pipeline_port_out_create(pipeline_name, &p); 1877 if (status) { 1878 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 1879 return; 1880 } 1881 } 1882 1883 static const char cmd_pipeline_table_help[] = 1884 "pipeline <pipeline_name> table\n" 1885 " match\n" 1886 " acl\n" 1887 " ipv4 | ipv6\n" 1888 " offset <ip_header_offset>\n" 1889 " size <n_rules>\n" 1890 " | array\n" 1891 " offset <key_offset>\n" 1892 " size <n_keys>\n" 1893 " | hash\n" 1894 " ext | lru\n" 1895 " key <key_size>\n" 1896 " mask <key_mask>\n" 1897 " offset <key_offset>\n" 1898 " buckets <n_buckets>\n" 1899 " size <n_keys>\n" 1900 " | lpm\n" 1901 " ipv4 | ipv6\n" 1902 " offset <ip_header_offset>\n" 1903 " size <n_rules>\n" 1904 " | stub\n" 1905 " [action <table_action_profile_name>]\n"; 1906 1907 static void 1908 cmd_pipeline_table(char **tokens, 1909 uint32_t n_tokens, 1910 char *out, 1911 size_t out_size) 1912 { 1913 uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; 1914 struct table_params p; 1915 char *pipeline_name; 1916 uint32_t t0; 1917 int status; 1918 1919 if (n_tokens < 5) { 1920 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 1921 return; 1922 } 1923 1924 pipeline_name = tokens[1]; 1925 1926 if (strcmp(tokens[2], "table") != 0) { 1927 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 1928 return; 1929 } 1930 1931 if (strcmp(tokens[3], "match") != 0) { 1932 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 1933 return; 1934 } 1935 1936 t0 = 4; 1937 if (strcmp(tokens[t0], "acl") == 0) { 1938 if (n_tokens < t0 + 6) { 1939 snprintf(out, out_size, MSG_ARG_MISMATCH, 1940 "pipeline table acl"); 1941 return; 1942 } 1943 1944 p.match_type = TABLE_ACL; 1945 1946 if (strcmp(tokens[t0 + 1], "ipv4") == 0) 1947 p.match.acl.ip_version = 1; 1948 else if (strcmp(tokens[t0 + 1], "ipv6") == 0) 1949 p.match.acl.ip_version = 0; 1950 else { 1951 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 1952 "ipv4 or ipv6"); 1953 return; 1954 } 1955 1956 if (strcmp(tokens[t0 + 2], "offset") != 0) { 1957 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1958 return; 1959 } 1960 1961 if (parser_read_uint32(&p.match.acl.ip_header_offset, 1962 tokens[t0 + 3]) != 0) { 1963 snprintf(out, out_size, MSG_ARG_INVALID, 1964 "ip_header_offset"); 1965 return; 1966 } 1967 1968 if (strcmp(tokens[t0 + 4], "size") != 0) { 1969 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 1970 return; 1971 } 1972 1973 if (parser_read_uint32(&p.match.acl.n_rules, 1974 tokens[t0 + 5]) != 0) { 1975 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 1976 return; 1977 } 1978 1979 t0 += 6; 1980 } else if (strcmp(tokens[t0], "array") == 0) { 1981 if (n_tokens < t0 + 5) { 1982 snprintf(out, out_size, MSG_ARG_MISMATCH, 1983 "pipeline table array"); 1984 return; 1985 } 1986 1987 p.match_type = TABLE_ARRAY; 1988 1989 if (strcmp(tokens[t0 + 1], "offset") != 0) { 1990 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 1991 return; 1992 } 1993 1994 if (parser_read_uint32(&p.match.array.key_offset, 1995 tokens[t0 + 2]) != 0) { 1996 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 1997 return; 1998 } 1999 2000 if (strcmp(tokens[t0 + 3], "size") != 0) { 2001 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2002 return; 2003 } 2004 2005 if (parser_read_uint32(&p.match.array.n_keys, 2006 tokens[t0 + 4]) != 0) { 2007 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 2008 return; 2009 } 2010 2011 t0 += 5; 2012 } else if (strcmp(tokens[t0], "hash") == 0) { 2013 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; 2014 2015 if (n_tokens < t0 + 12) { 2016 snprintf(out, out_size, MSG_ARG_MISMATCH, 2017 "pipeline table hash"); 2018 return; 2019 } 2020 2021 p.match_type = TABLE_HASH; 2022 2023 if (strcmp(tokens[t0 + 1], "ext") == 0) 2024 p.match.hash.extendable_bucket = 1; 2025 else if (strcmp(tokens[t0 + 1], "lru") == 0) 2026 p.match.hash.extendable_bucket = 0; 2027 else { 2028 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2029 "ext or lru"); 2030 return; 2031 } 2032 2033 if (strcmp(tokens[t0 + 2], "key") != 0) { 2034 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 2035 return; 2036 } 2037 2038 if ((parser_read_uint32(&p.match.hash.key_size, 2039 tokens[t0 + 3]) != 0) || 2040 (p.match.hash.key_size == 0) || 2041 (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) { 2042 snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); 2043 return; 2044 } 2045 2046 if (strcmp(tokens[t0 + 4], "mask") != 0) { 2047 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 2048 return; 2049 } 2050 2051 if ((parse_hex_string(tokens[t0 + 5], 2052 key_mask, &key_mask_size) != 0) || 2053 (key_mask_size != p.match.hash.key_size)) { 2054 snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); 2055 return; 2056 } 2057 p.match.hash.key_mask = key_mask; 2058 2059 if (strcmp(tokens[t0 + 6], "offset") != 0) { 2060 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2061 return; 2062 } 2063 2064 if (parser_read_uint32(&p.match.hash.key_offset, 2065 tokens[t0 + 7]) != 0) { 2066 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2067 return; 2068 } 2069 2070 if (strcmp(tokens[t0 + 8], "buckets") != 0) { 2071 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); 2072 return; 2073 } 2074 2075 if (parser_read_uint32(&p.match.hash.n_buckets, 2076 tokens[t0 + 9]) != 0) { 2077 snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); 2078 return; 2079 } 2080 2081 if (strcmp(tokens[t0 + 10], "size") != 0) { 2082 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2083 return; 2084 } 2085 2086 if (parser_read_uint32(&p.match.hash.n_keys, 2087 tokens[t0 + 11]) != 0) { 2088 snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 2089 return; 2090 } 2091 2092 t0 += 12; 2093 } else if (strcmp(tokens[t0], "lpm") == 0) { 2094 if (n_tokens < t0 + 6) { 2095 snprintf(out, out_size, MSG_ARG_MISMATCH, 2096 "pipeline table lpm"); 2097 return; 2098 } 2099 2100 p.match_type = TABLE_LPM; 2101 2102 if (strcmp(tokens[t0 + 1], "ipv4") == 0) 2103 p.match.lpm.key_size = 4; 2104 else if (strcmp(tokens[t0 + 1], "ipv6") == 0) 2105 p.match.lpm.key_size = 16; 2106 else { 2107 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2108 "ipv4 or ipv6"); 2109 return; 2110 } 2111 2112 if (strcmp(tokens[t0 + 2], "offset") != 0) { 2113 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 2114 return; 2115 } 2116 2117 if (parser_read_uint32(&p.match.lpm.key_offset, 2118 tokens[t0 + 3]) != 0) { 2119 snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); 2120 return; 2121 } 2122 2123 if (strcmp(tokens[t0 + 4], "size") != 0) { 2124 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 2125 return; 2126 } 2127 2128 if (parser_read_uint32(&p.match.lpm.n_rules, 2129 tokens[t0 + 5]) != 0) { 2130 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 2131 return; 2132 } 2133 2134 t0 += 6; 2135 } else if (strcmp(tokens[t0], "stub") == 0) { 2136 p.match_type = TABLE_STUB; 2137 2138 t0 += 1; 2139 } else { 2140 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 2141 return; 2142 } 2143 2144 p.action_profile_name = NULL; 2145 if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) { 2146 if (n_tokens < t0 + 2) { 2147 snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); 2148 return; 2149 } 2150 2151 p.action_profile_name = tokens[t0 + 1]; 2152 2153 t0 += 2; 2154 } 2155 2156 if (n_tokens > t0) { 2157 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2158 return; 2159 } 2160 2161 status = pipeline_table_create(pipeline_name, &p); 2162 if (status) { 2163 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2164 return; 2165 } 2166 } 2167 2168 static const char cmd_pipeline_port_in_table_help[] = 2169 "pipeline <pipeline_name> port in <port_id> table <table_id>\n"; 2170 2171 static void 2172 cmd_pipeline_port_in_table(char **tokens, 2173 uint32_t n_tokens, 2174 char *out, 2175 size_t out_size) 2176 { 2177 char *pipeline_name; 2178 uint32_t port_id, table_id; 2179 int status; 2180 2181 if (n_tokens != 7) { 2182 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2183 return; 2184 } 2185 2186 pipeline_name = tokens[1]; 2187 2188 if (strcmp(tokens[2], "port") != 0) { 2189 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2190 return; 2191 } 2192 2193 if (strcmp(tokens[3], "in") != 0) { 2194 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2195 return; 2196 } 2197 2198 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2199 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2200 return; 2201 } 2202 2203 if (strcmp(tokens[5], "table") != 0) { 2204 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 2205 return; 2206 } 2207 2208 if (parser_read_uint32(&table_id, tokens[6]) != 0) { 2209 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2210 return; 2211 } 2212 2213 status = pipeline_port_in_connect_to_table(pipeline_name, 2214 port_id, 2215 table_id); 2216 if (status) { 2217 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2218 return; 2219 } 2220 } 2221 2222 2223 static const char cmd_pipeline_port_in_stats_help[] = 2224 "pipeline <pipeline_name> port in <port_id> stats read [clear]\n"; 2225 2226 #define MSG_PIPELINE_PORT_IN_STATS \ 2227 "Pkts in: %" PRIu64 "\n" \ 2228 "Pkts dropped by AH: %" PRIu64 "\n" \ 2229 "Pkts dropped by other: %" PRIu64 "\n" 2230 2231 static void 2232 cmd_pipeline_port_in_stats(char **tokens, 2233 uint32_t n_tokens, 2234 char *out, 2235 size_t out_size) 2236 { 2237 struct rte_pipeline_port_in_stats stats; 2238 char *pipeline_name; 2239 uint32_t port_id; 2240 int clear, status; 2241 2242 if ((n_tokens != 7) && (n_tokens != 8)) { 2243 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2244 return; 2245 } 2246 2247 pipeline_name = tokens[1]; 2248 2249 if (strcmp(tokens[2], "port") != 0) { 2250 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2251 return; 2252 } 2253 2254 if (strcmp(tokens[3], "in") != 0) { 2255 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2256 return; 2257 } 2258 2259 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2260 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2261 return; 2262 } 2263 2264 if (strcmp(tokens[5], "stats") != 0) { 2265 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2266 return; 2267 } 2268 2269 if (strcmp(tokens[6], "read") != 0) { 2270 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2271 return; 2272 } 2273 2274 clear = 0; 2275 if (n_tokens == 8) { 2276 if (strcmp(tokens[7], "clear") != 0) { 2277 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2278 return; 2279 } 2280 2281 clear = 1; 2282 } 2283 2284 status = pipeline_port_in_stats_read(pipeline_name, 2285 port_id, 2286 &stats, 2287 clear); 2288 if (status) { 2289 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2290 return; 2291 } 2292 2293 snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, 2294 stats.stats.n_pkts_in, 2295 stats.n_pkts_dropped_by_ah, 2296 stats.stats.n_pkts_drop); 2297 } 2298 2299 2300 static const char cmd_pipeline_port_in_enable_help[] = 2301 "pipeline <pipeline_name> port in <port_id> enable\n"; 2302 2303 static void 2304 cmd_pipeline_port_in_enable(char **tokens, 2305 uint32_t n_tokens, 2306 char *out, 2307 size_t out_size) 2308 { 2309 char *pipeline_name; 2310 uint32_t port_id; 2311 int status; 2312 2313 if (n_tokens != 6) { 2314 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2315 return; 2316 } 2317 2318 pipeline_name = tokens[1]; 2319 2320 if (strcmp(tokens[2], "port") != 0) { 2321 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2322 return; 2323 } 2324 2325 if (strcmp(tokens[3], "in") != 0) { 2326 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2327 return; 2328 } 2329 2330 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2331 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2332 return; 2333 } 2334 2335 if (strcmp(tokens[5], "enable") != 0) { 2336 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 2337 return; 2338 } 2339 2340 status = pipeline_port_in_enable(pipeline_name, port_id); 2341 if (status) { 2342 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2343 return; 2344 } 2345 } 2346 2347 2348 static const char cmd_pipeline_port_in_disable_help[] = 2349 "pipeline <pipeline_name> port in <port_id> disable\n"; 2350 2351 static void 2352 cmd_pipeline_port_in_disable(char **tokens, 2353 uint32_t n_tokens, 2354 char *out, 2355 size_t out_size) 2356 { 2357 char *pipeline_name; 2358 uint32_t port_id; 2359 int status; 2360 2361 if (n_tokens != 6) { 2362 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2363 return; 2364 } 2365 2366 pipeline_name = tokens[1]; 2367 2368 if (strcmp(tokens[2], "port") != 0) { 2369 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2370 return; 2371 } 2372 2373 if (strcmp(tokens[3], "in") != 0) { 2374 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); 2375 return; 2376 } 2377 2378 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2379 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2380 return; 2381 } 2382 2383 if (strcmp(tokens[5], "disable") != 0) { 2384 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 2385 return; 2386 } 2387 2388 status = pipeline_port_in_disable(pipeline_name, port_id); 2389 if (status) { 2390 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2391 return; 2392 } 2393 } 2394 2395 2396 static const char cmd_pipeline_port_out_stats_help[] = 2397 "pipeline <pipeline_name> port out <port_id> stats read [clear]\n"; 2398 2399 #define MSG_PIPELINE_PORT_OUT_STATS \ 2400 "Pkts in: %" PRIu64 "\n" \ 2401 "Pkts dropped by AH: %" PRIu64 "\n" \ 2402 "Pkts dropped by other: %" PRIu64 "\n" 2403 2404 static void 2405 cmd_pipeline_port_out_stats(char **tokens, 2406 uint32_t n_tokens, 2407 char *out, 2408 size_t out_size) 2409 { 2410 struct rte_pipeline_port_out_stats stats; 2411 char *pipeline_name; 2412 uint32_t port_id; 2413 int clear, status; 2414 2415 if ((n_tokens != 7) && (n_tokens != 8)) { 2416 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2417 return; 2418 } 2419 2420 pipeline_name = tokens[1]; 2421 2422 if (strcmp(tokens[2], "port") != 0) { 2423 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2424 return; 2425 } 2426 2427 if (strcmp(tokens[3], "out") != 0) { 2428 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); 2429 return; 2430 } 2431 2432 if (parser_read_uint32(&port_id, tokens[4]) != 0) { 2433 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 2434 return; 2435 } 2436 2437 if (strcmp(tokens[5], "stats") != 0) { 2438 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2439 return; 2440 } 2441 2442 if (strcmp(tokens[6], "read") != 0) { 2443 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2444 return; 2445 } 2446 2447 clear = 0; 2448 if (n_tokens == 8) { 2449 if (strcmp(tokens[7], "clear") != 0) { 2450 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2451 return; 2452 } 2453 2454 clear = 1; 2455 } 2456 2457 status = pipeline_port_out_stats_read(pipeline_name, 2458 port_id, 2459 &stats, 2460 clear); 2461 if (status) { 2462 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2463 return; 2464 } 2465 2466 snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, 2467 stats.stats.n_pkts_in, 2468 stats.n_pkts_dropped_by_ah, 2469 stats.stats.n_pkts_drop); 2470 } 2471 2472 2473 static const char cmd_pipeline_table_stats_help[] = 2474 "pipeline <pipeline_name> table <table_id> stats read [clear]\n"; 2475 2476 #define MSG_PIPELINE_TABLE_STATS \ 2477 "Pkts in: %" PRIu64 "\n" \ 2478 "Pkts in with lookup miss: %" PRIu64 "\n" \ 2479 "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ 2480 "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ 2481 "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ 2482 "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" 2483 2484 static void 2485 cmd_pipeline_table_stats(char **tokens, 2486 uint32_t n_tokens, 2487 char *out, 2488 size_t out_size) 2489 { 2490 struct rte_pipeline_table_stats stats; 2491 char *pipeline_name; 2492 uint32_t table_id; 2493 int clear, status; 2494 2495 if ((n_tokens != 6) && (n_tokens != 7)) { 2496 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2497 return; 2498 } 2499 2500 pipeline_name = tokens[1]; 2501 2502 if (strcmp(tokens[2], "table") != 0) { 2503 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 2504 return; 2505 } 2506 2507 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 2508 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 2509 return; 2510 } 2511 2512 if (strcmp(tokens[4], "stats") != 0) { 2513 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 2514 return; 2515 } 2516 2517 if (strcmp(tokens[5], "read") != 0) { 2518 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 2519 return; 2520 } 2521 2522 clear = 0; 2523 if (n_tokens == 7) { 2524 if (strcmp(tokens[6], "clear") != 0) { 2525 snprintf(out, out_size, MSG_ARG_INVALID, "clear"); 2526 return; 2527 } 2528 2529 clear = 1; 2530 } 2531 2532 status = pipeline_table_stats_read(pipeline_name, 2533 table_id, 2534 &stats, 2535 clear); 2536 if (status) { 2537 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 2538 return; 2539 } 2540 2541 snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, 2542 stats.stats.n_pkts_in, 2543 stats.stats.n_pkts_lookup_miss, 2544 stats.n_pkts_dropped_by_lkp_hit_ah, 2545 stats.n_pkts_dropped_lkp_hit, 2546 stats.n_pkts_dropped_by_lkp_miss_ah, 2547 stats.n_pkts_dropped_lkp_miss); 2548 } 2549 2550 /** 2551 * <match> ::= 2552 * 2553 * match 2554 * acl 2555 * priority <priority> 2556 * ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth> 2557 * <sp0> <sp1> <dp0> <dp1> <proto> 2558 * | array <pos> 2559 * | hash 2560 * raw <key> 2561 * | ipv4_5tuple <sa> <da> <sp> <dp> <proto> 2562 * | ipv6_5tuple <sa> <da> <sp> <dp> <proto> 2563 * | ipv4_addr <addr> 2564 * | ipv6_addr <addr> 2565 * | qinq <svlan> <cvlan> 2566 * | lpm 2567 * ipv4 | ipv6 <addr> <depth> 2568 */ 2569 struct pkt_key_qinq { 2570 uint16_t ethertype_svlan; 2571 uint16_t svlan; 2572 uint16_t ethertype_cvlan; 2573 uint16_t cvlan; 2574 } __rte_packed; 2575 2576 struct pkt_key_ipv4_5tuple { 2577 uint8_t time_to_live; 2578 uint8_t proto; 2579 uint16_t hdr_checksum; 2580 uint32_t sa; 2581 uint32_t da; 2582 uint16_t sp; 2583 uint16_t dp; 2584 } __rte_packed; 2585 2586 struct pkt_key_ipv6_5tuple { 2587 uint16_t payload_length; 2588 uint8_t proto; 2589 uint8_t hop_limit; 2590 uint8_t sa[16]; 2591 uint8_t da[16]; 2592 uint16_t sp; 2593 uint16_t dp; 2594 } __rte_packed; 2595 2596 struct pkt_key_ipv4_addr { 2597 uint32_t addr; 2598 } __rte_packed; 2599 2600 struct pkt_key_ipv6_addr { 2601 uint8_t addr[16]; 2602 } __rte_packed; 2603 2604 static uint32_t 2605 parse_match(char **tokens, 2606 uint32_t n_tokens, 2607 char *out, 2608 size_t out_size, 2609 struct table_rule_match *m) 2610 { 2611 memset(m, 0, sizeof(*m)); 2612 2613 if (n_tokens < 2) 2614 return 0; 2615 2616 if (strcmp(tokens[0], "match") != 0) { 2617 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 2618 return 0; 2619 } 2620 2621 if (strcmp(tokens[1], "acl") == 0) { 2622 if (n_tokens < 14) { 2623 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2624 return 0; 2625 } 2626 2627 m->match_type = TABLE_ACL; 2628 2629 if (strcmp(tokens[2], "priority") != 0) { 2630 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); 2631 return 0; 2632 } 2633 2634 if (parser_read_uint32(&m->match.acl.priority, 2635 tokens[3]) != 0) { 2636 snprintf(out, out_size, MSG_ARG_INVALID, "priority"); 2637 return 0; 2638 } 2639 2640 if (strcmp(tokens[4], "ipv4") == 0) { 2641 struct in_addr saddr, daddr; 2642 2643 m->match.acl.ip_version = 1; 2644 2645 if (parse_ipv4_addr(tokens[5], &saddr) != 0) { 2646 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2647 return 0; 2648 } 2649 m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); 2650 2651 if (parse_ipv4_addr(tokens[7], &daddr) != 0) { 2652 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2653 return 0; 2654 } 2655 m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); 2656 } else if (strcmp(tokens[4], "ipv6") == 0) { 2657 struct in6_addr saddr, daddr; 2658 2659 m->match.acl.ip_version = 0; 2660 2661 if (parse_ipv6_addr(tokens[5], &saddr) != 0) { 2662 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2663 return 0; 2664 } 2665 memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); 2666 2667 if (parse_ipv6_addr(tokens[7], &daddr) != 0) { 2668 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2669 return 0; 2670 } 2671 memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); 2672 } else { 2673 snprintf(out, out_size, MSG_ARG_NOT_FOUND, 2674 "ipv4 or ipv6"); 2675 return 0; 2676 } 2677 2678 if (parser_read_uint32(&m->match.acl.sa_depth, 2679 tokens[6]) != 0) { 2680 snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); 2681 return 0; 2682 } 2683 2684 if (parser_read_uint32(&m->match.acl.da_depth, 2685 tokens[8]) != 0) { 2686 snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); 2687 return 0; 2688 } 2689 2690 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { 2691 snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); 2692 return 0; 2693 } 2694 2695 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { 2696 snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); 2697 return 0; 2698 } 2699 2700 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { 2701 snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); 2702 return 0; 2703 } 2704 2705 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { 2706 snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); 2707 return 0; 2708 } 2709 2710 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { 2711 snprintf(out, out_size, MSG_ARG_INVALID, "proto"); 2712 return 0; 2713 } 2714 2715 m->match.acl.proto_mask = 0xff; 2716 2717 return 14; 2718 } /* acl */ 2719 2720 if (strcmp(tokens[1], "array") == 0) { 2721 if (n_tokens < 3) { 2722 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2723 return 0; 2724 } 2725 2726 m->match_type = TABLE_ARRAY; 2727 2728 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { 2729 snprintf(out, out_size, MSG_ARG_INVALID, "pos"); 2730 return 0; 2731 } 2732 2733 return 3; 2734 } /* array */ 2735 2736 if (strcmp(tokens[1], "hash") == 0) { 2737 if (n_tokens < 3) { 2738 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2739 return 0; 2740 } 2741 2742 m->match_type = TABLE_HASH; 2743 2744 if (strcmp(tokens[2], "raw") == 0) { 2745 uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; 2746 2747 if (n_tokens < 4) { 2748 snprintf(out, out_size, MSG_ARG_MISMATCH, 2749 tokens[0]); 2750 return 0; 2751 } 2752 2753 if (parse_hex_string(tokens[3], 2754 m->match.hash.key, &key_size) != 0) { 2755 snprintf(out, out_size, MSG_ARG_INVALID, "key"); 2756 return 0; 2757 } 2758 2759 return 4; 2760 } /* hash raw */ 2761 2762 if (strcmp(tokens[2], "ipv4_5tuple") == 0) { 2763 struct pkt_key_ipv4_5tuple *ipv4 = 2764 (struct pkt_key_ipv4_5tuple *) m->match.hash.key; 2765 struct in_addr saddr, daddr; 2766 uint16_t sp, dp; 2767 uint8_t proto; 2768 2769 if (n_tokens < 8) { 2770 snprintf(out, out_size, MSG_ARG_MISMATCH, 2771 tokens[0]); 2772 return 0; 2773 } 2774 2775 if (parse_ipv4_addr(tokens[3], &saddr) != 0) { 2776 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2777 return 0; 2778 } 2779 2780 if (parse_ipv4_addr(tokens[4], &daddr) != 0) { 2781 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2782 return 0; 2783 } 2784 2785 if (parser_read_uint16(&sp, tokens[5]) != 0) { 2786 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 2787 return 0; 2788 } 2789 2790 if (parser_read_uint16(&dp, tokens[6]) != 0) { 2791 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 2792 return 0; 2793 } 2794 2795 if (parser_read_uint8(&proto, tokens[7]) != 0) { 2796 snprintf(out, out_size, MSG_ARG_INVALID, 2797 "proto"); 2798 return 0; 2799 } 2800 2801 ipv4->sa = saddr.s_addr; 2802 ipv4->da = daddr.s_addr; 2803 ipv4->sp = rte_cpu_to_be_16(sp); 2804 ipv4->dp = rte_cpu_to_be_16(dp); 2805 ipv4->proto = proto; 2806 2807 return 8; 2808 } /* hash ipv4_5tuple */ 2809 2810 if (strcmp(tokens[2], "ipv6_5tuple") == 0) { 2811 struct pkt_key_ipv6_5tuple *ipv6 = 2812 (struct pkt_key_ipv6_5tuple *) m->match.hash.key; 2813 struct in6_addr saddr, daddr; 2814 uint16_t sp, dp; 2815 uint8_t proto; 2816 2817 if (n_tokens < 8) { 2818 snprintf(out, out_size, MSG_ARG_MISMATCH, 2819 tokens[0]); 2820 return 0; 2821 } 2822 2823 if (parse_ipv6_addr(tokens[3], &saddr) != 0) { 2824 snprintf(out, out_size, MSG_ARG_INVALID, "sa"); 2825 return 0; 2826 } 2827 2828 if (parse_ipv6_addr(tokens[4], &daddr) != 0) { 2829 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2830 return 0; 2831 } 2832 2833 if (parser_read_uint16(&sp, tokens[5]) != 0) { 2834 snprintf(out, out_size, MSG_ARG_INVALID, "sp"); 2835 return 0; 2836 } 2837 2838 if (parser_read_uint16(&dp, tokens[6]) != 0) { 2839 snprintf(out, out_size, MSG_ARG_INVALID, "dp"); 2840 return 0; 2841 } 2842 2843 if (parser_read_uint8(&proto, tokens[7]) != 0) { 2844 snprintf(out, out_size, MSG_ARG_INVALID, 2845 "proto"); 2846 return 0; 2847 } 2848 2849 memcpy(ipv6->sa, saddr.s6_addr, 16); 2850 memcpy(ipv6->da, daddr.s6_addr, 16); 2851 ipv6->sp = rte_cpu_to_be_16(sp); 2852 ipv6->dp = rte_cpu_to_be_16(dp); 2853 ipv6->proto = proto; 2854 2855 return 8; 2856 } /* hash ipv6_5tuple */ 2857 2858 if (strcmp(tokens[2], "ipv4_addr") == 0) { 2859 struct pkt_key_ipv4_addr *ipv4_addr = 2860 (struct pkt_key_ipv4_addr *) m->match.hash.key; 2861 struct in_addr addr; 2862 2863 if (n_tokens < 4) { 2864 snprintf(out, out_size, MSG_ARG_MISMATCH, 2865 tokens[0]); 2866 return 0; 2867 } 2868 2869 if (parse_ipv4_addr(tokens[3], &addr) != 0) { 2870 snprintf(out, out_size, MSG_ARG_INVALID, 2871 "addr"); 2872 return 0; 2873 } 2874 2875 ipv4_addr->addr = addr.s_addr; 2876 2877 return 4; 2878 } /* hash ipv4_addr */ 2879 2880 if (strcmp(tokens[2], "ipv6_addr") == 0) { 2881 struct pkt_key_ipv6_addr *ipv6_addr = 2882 (struct pkt_key_ipv6_addr *) m->match.hash.key; 2883 struct in6_addr addr; 2884 2885 if (n_tokens < 4) { 2886 snprintf(out, out_size, MSG_ARG_MISMATCH, 2887 tokens[0]); 2888 return 0; 2889 } 2890 2891 if (parse_ipv6_addr(tokens[3], &addr) != 0) { 2892 snprintf(out, out_size, MSG_ARG_INVALID, 2893 "addr"); 2894 return 0; 2895 } 2896 2897 memcpy(ipv6_addr->addr, addr.s6_addr, 16); 2898 2899 return 4; 2900 } /* hash ipv6_5tuple */ 2901 2902 if (strcmp(tokens[2], "qinq") == 0) { 2903 struct pkt_key_qinq *qinq = 2904 (struct pkt_key_qinq *) m->match.hash.key; 2905 uint16_t svlan, cvlan; 2906 2907 if (n_tokens < 5) { 2908 snprintf(out, out_size, MSG_ARG_MISMATCH, 2909 tokens[0]); 2910 return 0; 2911 } 2912 2913 if ((parser_read_uint16(&svlan, tokens[3]) != 0) || 2914 (svlan > 0xFFF)) { 2915 snprintf(out, out_size, MSG_ARG_INVALID, 2916 "svlan"); 2917 return 0; 2918 } 2919 2920 if ((parser_read_uint16(&cvlan, tokens[4]) != 0) || 2921 (cvlan > 0xFFF)) { 2922 snprintf(out, out_size, MSG_ARG_INVALID, 2923 "cvlan"); 2924 return 0; 2925 } 2926 2927 qinq->svlan = rte_cpu_to_be_16(svlan); 2928 qinq->cvlan = rte_cpu_to_be_16(cvlan); 2929 2930 return 5; 2931 } /* hash qinq */ 2932 2933 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2934 return 0; 2935 } /* hash */ 2936 2937 if (strcmp(tokens[1], "lpm") == 0) { 2938 if (n_tokens < 5) { 2939 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 2940 return 0; 2941 } 2942 2943 m->match_type = TABLE_LPM; 2944 2945 if (strcmp(tokens[2], "ipv4") == 0) { 2946 struct in_addr addr; 2947 2948 m->match.lpm.ip_version = 1; 2949 2950 if (parse_ipv4_addr(tokens[3], &addr) != 0) { 2951 snprintf(out, out_size, MSG_ARG_INVALID, 2952 "addr"); 2953 return 0; 2954 } 2955 2956 m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr); 2957 } else if (strcmp(tokens[2], "ipv6") == 0) { 2958 struct in6_addr addr; 2959 2960 m->match.lpm.ip_version = 0; 2961 2962 if (parse_ipv6_addr(tokens[3], &addr) != 0) { 2963 snprintf(out, out_size, MSG_ARG_INVALID, 2964 "addr"); 2965 return 0; 2966 } 2967 2968 memcpy(m->match.lpm.ipv6, addr.s6_addr, 16); 2969 } else { 2970 snprintf(out, out_size, MSG_ARG_MISMATCH, 2971 "ipv4 or ipv6"); 2972 return 0; 2973 } 2974 2975 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) { 2976 snprintf(out, out_size, MSG_ARG_INVALID, "depth"); 2977 return 0; 2978 } 2979 2980 return 5; 2981 } /* lpm */ 2982 2983 snprintf(out, out_size, MSG_ARG_MISMATCH, 2984 "acl or array or hash or lpm"); 2985 return 0; 2986 } 2987 2988 /** 2989 * table_action ::= 2990 * 2991 * action 2992 * fwd 2993 * drop 2994 * | port <port_id> 2995 * | meta 2996 * | table <table_id> 2997 * [balance <out0> ... <out7>] 2998 * [meter 2999 * tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3000 * [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3001 * tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa> 3002 * tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]] 3003 * [tm subport <subport_id> pipe <pipe_id>] 3004 * [encap 3005 * ether <da> <sa> 3006 * | vlan <da> <sa> <pcp> <dei> <vid> 3007 * | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid> 3008 * | qinq_pppoe <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid> <session_id> 3009 * | mpls unicast | multicast 3010 * <da> <sa> 3011 * label0 <label> <tc> <ttl> 3012 * [label1 <label> <tc> <ttl> 3013 * [label2 <label> <tc> <ttl> 3014 * [label3 <label> <tc> <ttl>]]] 3015 * | pppoe <da> <sa> <session_id> 3016 * | vxlan ether <da> <sa> 3017 * [vlan <pcp> <dei> <vid>] 3018 * ipv4 <sa> <da> <dscp> <ttl> 3019 * | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> 3020 * udp <sp> <dp> 3021 * vxlan <vni>] 3022 * [nat ipv4 | ipv6 <addr> <port>] 3023 * [ttl dec | keep] 3024 * [stats] 3025 * [time] 3026 * [sym_crypto 3027 * encrypt | decrypt 3028 * type 3029 * | cipher 3030 * cipher_algo <algo> cipher_key <key> cipher_iv <iv> 3031 * | cipher_auth 3032 * cipher_algo <algo> cipher_key <key> cipher_iv <iv> 3033 * auth_algo <algo> auth_key <key> digest_size <size> 3034 * | aead 3035 * aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad> 3036 * digest_size <size> 3037 * data_offset <data_offset>] 3038 * [tag <tag>] 3039 * [decap <n>] 3040 * 3041 * where: 3042 * <pa> ::= g | y | r | drop 3043 */ 3044 static uint32_t 3045 parse_table_action_fwd(char **tokens, 3046 uint32_t n_tokens, 3047 struct table_rule_action *a) 3048 { 3049 if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0)) 3050 return 0; 3051 3052 tokens++; 3053 n_tokens--; 3054 3055 if (n_tokens && (strcmp(tokens[0], "drop") == 0)) { 3056 a->fwd.action = RTE_PIPELINE_ACTION_DROP; 3057 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3058 return 1 + 1; 3059 } 3060 3061 if (n_tokens && (strcmp(tokens[0], "port") == 0)) { 3062 uint32_t id; 3063 3064 if ((n_tokens < 2) || 3065 parser_read_uint32(&id, tokens[1])) 3066 return 0; 3067 3068 a->fwd.action = RTE_PIPELINE_ACTION_PORT; 3069 a->fwd.id = id; 3070 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3071 return 1 + 2; 3072 } 3073 3074 if (n_tokens && (strcmp(tokens[0], "meta") == 0)) { 3075 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META; 3076 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3077 return 1 + 1; 3078 } 3079 3080 if (n_tokens && (strcmp(tokens[0], "table") == 0)) { 3081 uint32_t id; 3082 3083 if ((n_tokens < 2) || 3084 parser_read_uint32(&id, tokens[1])) 3085 return 0; 3086 3087 a->fwd.action = RTE_PIPELINE_ACTION_TABLE; 3088 a->fwd.id = id; 3089 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD; 3090 return 1 + 2; 3091 } 3092 3093 return 0; 3094 } 3095 3096 static uint32_t 3097 parse_table_action_balance(char **tokens, 3098 uint32_t n_tokens, 3099 struct table_rule_action *a) 3100 { 3101 uint32_t i; 3102 3103 if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0)) 3104 return 0; 3105 3106 tokens++; 3107 n_tokens--; 3108 3109 if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE) 3110 return 0; 3111 3112 for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++) 3113 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0) 3114 return 0; 3115 3116 a->action_mask |= 1 << RTE_TABLE_ACTION_LB; 3117 return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE; 3118 3119 } 3120 3121 static int 3122 parse_policer_action(char *token, enum rte_table_action_policer *a) 3123 { 3124 if (strcmp(token, "g") == 0) { 3125 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN; 3126 return 0; 3127 } 3128 3129 if (strcmp(token, "y") == 0) { 3130 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW; 3131 return 0; 3132 } 3133 3134 if (strcmp(token, "r") == 0) { 3135 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED; 3136 return 0; 3137 } 3138 3139 if (strcmp(token, "drop") == 0) { 3140 *a = RTE_TABLE_ACTION_POLICER_DROP; 3141 return 0; 3142 } 3143 3144 return -1; 3145 } 3146 3147 static uint32_t 3148 parse_table_action_meter_tc(char **tokens, 3149 uint32_t n_tokens, 3150 struct rte_table_action_mtr_tc_params *mtr) 3151 { 3152 if ((n_tokens < 9) || 3153 strcmp(tokens[0], "meter") || 3154 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) || 3155 strcmp(tokens[2], "policer") || 3156 strcmp(tokens[3], "g") || 3157 parse_policer_action(tokens[4], &mtr->policer[RTE_COLOR_GREEN]) || 3158 strcmp(tokens[5], "y") || 3159 parse_policer_action(tokens[6], &mtr->policer[RTE_COLOR_YELLOW]) || 3160 strcmp(tokens[7], "r") || 3161 parse_policer_action(tokens[8], &mtr->policer[RTE_COLOR_RED])) 3162 return 0; 3163 3164 return 9; 3165 } 3166 3167 static uint32_t 3168 parse_table_action_meter(char **tokens, 3169 uint32_t n_tokens, 3170 struct table_rule_action *a) 3171 { 3172 if ((n_tokens == 0) || strcmp(tokens[0], "meter")) 3173 return 0; 3174 3175 tokens++; 3176 n_tokens--; 3177 3178 if ((n_tokens < 10) || 3179 strcmp(tokens[0], "tc0") || 3180 (parse_table_action_meter_tc(tokens + 1, 3181 n_tokens - 1, 3182 &a->mtr.mtr[0]) == 0)) 3183 return 0; 3184 3185 tokens += 10; 3186 n_tokens -= 10; 3187 3188 if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) { 3189 a->mtr.tc_mask = 1; 3190 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 3191 return 1 + 10; 3192 } 3193 3194 if ((n_tokens < 30) || 3195 (parse_table_action_meter_tc(tokens + 1, 3196 n_tokens - 1, &a->mtr.mtr[1]) == 0) || 3197 strcmp(tokens[10], "tc2") || 3198 (parse_table_action_meter_tc(tokens + 11, 3199 n_tokens - 11, &a->mtr.mtr[2]) == 0) || 3200 strcmp(tokens[20], "tc3") || 3201 (parse_table_action_meter_tc(tokens + 21, 3202 n_tokens - 21, &a->mtr.mtr[3]) == 0)) 3203 return 0; 3204 3205 a->mtr.tc_mask = 0xF; 3206 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR; 3207 return 1 + 10 + 3 * 10; 3208 } 3209 3210 static uint32_t 3211 parse_table_action_tm(char **tokens, 3212 uint32_t n_tokens, 3213 struct table_rule_action *a) 3214 { 3215 uint32_t subport_id, pipe_id; 3216 3217 if ((n_tokens < 5) || 3218 strcmp(tokens[0], "tm") || 3219 strcmp(tokens[1], "subport") || 3220 parser_read_uint32(&subport_id, tokens[2]) || 3221 strcmp(tokens[3], "pipe") || 3222 parser_read_uint32(&pipe_id, tokens[4])) 3223 return 0; 3224 3225 a->tm.subport_id = subport_id; 3226 a->tm.pipe_id = pipe_id; 3227 a->action_mask |= 1 << RTE_TABLE_ACTION_TM; 3228 return 5; 3229 } 3230 3231 static uint32_t 3232 parse_table_action_encap(char **tokens, 3233 uint32_t n_tokens, 3234 struct table_rule_action *a) 3235 { 3236 if ((n_tokens == 0) || strcmp(tokens[0], "encap")) 3237 return 0; 3238 3239 tokens++; 3240 n_tokens--; 3241 3242 /* ether */ 3243 if (n_tokens && (strcmp(tokens[0], "ether") == 0)) { 3244 if ((n_tokens < 3) || 3245 parse_mac_addr(tokens[1], &a->encap.ether.ether.da) || 3246 parse_mac_addr(tokens[2], &a->encap.ether.ether.sa)) 3247 return 0; 3248 3249 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER; 3250 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3251 return 1 + 3; 3252 } 3253 3254 /* vlan */ 3255 if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) { 3256 uint32_t pcp, dei, vid; 3257 3258 if ((n_tokens < 6) || 3259 parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) || 3260 parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) || 3261 parser_read_uint32(&pcp, tokens[3]) || 3262 (pcp > 0x7) || 3263 parser_read_uint32(&dei, tokens[4]) || 3264 (dei > 0x1) || 3265 parser_read_uint32(&vid, tokens[5]) || 3266 (vid > 0xFFF)) 3267 return 0; 3268 3269 a->encap.vlan.vlan.pcp = pcp & 0x7; 3270 a->encap.vlan.vlan.dei = dei & 0x1; 3271 a->encap.vlan.vlan.vid = vid & 0xFFF; 3272 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN; 3273 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3274 return 1 + 6; 3275 } 3276 3277 /* qinq */ 3278 if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) { 3279 uint32_t svlan_pcp, svlan_dei, svlan_vid; 3280 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid; 3281 3282 if ((n_tokens < 9) || 3283 parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) || 3284 parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) || 3285 parser_read_uint32(&svlan_pcp, tokens[3]) || 3286 (svlan_pcp > 0x7) || 3287 parser_read_uint32(&svlan_dei, tokens[4]) || 3288 (svlan_dei > 0x1) || 3289 parser_read_uint32(&svlan_vid, tokens[5]) || 3290 (svlan_vid > 0xFFF) || 3291 parser_read_uint32(&cvlan_pcp, tokens[6]) || 3292 (cvlan_pcp > 0x7) || 3293 parser_read_uint32(&cvlan_dei, tokens[7]) || 3294 (cvlan_dei > 0x1) || 3295 parser_read_uint32(&cvlan_vid, tokens[8]) || 3296 (cvlan_vid > 0xFFF)) 3297 return 0; 3298 3299 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7; 3300 a->encap.qinq.svlan.dei = svlan_dei & 0x1; 3301 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF; 3302 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7; 3303 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1; 3304 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF; 3305 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ; 3306 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3307 return 1 + 9; 3308 } 3309 3310 /* qinq_pppoe */ 3311 if (n_tokens && (strcmp(tokens[0], "qinq_pppoe") == 0)) { 3312 uint32_t svlan_pcp, svlan_dei, svlan_vid; 3313 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid; 3314 3315 if ((n_tokens < 10) || 3316 parse_mac_addr(tokens[1], 3317 &a->encap.qinq_pppoe.ether.da) || 3318 parse_mac_addr(tokens[2], 3319 &a->encap.qinq_pppoe.ether.sa) || 3320 parser_read_uint32(&svlan_pcp, tokens[3]) || 3321 (svlan_pcp > 0x7) || 3322 parser_read_uint32(&svlan_dei, tokens[4]) || 3323 (svlan_dei > 0x1) || 3324 parser_read_uint32(&svlan_vid, tokens[5]) || 3325 (svlan_vid > 0xFFF) || 3326 parser_read_uint32(&cvlan_pcp, tokens[6]) || 3327 (cvlan_pcp > 0x7) || 3328 parser_read_uint32(&cvlan_dei, tokens[7]) || 3329 (cvlan_dei > 0x1) || 3330 parser_read_uint32(&cvlan_vid, tokens[8]) || 3331 (cvlan_vid > 0xFFF) || 3332 parser_read_uint16(&a->encap.qinq_pppoe.pppoe.session_id, 3333 tokens[9])) 3334 return 0; 3335 3336 a->encap.qinq_pppoe.svlan.pcp = svlan_pcp & 0x7; 3337 a->encap.qinq_pppoe.svlan.dei = svlan_dei & 0x1; 3338 a->encap.qinq_pppoe.svlan.vid = svlan_vid & 0xFFF; 3339 a->encap.qinq_pppoe.cvlan.pcp = cvlan_pcp & 0x7; 3340 a->encap.qinq_pppoe.cvlan.dei = cvlan_dei & 0x1; 3341 a->encap.qinq_pppoe.cvlan.vid = cvlan_vid & 0xFFF; 3342 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ_PPPOE; 3343 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3344 return 1 + 10; 3345 3346 } 3347 3348 /* mpls */ 3349 if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) { 3350 uint32_t label, tc, ttl; 3351 3352 if (n_tokens < 8) 3353 return 0; 3354 3355 if (strcmp(tokens[1], "unicast") == 0) 3356 a->encap.mpls.unicast = 1; 3357 else if (strcmp(tokens[1], "multicast") == 0) 3358 a->encap.mpls.unicast = 0; 3359 else 3360 return 0; 3361 3362 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) || 3363 parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) || 3364 strcmp(tokens[4], "label0") || 3365 parser_read_uint32(&label, tokens[5]) || 3366 (label > 0xFFFFF) || 3367 parser_read_uint32(&tc, tokens[6]) || 3368 (tc > 0x7) || 3369 parser_read_uint32(&ttl, tokens[7]) || 3370 (ttl > 0x3F)) 3371 return 0; 3372 3373 a->encap.mpls.mpls[0].label = label; 3374 a->encap.mpls.mpls[0].tc = tc; 3375 a->encap.mpls.mpls[0].ttl = ttl; 3376 3377 tokens += 8; 3378 n_tokens -= 8; 3379 3380 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) { 3381 a->encap.mpls.mpls_count = 1; 3382 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3383 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3384 return 1 + 8; 3385 } 3386 3387 if ((n_tokens < 4) || 3388 parser_read_uint32(&label, tokens[1]) || 3389 (label > 0xFFFFF) || 3390 parser_read_uint32(&tc, tokens[2]) || 3391 (tc > 0x7) || 3392 parser_read_uint32(&ttl, tokens[3]) || 3393 (ttl > 0x3F)) 3394 return 0; 3395 3396 a->encap.mpls.mpls[1].label = label; 3397 a->encap.mpls.mpls[1].tc = tc; 3398 a->encap.mpls.mpls[1].ttl = ttl; 3399 3400 tokens += 4; 3401 n_tokens -= 4; 3402 3403 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) { 3404 a->encap.mpls.mpls_count = 2; 3405 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3406 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3407 return 1 + 8 + 4; 3408 } 3409 3410 if ((n_tokens < 4) || 3411 parser_read_uint32(&label, tokens[1]) || 3412 (label > 0xFFFFF) || 3413 parser_read_uint32(&tc, tokens[2]) || 3414 (tc > 0x7) || 3415 parser_read_uint32(&ttl, tokens[3]) || 3416 (ttl > 0x3F)) 3417 return 0; 3418 3419 a->encap.mpls.mpls[2].label = label; 3420 a->encap.mpls.mpls[2].tc = tc; 3421 a->encap.mpls.mpls[2].ttl = ttl; 3422 3423 tokens += 4; 3424 n_tokens -= 4; 3425 3426 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) { 3427 a->encap.mpls.mpls_count = 3; 3428 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3429 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3430 return 1 + 8 + 4 + 4; 3431 } 3432 3433 if ((n_tokens < 4) || 3434 parser_read_uint32(&label, tokens[1]) || 3435 (label > 0xFFFFF) || 3436 parser_read_uint32(&tc, tokens[2]) || 3437 (tc > 0x7) || 3438 parser_read_uint32(&ttl, tokens[3]) || 3439 (ttl > 0x3F)) 3440 return 0; 3441 3442 a->encap.mpls.mpls[3].label = label; 3443 a->encap.mpls.mpls[3].tc = tc; 3444 a->encap.mpls.mpls[3].ttl = ttl; 3445 3446 a->encap.mpls.mpls_count = 4; 3447 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS; 3448 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3449 return 1 + 8 + 4 + 4 + 4; 3450 } 3451 3452 /* pppoe */ 3453 if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) { 3454 if ((n_tokens < 4) || 3455 parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) || 3456 parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) || 3457 parser_read_uint16(&a->encap.pppoe.pppoe.session_id, 3458 tokens[3])) 3459 return 0; 3460 3461 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE; 3462 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3463 return 1 + 4; 3464 } 3465 3466 /* vxlan */ 3467 if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) { 3468 uint32_t n = 0; 3469 3470 n_tokens--; 3471 tokens++; 3472 n++; 3473 3474 /* ether <da> <sa> */ 3475 if ((n_tokens < 3) || 3476 strcmp(tokens[0], "ether") || 3477 parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) || 3478 parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa)) 3479 return 0; 3480 3481 n_tokens -= 3; 3482 tokens += 3; 3483 n += 3; 3484 3485 /* [vlan <pcp> <dei> <vid>] */ 3486 if (strcmp(tokens[0], "vlan") == 0) { 3487 uint32_t pcp, dei, vid; 3488 3489 if ((n_tokens < 4) || 3490 parser_read_uint32(&pcp, tokens[1]) || 3491 (pcp > 7) || 3492 parser_read_uint32(&dei, tokens[2]) || 3493 (dei > 1) || 3494 parser_read_uint32(&vid, tokens[3]) || 3495 (vid > 0xFFF)) 3496 return 0; 3497 3498 a->encap.vxlan.vlan.pcp = pcp; 3499 a->encap.vxlan.vlan.dei = dei; 3500 a->encap.vxlan.vlan.vid = vid; 3501 3502 n_tokens -= 4; 3503 tokens += 4; 3504 n += 4; 3505 } 3506 3507 /* ipv4 <sa> <da> <dscp> <ttl> 3508 | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */ 3509 if (strcmp(tokens[0], "ipv4") == 0) { 3510 struct in_addr sa, da; 3511 uint8_t dscp, ttl; 3512 3513 if ((n_tokens < 5) || 3514 parse_ipv4_addr(tokens[1], &sa) || 3515 parse_ipv4_addr(tokens[2], &da) || 3516 parser_read_uint8(&dscp, tokens[3]) || 3517 (dscp > 64) || 3518 parser_read_uint8(&ttl, tokens[4])) 3519 return 0; 3520 3521 a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr); 3522 a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr); 3523 a->encap.vxlan.ipv4.dscp = dscp; 3524 a->encap.vxlan.ipv4.ttl = ttl; 3525 3526 n_tokens -= 5; 3527 tokens += 5; 3528 n += 5; 3529 } else if (strcmp(tokens[0], "ipv6") == 0) { 3530 struct in6_addr sa, da; 3531 uint32_t flow_label; 3532 uint8_t dscp, hop_limit; 3533 3534 if ((n_tokens < 6) || 3535 parse_ipv6_addr(tokens[1], &sa) || 3536 parse_ipv6_addr(tokens[2], &da) || 3537 parser_read_uint32(&flow_label, tokens[3]) || 3538 parser_read_uint8(&dscp, tokens[4]) || 3539 (dscp > 64) || 3540 parser_read_uint8(&hop_limit, tokens[5])) 3541 return 0; 3542 3543 memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16); 3544 memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16); 3545 a->encap.vxlan.ipv6.flow_label = flow_label; 3546 a->encap.vxlan.ipv6.dscp = dscp; 3547 a->encap.vxlan.ipv6.hop_limit = hop_limit; 3548 3549 n_tokens -= 6; 3550 tokens += 6; 3551 n += 6; 3552 } else 3553 return 0; 3554 3555 /* udp <sp> <dp> */ 3556 if ((n_tokens < 3) || 3557 strcmp(tokens[0], "udp") || 3558 parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) || 3559 parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2])) 3560 return 0; 3561 3562 n_tokens -= 3; 3563 tokens += 3; 3564 n += 3; 3565 3566 /* vxlan <vni> */ 3567 if ((n_tokens < 2) || 3568 strcmp(tokens[0], "vxlan") || 3569 parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) || 3570 (a->encap.vxlan.vxlan.vni > 0xFFFFFF)) 3571 return 0; 3572 3573 n_tokens -= 2; 3574 tokens += 2; 3575 n += 2; 3576 3577 a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN; 3578 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; 3579 return 1 + n; 3580 } 3581 3582 return 0; 3583 } 3584 3585 static uint32_t 3586 parse_table_action_nat(char **tokens, 3587 uint32_t n_tokens, 3588 struct table_rule_action *a) 3589 { 3590 if ((n_tokens < 4) || 3591 strcmp(tokens[0], "nat")) 3592 return 0; 3593 3594 if (strcmp(tokens[1], "ipv4") == 0) { 3595 struct in_addr addr; 3596 uint16_t port; 3597 3598 if (parse_ipv4_addr(tokens[2], &addr) || 3599 parser_read_uint16(&port, tokens[3])) 3600 return 0; 3601 3602 a->nat.ip_version = 1; 3603 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr); 3604 a->nat.port = port; 3605 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3606 return 4; 3607 } 3608 3609 if (strcmp(tokens[1], "ipv6") == 0) { 3610 struct in6_addr addr; 3611 uint16_t port; 3612 3613 if (parse_ipv6_addr(tokens[2], &addr) || 3614 parser_read_uint16(&port, tokens[3])) 3615 return 0; 3616 3617 a->nat.ip_version = 0; 3618 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16); 3619 a->nat.port = port; 3620 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT; 3621 return 4; 3622 } 3623 3624 return 0; 3625 } 3626 3627 static uint32_t 3628 parse_table_action_ttl(char **tokens, 3629 uint32_t n_tokens, 3630 struct table_rule_action *a) 3631 { 3632 if ((n_tokens < 2) || 3633 strcmp(tokens[0], "ttl")) 3634 return 0; 3635 3636 if (strcmp(tokens[1], "dec") == 0) 3637 a->ttl.decrement = 1; 3638 else if (strcmp(tokens[1], "keep") == 0) 3639 a->ttl.decrement = 0; 3640 else 3641 return 0; 3642 3643 a->action_mask |= 1 << RTE_TABLE_ACTION_TTL; 3644 return 2; 3645 } 3646 3647 static uint32_t 3648 parse_table_action_stats(char **tokens, 3649 uint32_t n_tokens, 3650 struct table_rule_action *a) 3651 { 3652 if ((n_tokens < 1) || 3653 strcmp(tokens[0], "stats")) 3654 return 0; 3655 3656 a->stats.n_packets = 0; 3657 a->stats.n_bytes = 0; 3658 a->action_mask |= 1 << RTE_TABLE_ACTION_STATS; 3659 return 1; 3660 } 3661 3662 static uint32_t 3663 parse_table_action_time(char **tokens, 3664 uint32_t n_tokens, 3665 struct table_rule_action *a) 3666 { 3667 if ((n_tokens < 1) || 3668 strcmp(tokens[0], "time")) 3669 return 0; 3670 3671 a->time.time = rte_rdtsc(); 3672 a->action_mask |= 1 << RTE_TABLE_ACTION_TIME; 3673 return 1; 3674 } 3675 3676 static void 3677 parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p) 3678 { 3679 struct rte_crypto_sym_xform *xform[2] = {NULL}; 3680 uint32_t i; 3681 3682 xform[0] = p->xform; 3683 if (xform[0]) 3684 xform[1] = xform[0]->next; 3685 3686 for (i = 0; i < 2; i++) { 3687 if (xform[i] == NULL) 3688 continue; 3689 3690 switch (xform[i]->type) { 3691 case RTE_CRYPTO_SYM_XFORM_CIPHER: 3692 free(p->cipher_auth.cipher_iv.val); 3693 free(p->cipher_auth.cipher_iv_update.val); 3694 break; 3695 case RTE_CRYPTO_SYM_XFORM_AUTH: 3696 if (p->cipher_auth.auth_iv.val) 3697 free(p->cipher_auth.cipher_iv.val); 3698 if (p->cipher_auth.auth_iv_update.val) 3699 free(p->cipher_auth.cipher_iv_update.val); 3700 break; 3701 case RTE_CRYPTO_SYM_XFORM_AEAD: 3702 free(p->aead.iv.val); 3703 free(p->aead.aad.val); 3704 break; 3705 default: 3706 continue; 3707 } 3708 } 3709 3710 } 3711 3712 static struct rte_crypto_sym_xform * 3713 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p, 3714 uint8_t *key, uint32_t max_key_len, char **tokens, 3715 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens) 3716 { 3717 struct rte_crypto_sym_xform *xform_cipher; 3718 int status; 3719 size_t len; 3720 3721 if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") || 3722 strcmp(tokens[3], "cipher_key") || 3723 strcmp(tokens[5], "cipher_iv")) 3724 return NULL; 3725 3726 xform_cipher = calloc(1, sizeof(*xform_cipher)); 3727 if (xform_cipher == NULL) 3728 return NULL; 3729 3730 xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER; 3731 xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT : 3732 RTE_CRYPTO_CIPHER_OP_DECRYPT; 3733 3734 /* cipher_algo */ 3735 status = rte_cryptodev_get_cipher_algo_enum( 3736 &xform_cipher->cipher.algo, tokens[2]); 3737 if (status < 0) 3738 goto error_exit; 3739 3740 /* cipher_key */ 3741 len = strlen(tokens[4]); 3742 if (len / 2 > max_key_len) { 3743 status = -ENOMEM; 3744 goto error_exit; 3745 } 3746 3747 status = parse_hex_string(tokens[4], key, (uint32_t *)&len); 3748 if (status < 0) 3749 goto error_exit; 3750 3751 xform_cipher->cipher.key.data = key; 3752 xform_cipher->cipher.key.length = (uint16_t)len; 3753 3754 /* cipher_iv */ 3755 len = strlen(tokens[6]); 3756 3757 p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1); 3758 if (p->cipher_auth.cipher_iv.val == NULL) 3759 goto error_exit; 3760 3761 status = parse_hex_string(tokens[6], 3762 p->cipher_auth.cipher_iv.val, 3763 (uint32_t *)&len); 3764 if (status < 0) 3765 goto error_exit; 3766 3767 xform_cipher->cipher.iv.length = (uint16_t)len; 3768 xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET; 3769 p->cipher_auth.cipher_iv.length = (uint32_t)len; 3770 *used_n_tokens = 7; 3771 3772 return xform_cipher; 3773 3774 error_exit: 3775 if (p->cipher_auth.cipher_iv.val) { 3776 free(p->cipher_auth.cipher_iv.val); 3777 p->cipher_auth.cipher_iv.val = NULL; 3778 } 3779 3780 free(xform_cipher); 3781 3782 return NULL; 3783 } 3784 3785 static struct rte_crypto_sym_xform * 3786 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p, 3787 uint8_t *key, uint32_t max_key_len, char **tokens, 3788 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens) 3789 { 3790 struct rte_crypto_sym_xform *xform_cipher; 3791 struct rte_crypto_sym_xform *xform_auth; 3792 int status; 3793 size_t len; 3794 3795 if (n_tokens < 13 || 3796 strcmp(tokens[7], "auth_algo") || 3797 strcmp(tokens[9], "auth_key") || 3798 strcmp(tokens[11], "digest_size")) 3799 return NULL; 3800 3801 xform_auth = calloc(1, sizeof(*xform_auth)); 3802 if (xform_auth == NULL) 3803 return NULL; 3804 3805 xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH; 3806 xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE : 3807 RTE_CRYPTO_AUTH_OP_VERIFY; 3808 3809 /* auth_algo */ 3810 status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo, 3811 tokens[8]); 3812 if (status < 0) 3813 goto error_exit; 3814 3815 /* auth_key */ 3816 len = strlen(tokens[10]); 3817 if (len / 2 > max_key_len) { 3818 status = -ENOMEM; 3819 goto error_exit; 3820 } 3821 3822 status = parse_hex_string(tokens[10], key, (uint32_t *)&len); 3823 if (status < 0) 3824 goto error_exit; 3825 3826 xform_auth->auth.key.data = key; 3827 xform_auth->auth.key.length = (uint16_t)len; 3828 3829 key += xform_auth->auth.key.length; 3830 max_key_len -= xform_auth->auth.key.length; 3831 3832 if (strcmp(tokens[11], "digest_size")) 3833 goto error_exit; 3834 3835 status = parser_read_uint16(&xform_auth->auth.digest_length, 3836 tokens[12]); 3837 if (status < 0) 3838 goto error_exit; 3839 3840 xform_cipher = parse_table_action_cipher(p, key, max_key_len, tokens, 3841 7, encrypt, used_n_tokens); 3842 if (xform_cipher == NULL) 3843 goto error_exit; 3844 3845 *used_n_tokens += 6; 3846 3847 if (encrypt) { 3848 xform_cipher->next = xform_auth; 3849 return xform_cipher; 3850 } else { 3851 xform_auth->next = xform_cipher; 3852 return xform_auth; 3853 } 3854 3855 error_exit: 3856 if (p->cipher_auth.auth_iv.val) { 3857 free(p->cipher_auth.auth_iv.val); 3858 p->cipher_auth.auth_iv.val = 0; 3859 } 3860 3861 free(xform_auth); 3862 3863 return NULL; 3864 } 3865 3866 static struct rte_crypto_sym_xform * 3867 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p, 3868 uint8_t *key, uint32_t max_key_len, char **tokens, 3869 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens) 3870 { 3871 struct rte_crypto_sym_xform *xform_aead; 3872 int status; 3873 size_t len; 3874 3875 if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") || 3876 strcmp(tokens[3], "aead_key") || 3877 strcmp(tokens[5], "aead_iv") || 3878 strcmp(tokens[7], "aead_aad") || 3879 strcmp(tokens[9], "digest_size")) 3880 return NULL; 3881 3882 xform_aead = calloc(1, sizeof(*xform_aead)); 3883 if (xform_aead == NULL) 3884 return NULL; 3885 3886 xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD; 3887 xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT : 3888 RTE_CRYPTO_AEAD_OP_DECRYPT; 3889 3890 /* aead_algo */ 3891 status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo, 3892 tokens[2]); 3893 if (status < 0) 3894 goto error_exit; 3895 3896 /* aead_key */ 3897 len = strlen(tokens[4]); 3898 if (len / 2 > max_key_len) { 3899 status = -ENOMEM; 3900 goto error_exit; 3901 } 3902 3903 status = parse_hex_string(tokens[4], key, (uint32_t *)&len); 3904 if (status < 0) 3905 goto error_exit; 3906 3907 xform_aead->aead.key.data = key; 3908 xform_aead->aead.key.length = (uint16_t)len; 3909 3910 /* aead_iv */ 3911 len = strlen(tokens[6]); 3912 p->aead.iv.val = calloc(1, len / 2 + 1); 3913 if (p->aead.iv.val == NULL) 3914 goto error_exit; 3915 3916 status = parse_hex_string(tokens[6], p->aead.iv.val, 3917 (uint32_t *)&len); 3918 if (status < 0) 3919 goto error_exit; 3920 3921 xform_aead->aead.iv.length = (uint16_t)len; 3922 xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET; 3923 p->aead.iv.length = (uint32_t)len; 3924 3925 /* aead_aad */ 3926 len = strlen(tokens[8]); 3927 p->aead.aad.val = calloc(1, len / 2 + 1); 3928 if (p->aead.aad.val == NULL) 3929 goto error_exit; 3930 3931 status = parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len); 3932 if (status < 0) 3933 goto error_exit; 3934 3935 xform_aead->aead.aad_length = (uint16_t)len; 3936 p->aead.aad.length = (uint32_t)len; 3937 3938 /* digest_size */ 3939 status = parser_read_uint16(&xform_aead->aead.digest_length, 3940 tokens[10]); 3941 if (status < 0) 3942 goto error_exit; 3943 3944 *used_n_tokens = 11; 3945 3946 return xform_aead; 3947 3948 error_exit: 3949 if (p->aead.iv.val) { 3950 free(p->aead.iv.val); 3951 p->aead.iv.val = NULL; 3952 } 3953 if (p->aead.aad.val) { 3954 free(p->aead.aad.val); 3955 p->aead.aad.val = NULL; 3956 } 3957 3958 free(xform_aead); 3959 3960 return NULL; 3961 } 3962 3963 3964 static uint32_t 3965 parse_table_action_sym_crypto(char **tokens, 3966 uint32_t n_tokens, 3967 struct table_rule_action *a) 3968 { 3969 struct rte_table_action_sym_crypto_params *p = &a->sym_crypto; 3970 struct rte_crypto_sym_xform *xform = NULL; 3971 uint8_t *key = a->sym_crypto_key; 3972 uint32_t max_key_len = SYM_CRYPTO_MAX_KEY_SIZE; 3973 uint32_t used_n_tokens; 3974 uint32_t encrypt; 3975 int status; 3976 3977 if ((n_tokens < 12) || 3978 strcmp(tokens[0], "sym_crypto") || 3979 strcmp(tokens[2], "type")) 3980 return 0; 3981 3982 memset(p, 0, sizeof(*p)); 3983 3984 if (strcmp(tokens[1], "encrypt") == 0) 3985 encrypt = 1; 3986 else 3987 encrypt = 0; 3988 3989 status = parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]); 3990 if (status < 0) 3991 return 0; 3992 3993 if (strcmp(tokens[3], "cipher") == 0) { 3994 tokens += 3; 3995 n_tokens -= 3; 3996 3997 xform = parse_table_action_cipher(p, key, max_key_len, tokens, 3998 n_tokens, encrypt, &used_n_tokens); 3999 } else if (strcmp(tokens[3], "cipher_auth") == 0) { 4000 tokens += 3; 4001 n_tokens -= 3; 4002 4003 xform = parse_table_action_cipher_auth(p, key, max_key_len, 4004 tokens, n_tokens, encrypt, &used_n_tokens); 4005 } else if (strcmp(tokens[3], "aead") == 0) { 4006 tokens += 3; 4007 n_tokens -= 3; 4008 4009 xform = parse_table_action_aead(p, key, max_key_len, tokens, 4010 n_tokens, encrypt, &used_n_tokens); 4011 } 4012 4013 if (xform == NULL) 4014 return 0; 4015 4016 p->xform = xform; 4017 4018 if (strcmp(tokens[used_n_tokens], "data_offset")) { 4019 parse_free_sym_crypto_param_data(p); 4020 return 0; 4021 } 4022 4023 a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO; 4024 4025 return used_n_tokens + 5; 4026 } 4027 4028 static uint32_t 4029 parse_table_action_tag(char **tokens, 4030 uint32_t n_tokens, 4031 struct table_rule_action *a) 4032 { 4033 if ((n_tokens < 2) || 4034 strcmp(tokens[0], "tag")) 4035 return 0; 4036 4037 if (parser_read_uint32(&a->tag.tag, tokens[1])) 4038 return 0; 4039 4040 a->action_mask |= 1 << RTE_TABLE_ACTION_TAG; 4041 return 2; 4042 } 4043 4044 static uint32_t 4045 parse_table_action_decap(char **tokens, 4046 uint32_t n_tokens, 4047 struct table_rule_action *a) 4048 { 4049 if ((n_tokens < 2) || 4050 strcmp(tokens[0], "decap")) 4051 return 0; 4052 4053 if (parser_read_uint16(&a->decap.n, tokens[1])) 4054 return 0; 4055 4056 a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP; 4057 return 2; 4058 } 4059 4060 static uint32_t 4061 parse_table_action(char **tokens, 4062 uint32_t n_tokens, 4063 char *out, 4064 size_t out_size, 4065 struct table_rule_action *a) 4066 { 4067 uint32_t n_tokens0 = n_tokens; 4068 4069 memset(a, 0, sizeof(*a)); 4070 4071 if ((n_tokens < 2) || 4072 strcmp(tokens[0], "action")) 4073 return 0; 4074 4075 tokens++; 4076 n_tokens--; 4077 4078 if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) { 4079 uint32_t n; 4080 4081 n = parse_table_action_fwd(tokens, n_tokens, a); 4082 if (n == 0) { 4083 snprintf(out, out_size, MSG_ARG_INVALID, 4084 "action fwd"); 4085 return 0; 4086 } 4087 4088 tokens += n; 4089 n_tokens -= n; 4090 } 4091 4092 if (n_tokens && (strcmp(tokens[0], "balance") == 0)) { 4093 uint32_t n; 4094 4095 n = parse_table_action_balance(tokens, n_tokens, a); 4096 if (n == 0) { 4097 snprintf(out, out_size, MSG_ARG_INVALID, 4098 "action balance"); 4099 return 0; 4100 } 4101 4102 tokens += n; 4103 n_tokens -= n; 4104 } 4105 4106 if (n_tokens && (strcmp(tokens[0], "meter") == 0)) { 4107 uint32_t n; 4108 4109 n = parse_table_action_meter(tokens, n_tokens, a); 4110 if (n == 0) { 4111 snprintf(out, out_size, MSG_ARG_INVALID, 4112 "action meter"); 4113 return 0; 4114 } 4115 4116 tokens += n; 4117 n_tokens -= n; 4118 } 4119 4120 if (n_tokens && (strcmp(tokens[0], "tm") == 0)) { 4121 uint32_t n; 4122 4123 n = parse_table_action_tm(tokens, n_tokens, a); 4124 if (n == 0) { 4125 snprintf(out, out_size, MSG_ARG_INVALID, 4126 "action tm"); 4127 return 0; 4128 } 4129 4130 tokens += n; 4131 n_tokens -= n; 4132 } 4133 4134 if (n_tokens && (strcmp(tokens[0], "encap") == 0)) { 4135 uint32_t n; 4136 4137 n = parse_table_action_encap(tokens, n_tokens, a); 4138 if (n == 0) { 4139 snprintf(out, out_size, MSG_ARG_INVALID, 4140 "action encap"); 4141 return 0; 4142 } 4143 4144 tokens += n; 4145 n_tokens -= n; 4146 } 4147 4148 if (n_tokens && (strcmp(tokens[0], "nat") == 0)) { 4149 uint32_t n; 4150 4151 n = parse_table_action_nat(tokens, n_tokens, a); 4152 if (n == 0) { 4153 snprintf(out, out_size, MSG_ARG_INVALID, 4154 "action nat"); 4155 return 0; 4156 } 4157 4158 tokens += n; 4159 n_tokens -= n; 4160 } 4161 4162 if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) { 4163 uint32_t n; 4164 4165 n = parse_table_action_ttl(tokens, n_tokens, a); 4166 if (n == 0) { 4167 snprintf(out, out_size, MSG_ARG_INVALID, 4168 "action ttl"); 4169 return 0; 4170 } 4171 4172 tokens += n; 4173 n_tokens -= n; 4174 } 4175 4176 if (n_tokens && (strcmp(tokens[0], "stats") == 0)) { 4177 uint32_t n; 4178 4179 n = parse_table_action_stats(tokens, n_tokens, a); 4180 if (n == 0) { 4181 snprintf(out, out_size, MSG_ARG_INVALID, 4182 "action stats"); 4183 return 0; 4184 } 4185 4186 tokens += n; 4187 n_tokens -= n; 4188 } 4189 4190 if (n_tokens && (strcmp(tokens[0], "time") == 0)) { 4191 uint32_t n; 4192 4193 n = parse_table_action_time(tokens, n_tokens, a); 4194 if (n == 0) { 4195 snprintf(out, out_size, MSG_ARG_INVALID, 4196 "action time"); 4197 return 0; 4198 } 4199 4200 tokens += n; 4201 n_tokens -= n; 4202 } 4203 4204 if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) { 4205 uint32_t n; 4206 4207 n = parse_table_action_sym_crypto(tokens, n_tokens, a); 4208 if (n == 0) { 4209 snprintf(out, out_size, MSG_ARG_INVALID, 4210 "action sym_crypto"); 4211 } 4212 4213 tokens += n; 4214 n_tokens -= n; 4215 } 4216 4217 if (n_tokens && (strcmp(tokens[0], "tag") == 0)) { 4218 uint32_t n; 4219 4220 n = parse_table_action_tag(tokens, n_tokens, a); 4221 if (n == 0) { 4222 snprintf(out, out_size, MSG_ARG_INVALID, 4223 "action tag"); 4224 return 0; 4225 } 4226 4227 tokens += n; 4228 n_tokens -= n; 4229 } 4230 4231 if (n_tokens && (strcmp(tokens[0], "decap") == 0)) { 4232 uint32_t n; 4233 4234 n = parse_table_action_decap(tokens, n_tokens, a); 4235 if (n == 0) { 4236 snprintf(out, out_size, MSG_ARG_INVALID, 4237 "action decap"); 4238 return 0; 4239 } 4240 4241 tokens += n; 4242 n_tokens -= n; 4243 } 4244 4245 if (n_tokens0 - n_tokens == 1) { 4246 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 4247 return 0; 4248 } 4249 4250 return n_tokens0 - n_tokens; 4251 } 4252 4253 4254 static const char cmd_pipeline_table_rule_add_help[] = 4255 "pipeline <pipeline_name> table <table_id> rule add\n" 4256 " match <match>\n" 4257 " action <table_action>\n"; 4258 4259 static void 4260 cmd_pipeline_table_rule_add(char **tokens, 4261 uint32_t n_tokens, 4262 char *out, 4263 size_t out_size) 4264 { 4265 struct table_rule_match m; 4266 struct table_rule_action a; 4267 char *pipeline_name; 4268 uint32_t table_id, t0, n_tokens_parsed; 4269 int status; 4270 4271 if (n_tokens < 8) { 4272 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4273 return; 4274 } 4275 4276 pipeline_name = tokens[1]; 4277 4278 if (strcmp(tokens[2], "table") != 0) { 4279 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4280 return; 4281 } 4282 4283 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4284 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4285 return; 4286 } 4287 4288 if (strcmp(tokens[4], "rule") != 0) { 4289 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4290 return; 4291 } 4292 4293 if (strcmp(tokens[5], "add") != 0) { 4294 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4295 return; 4296 } 4297 4298 t0 = 6; 4299 4300 /* match */ 4301 n_tokens_parsed = parse_match(tokens + t0, 4302 n_tokens - t0, 4303 out, 4304 out_size, 4305 &m); 4306 if (n_tokens_parsed == 0) 4307 return; 4308 t0 += n_tokens_parsed; 4309 4310 /* action */ 4311 n_tokens_parsed = parse_table_action(tokens + t0, 4312 n_tokens - t0, 4313 out, 4314 out_size, 4315 &a); 4316 if (n_tokens_parsed == 0) 4317 return; 4318 t0 += n_tokens_parsed; 4319 4320 if (t0 != n_tokens) { 4321 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 4322 return; 4323 } 4324 4325 status = pipeline_table_rule_add(pipeline_name, table_id, &m, &a); 4326 if (status) { 4327 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4328 return; 4329 } 4330 4331 if (a.action_mask & 1 << RTE_TABLE_ACTION_SYM_CRYPTO) 4332 parse_free_sym_crypto_param_data(&a.sym_crypto); 4333 } 4334 4335 4336 static const char cmd_pipeline_table_rule_add_default_help[] = 4337 "pipeline <pipeline_name> table <table_id> rule add\n" 4338 " match\n" 4339 " default\n" 4340 " action\n" 4341 " fwd\n" 4342 " drop\n" 4343 " | port <port_id>\n" 4344 " | meta\n" 4345 " | table <table_id>\n"; 4346 4347 static void 4348 cmd_pipeline_table_rule_add_default(char **tokens, 4349 uint32_t n_tokens, 4350 char *out, 4351 size_t out_size) 4352 { 4353 struct table_rule_action action; 4354 char *pipeline_name; 4355 uint32_t table_id; 4356 int status; 4357 4358 if ((n_tokens != 11) && (n_tokens != 12)) { 4359 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4360 return; 4361 } 4362 4363 pipeline_name = tokens[1]; 4364 4365 if (strcmp(tokens[2], "table") != 0) { 4366 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4367 return; 4368 } 4369 4370 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4371 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4372 return; 4373 } 4374 4375 if (strcmp(tokens[4], "rule") != 0) { 4376 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4377 return; 4378 } 4379 4380 if (strcmp(tokens[5], "add") != 0) { 4381 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4382 return; 4383 } 4384 4385 if (strcmp(tokens[6], "match") != 0) { 4386 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 4387 return; 4388 } 4389 4390 if (strcmp(tokens[7], "default") != 0) { 4391 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 4392 return; 4393 } 4394 4395 if (strcmp(tokens[8], "action") != 0) { 4396 snprintf(out, out_size, MSG_ARG_INVALID, "action"); 4397 return; 4398 } 4399 4400 if (strcmp(tokens[9], "fwd") != 0) { 4401 snprintf(out, out_size, MSG_ARG_INVALID, "fwd"); 4402 return; 4403 } 4404 4405 action.action_mask = 1 << RTE_TABLE_ACTION_FWD; 4406 4407 if (strcmp(tokens[10], "drop") == 0) { 4408 if (n_tokens != 11) { 4409 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4410 return; 4411 } 4412 4413 action.fwd.action = RTE_PIPELINE_ACTION_DROP; 4414 } else if (strcmp(tokens[10], "port") == 0) { 4415 uint32_t id; 4416 4417 if (n_tokens != 12) { 4418 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4419 return; 4420 } 4421 4422 if (parser_read_uint32(&id, tokens[11]) != 0) { 4423 snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); 4424 return; 4425 } 4426 4427 action.fwd.action = RTE_PIPELINE_ACTION_PORT; 4428 action.fwd.id = id; 4429 } else if (strcmp(tokens[10], "meta") == 0) { 4430 if (n_tokens != 11) { 4431 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4432 return; 4433 } 4434 4435 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META; 4436 } else if (strcmp(tokens[10], "table") == 0) { 4437 uint32_t id; 4438 4439 if (n_tokens != 12) { 4440 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4441 return; 4442 } 4443 4444 if (parser_read_uint32(&id, tokens[11]) != 0) { 4445 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4446 return; 4447 } 4448 4449 action.fwd.action = RTE_PIPELINE_ACTION_TABLE; 4450 action.fwd.id = id; 4451 } else { 4452 snprintf(out, out_size, MSG_ARG_INVALID, 4453 "drop or port or meta or table"); 4454 return; 4455 } 4456 4457 status = pipeline_table_rule_add_default(pipeline_name, 4458 table_id, 4459 &action); 4460 if (status) { 4461 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4462 return; 4463 } 4464 } 4465 4466 4467 static const char cmd_pipeline_table_rule_add_bulk_help[] = 4468 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name>\n" 4469 "\n" 4470 " File <file_name>:\n" 4471 " - line format: match <match> action <action>\n"; 4472 4473 static int 4474 cli_rule_file_process(const char *file_name, 4475 size_t line_len_max, 4476 struct table_rule_list **rule_list, 4477 uint32_t *n_rules, 4478 uint32_t *line_number, 4479 char *out, 4480 size_t out_size); 4481 4482 static void 4483 cmd_pipeline_table_rule_add_bulk(char **tokens, 4484 uint32_t n_tokens, 4485 char *out, 4486 size_t out_size) 4487 { 4488 struct table_rule_list *list = NULL; 4489 char *pipeline_name, *file_name; 4490 uint32_t table_id, n_rules, n_rules_added, n_rules_not_added, line_number; 4491 int status; 4492 4493 if (n_tokens != 8) { 4494 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4495 return; 4496 } 4497 4498 pipeline_name = tokens[1]; 4499 4500 if (strcmp(tokens[2], "table") != 0) { 4501 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4502 return; 4503 } 4504 4505 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4506 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4507 return; 4508 } 4509 4510 if (strcmp(tokens[4], "rule") != 0) { 4511 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4512 return; 4513 } 4514 4515 if (strcmp(tokens[5], "add") != 0) { 4516 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 4517 return; 4518 } 4519 4520 if (strcmp(tokens[6], "bulk") != 0) { 4521 snprintf(out, out_size, MSG_ARG_INVALID, "bulk"); 4522 return; 4523 } 4524 4525 file_name = tokens[7]; 4526 4527 /* Load rules from file. */ 4528 status = cli_rule_file_process(file_name, 4529 1024, 4530 &list, 4531 &n_rules, 4532 &line_number, 4533 out, 4534 out_size); 4535 if (status) { 4536 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 4537 return; 4538 } 4539 4540 /* Rule bulk add */ 4541 status = pipeline_table_rule_add_bulk(pipeline_name, 4542 table_id, 4543 list, 4544 &n_rules_added, 4545 &n_rules_not_added); 4546 if (status) { 4547 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4548 return; 4549 } 4550 4551 snprintf(out, out_size, "Added %u rules out of %u.\n", 4552 n_rules_added, 4553 n_rules); 4554 } 4555 4556 4557 static const char cmd_pipeline_table_rule_delete_help[] = 4558 "pipeline <pipeline_name> table <table_id> rule delete\n" 4559 " match <match>\n"; 4560 4561 static void 4562 cmd_pipeline_table_rule_delete(char **tokens, 4563 uint32_t n_tokens, 4564 char *out, 4565 size_t out_size) 4566 { 4567 struct table_rule_match m; 4568 char *pipeline_name; 4569 uint32_t table_id, n_tokens_parsed, t0; 4570 int status; 4571 4572 if (n_tokens < 8) { 4573 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4574 return; 4575 } 4576 4577 pipeline_name = tokens[1]; 4578 4579 if (strcmp(tokens[2], "table") != 0) { 4580 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4581 return; 4582 } 4583 4584 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4585 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4586 return; 4587 } 4588 4589 if (strcmp(tokens[4], "rule") != 0) { 4590 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4591 return; 4592 } 4593 4594 if (strcmp(tokens[5], "delete") != 0) { 4595 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4596 return; 4597 } 4598 4599 t0 = 6; 4600 4601 /* match */ 4602 n_tokens_parsed = parse_match(tokens + t0, 4603 n_tokens - t0, 4604 out, 4605 out_size, 4606 &m); 4607 if (n_tokens_parsed == 0) 4608 return; 4609 t0 += n_tokens_parsed; 4610 4611 if (n_tokens != t0) { 4612 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4613 return; 4614 } 4615 4616 status = pipeline_table_rule_delete(pipeline_name, 4617 table_id, 4618 &m); 4619 if (status) { 4620 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4621 return; 4622 } 4623 } 4624 4625 4626 static const char cmd_pipeline_table_rule_delete_default_help[] = 4627 "pipeline <pipeline_name> table <table_id> rule delete\n" 4628 " match\n" 4629 " default\n"; 4630 4631 static void 4632 cmd_pipeline_table_rule_delete_default(char **tokens, 4633 uint32_t n_tokens, 4634 char *out, 4635 size_t out_size) 4636 { 4637 char *pipeline_name; 4638 uint32_t table_id; 4639 int status; 4640 4641 if (n_tokens != 8) { 4642 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 4643 return; 4644 } 4645 4646 pipeline_name = tokens[1]; 4647 4648 if (strcmp(tokens[2], "table") != 0) { 4649 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 4650 return; 4651 } 4652 4653 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 4654 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 4655 return; 4656 } 4657 4658 if (strcmp(tokens[4], "rule") != 0) { 4659 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 4660 return; 4661 } 4662 4663 if (strcmp(tokens[5], "delete") != 0) { 4664 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 4665 return; 4666 } 4667 4668 if (strcmp(tokens[6], "match") != 0) { 4669 snprintf(out, out_size, MSG_ARG_INVALID, "match"); 4670 return; 4671 } 4672 4673 if (strcmp(tokens[7], "default") != 0) { 4674 snprintf(out, out_size, MSG_ARG_INVALID, "default"); 4675 return; 4676 } 4677 4678 status = pipeline_table_rule_delete_default(pipeline_name, 4679 table_id); 4680 if (status) { 4681 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 4682 return; 4683 } 4684 } 4685 4686 static void 4687 ether_addr_show(FILE *f, struct rte_ether_addr *addr) 4688 { 4689 fprintf(f, RTE_ETHER_ADDR_PRT_FMT, RTE_ETHER_ADDR_BYTES(addr)); 4690 } 4691 4692 static void 4693 ipv4_addr_show(FILE *f, uint32_t addr) 4694 { 4695 fprintf(f, "%u.%u.%u.%u", 4696 addr >> 24, 4697 (addr >> 16) & 0xFF, 4698 (addr >> 8) & 0xFF, 4699 addr & 0xFF); 4700 } 4701 4702 static void 4703 ipv6_addr_show(FILE *f, uint8_t *addr) 4704 { 4705 fprintf(f, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" 4706 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:", 4707 (uint32_t)addr[0], (uint32_t)addr[1], 4708 (uint32_t)addr[2], (uint32_t)addr[3], 4709 (uint32_t)addr[4], (uint32_t)addr[5], 4710 (uint32_t)addr[6], (uint32_t)addr[7], 4711 (uint32_t)addr[8], (uint32_t)addr[9], 4712 (uint32_t)addr[10], (uint32_t)addr[11], 4713 (uint32_t)addr[12], (uint32_t)addr[13], 4714 (uint32_t)addr[14], (uint32_t)addr[15]); 4715 } 4716 4717 static const char * 4718 policer_action_string(enum rte_table_action_policer action) { 4719 switch (action) { 4720 case RTE_TABLE_ACTION_POLICER_COLOR_GREEN: return "G"; 4721 case RTE_TABLE_ACTION_POLICER_COLOR_YELLOW: return "Y"; 4722 case RTE_TABLE_ACTION_POLICER_COLOR_RED: return "R"; 4723 case RTE_TABLE_ACTION_POLICER_DROP: return "D"; 4724 default: return "?"; 4725 } 4726 } 4727 4728 static int 4729 table_rule_show(const char *pipeline_name, 4730 uint32_t table_id, 4731 const char *file_name) 4732 { 4733 struct pipeline *p; 4734 struct table *table; 4735 struct table_rule *rule; 4736 FILE *f = NULL; 4737 uint32_t i; 4738 4739 /* Check input params. */ 4740 if ((pipeline_name == NULL) || 4741 (file_name == NULL)) 4742 return -1; 4743 4744 p = pipeline_find(pipeline_name); 4745 if ((p == NULL) || 4746 (table_id >= p->n_tables)) 4747 return -1; 4748 4749 table = &p->table[table_id]; 4750 4751 /* Open file. */ 4752 f = fopen(file_name, "w"); 4753 if (f == NULL) 4754 return -1; 4755 4756 /* Write table rules to file. */ 4757 TAILQ_FOREACH(rule, &table->rules, node) { 4758 struct table_rule_match *m = &rule->match; 4759 struct table_rule_action *a = &rule->action; 4760 4761 fprintf(f, "match "); 4762 switch (m->match_type) { 4763 case TABLE_ACL: 4764 fprintf(f, "acl priority %u ", 4765 m->match.acl.priority); 4766 4767 fprintf(f, m->match.acl.ip_version ? "ipv4 " : "ipv6 "); 4768 4769 if (m->match.acl.ip_version) 4770 ipv4_addr_show(f, m->match.acl.ipv4.sa); 4771 else 4772 ipv6_addr_show(f, m->match.acl.ipv6.sa); 4773 4774 fprintf(f, "%u", m->match.acl.sa_depth); 4775 4776 if (m->match.acl.ip_version) 4777 ipv4_addr_show(f, m->match.acl.ipv4.da); 4778 else 4779 ipv6_addr_show(f, m->match.acl.ipv6.da); 4780 4781 fprintf(f, "%u", m->match.acl.da_depth); 4782 4783 fprintf(f, "%u %u %u %u %u ", 4784 (uint32_t)m->match.acl.sp0, 4785 (uint32_t)m->match.acl.sp1, 4786 (uint32_t)m->match.acl.dp0, 4787 (uint32_t)m->match.acl.dp1, 4788 (uint32_t)m->match.acl.proto); 4789 break; 4790 4791 case TABLE_ARRAY: 4792 fprintf(f, "array %u ", 4793 m->match.array.pos); 4794 break; 4795 4796 case TABLE_HASH: 4797 fprintf(f, "hash raw "); 4798 for (i = 0; i < table->params.match.hash.key_size; i++) 4799 fprintf(f, "%02x", m->match.hash.key[i]); 4800 fprintf(f, " "); 4801 break; 4802 4803 case TABLE_LPM: 4804 fprintf(f, "lpm "); 4805 4806 fprintf(f, m->match.lpm.ip_version ? "ipv4 " : "ipv6 "); 4807 4808 if (m->match.acl.ip_version) 4809 ipv4_addr_show(f, m->match.lpm.ipv4); 4810 else 4811 ipv6_addr_show(f, m->match.lpm.ipv6); 4812 4813 fprintf(f, "%u ", 4814 (uint32_t)m->match.lpm.depth); 4815 break; 4816 4817 default: 4818 fprintf(f, "unknown "); 4819 } 4820 4821 fprintf(f, "action "); 4822 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) { 4823 fprintf(f, "fwd "); 4824 switch (a->fwd.action) { 4825 case RTE_PIPELINE_ACTION_DROP: 4826 fprintf(f, "drop "); 4827 break; 4828 4829 case RTE_PIPELINE_ACTION_PORT: 4830 fprintf(f, "port %u ", a->fwd.id); 4831 break; 4832 4833 case RTE_PIPELINE_ACTION_PORT_META: 4834 fprintf(f, "meta "); 4835 break; 4836 4837 case RTE_PIPELINE_ACTION_TABLE: 4838 default: 4839 fprintf(f, "table %u ", a->fwd.id); 4840 } 4841 } 4842 4843 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) { 4844 fprintf(f, "balance "); 4845 for (i = 0; i < RTE_DIM(a->lb.out); i++) 4846 fprintf(f, "%u ", a->lb.out[i]); 4847 } 4848 4849 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) { 4850 fprintf(f, "mtr "); 4851 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) 4852 if (a->mtr.tc_mask & (1 << i)) { 4853 struct rte_table_action_mtr_tc_params *p = 4854 &a->mtr.mtr[i]; 4855 enum rte_table_action_policer ga = 4856 p->policer[RTE_COLOR_GREEN]; 4857 enum rte_table_action_policer ya = 4858 p->policer[RTE_COLOR_YELLOW]; 4859 enum rte_table_action_policer ra = 4860 p->policer[RTE_COLOR_RED]; 4861 4862 fprintf(f, "tc%u meter %u policer g %s y %s r %s ", 4863 i, 4864 a->mtr.mtr[i].meter_profile_id, 4865 policer_action_string(ga), 4866 policer_action_string(ya), 4867 policer_action_string(ra)); 4868 } 4869 } 4870 4871 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) 4872 fprintf(f, "tm subport %u pipe %u ", 4873 a->tm.subport_id, 4874 a->tm.pipe_id); 4875 4876 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) { 4877 fprintf(f, "encap "); 4878 switch (a->encap.type) { 4879 case RTE_TABLE_ACTION_ENCAP_ETHER: 4880 fprintf(f, "ether "); 4881 ether_addr_show(f, &a->encap.ether.ether.da); 4882 fprintf(f, " "); 4883 ether_addr_show(f, &a->encap.ether.ether.sa); 4884 fprintf(f, " "); 4885 break; 4886 4887 case RTE_TABLE_ACTION_ENCAP_VLAN: 4888 fprintf(f, "vlan "); 4889 ether_addr_show(f, &a->encap.vlan.ether.da); 4890 fprintf(f, " "); 4891 ether_addr_show(f, &a->encap.vlan.ether.sa); 4892 fprintf(f, " pcp %u dei %u vid %u ", 4893 a->encap.vlan.vlan.pcp, 4894 a->encap.vlan.vlan.dei, 4895 a->encap.vlan.vlan.vid); 4896 break; 4897 4898 case RTE_TABLE_ACTION_ENCAP_QINQ: 4899 fprintf(f, "qinq "); 4900 ether_addr_show(f, &a->encap.qinq.ether.da); 4901 fprintf(f, " "); 4902 ether_addr_show(f, &a->encap.qinq.ether.sa); 4903 fprintf(f, " pcp %u dei %u vid %u pcp %u dei %u vid %u ", 4904 a->encap.qinq.svlan.pcp, 4905 a->encap.qinq.svlan.dei, 4906 a->encap.qinq.svlan.vid, 4907 a->encap.qinq.cvlan.pcp, 4908 a->encap.qinq.cvlan.dei, 4909 a->encap.qinq.cvlan.vid); 4910 break; 4911 4912 case RTE_TABLE_ACTION_ENCAP_MPLS: 4913 fprintf(f, "mpls %s ", (a->encap.mpls.unicast) ? 4914 "unicast " : "multicast "); 4915 ether_addr_show(f, &a->encap.mpls.ether.da); 4916 fprintf(f, " "); 4917 ether_addr_show(f, &a->encap.mpls.ether.sa); 4918 fprintf(f, " "); 4919 for (i = 0; i < a->encap.mpls.mpls_count; i++) { 4920 struct rte_table_action_mpls_hdr *l = 4921 &a->encap.mpls.mpls[i]; 4922 4923 fprintf(f, "label%u %u %u %u ", 4924 i, 4925 l->label, 4926 l->tc, 4927 l->ttl); 4928 } 4929 break; 4930 4931 case RTE_TABLE_ACTION_ENCAP_PPPOE: 4932 fprintf(f, "pppoe "); 4933 ether_addr_show(f, &a->encap.pppoe.ether.da); 4934 fprintf(f, " "); 4935 ether_addr_show(f, &a->encap.pppoe.ether.sa); 4936 fprintf(f, " %u ", a->encap.pppoe.pppoe.session_id); 4937 break; 4938 4939 case RTE_TABLE_ACTION_ENCAP_VXLAN: 4940 fprintf(f, "vxlan ether "); 4941 ether_addr_show(f, &a->encap.vxlan.ether.da); 4942 fprintf(f, " "); 4943 ether_addr_show(f, &a->encap.vxlan.ether.sa); 4944 if (table->ap->params.encap.vxlan.vlan) 4945 fprintf(f, " vlan pcp %u dei %u vid %u ", 4946 a->encap.vxlan.vlan.pcp, 4947 a->encap.vxlan.vlan.dei, 4948 a->encap.vxlan.vlan.vid); 4949 if (table->ap->params.encap.vxlan.ip_version) { 4950 fprintf(f, " ipv4 "); 4951 ipv4_addr_show(f, a->encap.vxlan.ipv4.sa); 4952 fprintf(f, " "); 4953 ipv4_addr_show(f, a->encap.vxlan.ipv4.da); 4954 fprintf(f, " %u %u ", 4955 (uint32_t)a->encap.vxlan.ipv4.dscp, 4956 (uint32_t)a->encap.vxlan.ipv4.ttl); 4957 } else { 4958 fprintf(f, " ipv6 "); 4959 ipv6_addr_show(f, a->encap.vxlan.ipv6.sa); 4960 fprintf(f, " "); 4961 ipv6_addr_show(f, a->encap.vxlan.ipv6.da); 4962 fprintf(f, " %u %u %u ", 4963 a->encap.vxlan.ipv6.flow_label, 4964 (uint32_t)a->encap.vxlan.ipv6.dscp, 4965 (uint32_t)a->encap.vxlan.ipv6.hop_limit); 4966 fprintf(f, " udp %u %u vxlan %u ", 4967 a->encap.vxlan.udp.sp, 4968 a->encap.vxlan.udp.dp, 4969 a->encap.vxlan.vxlan.vni); 4970 } 4971 break; 4972 4973 default: 4974 fprintf(f, "unknown "); 4975 } 4976 } 4977 4978 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) { 4979 fprintf(f, "nat %s ", (a->nat.ip_version) ? "ipv4 " : "ipv6 "); 4980 if (a->nat.ip_version) 4981 ipv4_addr_show(f, a->nat.addr.ipv4); 4982 else 4983 ipv6_addr_show(f, a->nat.addr.ipv6); 4984 fprintf(f, " %u ", (uint32_t)(a->nat.port)); 4985 } 4986 4987 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) 4988 fprintf(f, "ttl %s ", (a->ttl.decrement) ? "dec" : "keep"); 4989 4990 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) 4991 fprintf(f, "stats "); 4992 4993 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) 4994 fprintf(f, "time "); 4995 4996 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) 4997 fprintf(f, "sym_crypto "); 4998 4999 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) 5000 fprintf(f, "tag %u ", a->tag.tag); 5001 5002 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) 5003 fprintf(f, "decap %u ", a->decap.n); 5004 5005 /* end */ 5006 fprintf(f, "\n"); 5007 } 5008 5009 /* Write table default rule to file. */ 5010 if (table->rule_default) { 5011 struct table_rule_action *a = &table->rule_default->action; 5012 5013 fprintf(f, "# match default action fwd "); 5014 5015 switch (a->fwd.action) { 5016 case RTE_PIPELINE_ACTION_DROP: 5017 fprintf(f, "drop "); 5018 break; 5019 5020 case RTE_PIPELINE_ACTION_PORT: 5021 fprintf(f, "port %u ", a->fwd.id); 5022 break; 5023 5024 case RTE_PIPELINE_ACTION_PORT_META: 5025 fprintf(f, "meta "); 5026 break; 5027 5028 case RTE_PIPELINE_ACTION_TABLE: 5029 default: 5030 fprintf(f, "table %u ", a->fwd.id); 5031 } 5032 } else 5033 fprintf(f, "# match default action fwd drop "); 5034 5035 fprintf(f, "\n"); 5036 5037 /* Close file. */ 5038 fclose(f); 5039 5040 return 0; 5041 } 5042 5043 static const char cmd_pipeline_table_rule_show_help[] = 5044 "pipeline <pipeline_name> table <table_id> rule show\n" 5045 " file <file_name>\n"; 5046 5047 static void 5048 cmd_pipeline_table_rule_show(char **tokens, 5049 uint32_t n_tokens, 5050 char *out, 5051 size_t out_size) 5052 { 5053 char *file_name = NULL, *pipeline_name; 5054 uint32_t table_id; 5055 int status; 5056 5057 if (n_tokens != 8) { 5058 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5059 return; 5060 } 5061 5062 pipeline_name = tokens[1]; 5063 5064 if (strcmp(tokens[2], "table") != 0) { 5065 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5066 return; 5067 } 5068 5069 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5070 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5071 return; 5072 } 5073 5074 if (strcmp(tokens[4], "rule") != 0) { 5075 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5076 return; 5077 } 5078 5079 if (strcmp(tokens[5], "show") != 0) { 5080 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "show"); 5081 return; 5082 } 5083 5084 if (strcmp(tokens[6], "file") != 0) { 5085 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file"); 5086 return; 5087 } 5088 5089 file_name = tokens[7]; 5090 5091 status = table_rule_show(pipeline_name, table_id, file_name); 5092 if (status) { 5093 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5094 return; 5095 } 5096 } 5097 5098 static const char cmd_pipeline_table_rule_stats_read_help[] = 5099 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n" 5100 " match <match>\n"; 5101 5102 static void 5103 cmd_pipeline_table_rule_stats_read(char **tokens, 5104 uint32_t n_tokens, 5105 char *out, 5106 size_t out_size) 5107 { 5108 struct table_rule_match m; 5109 struct rte_table_action_stats_counters stats; 5110 char *pipeline_name; 5111 uint32_t table_id, n_tokens_parsed; 5112 int clear = 0, status; 5113 5114 if (n_tokens < 7) { 5115 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5116 return; 5117 } 5118 5119 pipeline_name = tokens[1]; 5120 5121 if (strcmp(tokens[2], "table") != 0) { 5122 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5123 return; 5124 } 5125 5126 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5127 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5128 return; 5129 } 5130 5131 if (strcmp(tokens[4], "rule") != 0) { 5132 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5133 return; 5134 } 5135 5136 if (strcmp(tokens[5], "read") != 0) { 5137 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5138 return; 5139 } 5140 5141 if (strcmp(tokens[6], "stats") != 0) { 5142 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 5143 return; 5144 } 5145 5146 n_tokens -= 7; 5147 tokens += 7; 5148 5149 /* clear */ 5150 if (n_tokens && (strcmp(tokens[0], "clear") == 0)) { 5151 clear = 1; 5152 5153 n_tokens--; 5154 tokens++; 5155 } 5156 5157 /* match */ 5158 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5159 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5160 return; 5161 } 5162 5163 n_tokens_parsed = parse_match(tokens, 5164 n_tokens, 5165 out, 5166 out_size, 5167 &m); 5168 if (n_tokens_parsed == 0) 5169 return; 5170 n_tokens -= n_tokens_parsed; 5171 tokens += n_tokens_parsed; 5172 5173 /* end */ 5174 if (n_tokens) { 5175 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5176 return; 5177 } 5178 5179 /* Read table rule stats. */ 5180 status = pipeline_table_rule_stats_read(pipeline_name, 5181 table_id, 5182 &m, 5183 &stats, 5184 clear); 5185 if (status) { 5186 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5187 return; 5188 } 5189 5190 /* Print stats. */ 5191 if (stats.n_packets_valid && stats.n_bytes_valid) 5192 snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n", 5193 stats.n_packets, 5194 stats.n_bytes); 5195 5196 if (stats.n_packets_valid && !stats.n_bytes_valid) 5197 snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n", 5198 stats.n_packets); 5199 5200 if (!stats.n_packets_valid && stats.n_bytes_valid) 5201 snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n", 5202 stats.n_bytes); 5203 5204 if (!stats.n_packets_valid && !stats.n_bytes_valid) 5205 snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n"); 5206 } 5207 5208 static const char cmd_pipeline_table_meter_profile_add_help[] = 5209 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n" 5210 " add srtcm cir <cir> cbs <cbs> ebs <ebs>\n" 5211 " | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 5212 5213 static void 5214 cmd_pipeline_table_meter_profile_add(char **tokens, 5215 uint32_t n_tokens, 5216 char *out, 5217 size_t out_size) 5218 { 5219 struct rte_table_action_meter_profile p; 5220 char *pipeline_name; 5221 uint32_t table_id, meter_profile_id; 5222 int status; 5223 5224 if (n_tokens < 9) { 5225 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5226 return; 5227 } 5228 5229 pipeline_name = tokens[1]; 5230 5231 if (strcmp(tokens[2], "table") != 0) { 5232 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5233 return; 5234 } 5235 5236 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5237 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5238 return; 5239 } 5240 5241 if (strcmp(tokens[4], "meter") != 0) { 5242 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5243 return; 5244 } 5245 5246 if (strcmp(tokens[5], "profile") != 0) { 5247 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 5248 return; 5249 } 5250 5251 if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 5252 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 5253 return; 5254 } 5255 5256 if (strcmp(tokens[7], "add") != 0) { 5257 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 5258 return; 5259 } 5260 5261 if (strcmp(tokens[8], "srtcm") == 0) { 5262 if (n_tokens != 15) { 5263 snprintf(out, out_size, MSG_ARG_MISMATCH, 5264 tokens[0]); 5265 return; 5266 } 5267 5268 p.alg = RTE_TABLE_ACTION_METER_SRTCM; 5269 5270 if (strcmp(tokens[9], "cir") != 0) { 5271 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 5272 return; 5273 } 5274 5275 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) { 5276 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 5277 return; 5278 } 5279 5280 if (strcmp(tokens[11], "cbs") != 0) { 5281 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 5282 return; 5283 } 5284 5285 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) { 5286 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 5287 return; 5288 } 5289 5290 if (strcmp(tokens[13], "ebs") != 0) { 5291 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs"); 5292 return; 5293 } 5294 5295 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) { 5296 snprintf(out, out_size, MSG_ARG_INVALID, "ebs"); 5297 return; 5298 } 5299 } else if (strcmp(tokens[8], "trtcm") == 0) { 5300 if (n_tokens != 17) { 5301 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5302 return; 5303 } 5304 5305 p.alg = RTE_TABLE_ACTION_METER_TRTCM; 5306 5307 if (strcmp(tokens[9], "cir") != 0) { 5308 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 5309 return; 5310 } 5311 5312 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) { 5313 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 5314 return; 5315 } 5316 5317 if (strcmp(tokens[11], "pir") != 0) { 5318 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 5319 return; 5320 } 5321 5322 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) { 5323 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 5324 return; 5325 } 5326 if (strcmp(tokens[13], "cbs") != 0) { 5327 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 5328 return; 5329 } 5330 5331 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) { 5332 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 5333 return; 5334 } 5335 5336 if (strcmp(tokens[15], "pbs") != 0) { 5337 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 5338 return; 5339 } 5340 5341 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) { 5342 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 5343 return; 5344 } 5345 } else { 5346 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5347 return; 5348 } 5349 5350 status = pipeline_table_mtr_profile_add(pipeline_name, 5351 table_id, 5352 meter_profile_id, 5353 &p); 5354 if (status) { 5355 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5356 return; 5357 } 5358 } 5359 5360 5361 static const char cmd_pipeline_table_meter_profile_delete_help[] = 5362 "pipeline <pipeline_name> table <table_id>\n" 5363 " meter profile <meter_profile_id> delete\n"; 5364 5365 static void 5366 cmd_pipeline_table_meter_profile_delete(char **tokens, 5367 uint32_t n_tokens, 5368 char *out, 5369 size_t out_size) 5370 { 5371 char *pipeline_name; 5372 uint32_t table_id, meter_profile_id; 5373 int status; 5374 5375 if (n_tokens != 8) { 5376 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5377 return; 5378 } 5379 5380 pipeline_name = tokens[1]; 5381 5382 if (strcmp(tokens[2], "table") != 0) { 5383 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5384 return; 5385 } 5386 5387 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5388 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5389 return; 5390 } 5391 5392 if (strcmp(tokens[4], "meter") != 0) { 5393 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5394 return; 5395 } 5396 5397 if (strcmp(tokens[5], "profile") != 0) { 5398 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 5399 return; 5400 } 5401 5402 if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 5403 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 5404 return; 5405 } 5406 5407 if (strcmp(tokens[7], "delete") != 0) { 5408 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 5409 return; 5410 } 5411 5412 status = pipeline_table_mtr_profile_delete(pipeline_name, 5413 table_id, 5414 meter_profile_id); 5415 if (status) { 5416 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5417 return; 5418 } 5419 } 5420 5421 5422 static const char cmd_pipeline_table_rule_meter_read_help[] = 5423 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n" 5424 " match <match>\n"; 5425 5426 static void 5427 cmd_pipeline_table_rule_meter_read(char **tokens, 5428 uint32_t n_tokens, 5429 char *out, 5430 size_t out_size) 5431 { 5432 struct table_rule_match m; 5433 struct rte_table_action_mtr_counters stats; 5434 char *pipeline_name; 5435 uint32_t table_id, n_tokens_parsed; 5436 int clear = 0, status; 5437 5438 if (n_tokens < 7) { 5439 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5440 return; 5441 } 5442 5443 pipeline_name = tokens[1]; 5444 5445 if (strcmp(tokens[2], "table") != 0) { 5446 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5447 return; 5448 } 5449 5450 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5451 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5452 return; 5453 } 5454 5455 if (strcmp(tokens[4], "rule") != 0) { 5456 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5457 return; 5458 } 5459 5460 if (strcmp(tokens[5], "read") != 0) { 5461 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5462 return; 5463 } 5464 5465 if (strcmp(tokens[6], "meter") != 0) { 5466 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5467 return; 5468 } 5469 5470 n_tokens -= 7; 5471 tokens += 7; 5472 5473 /* clear */ 5474 if (n_tokens && (strcmp(tokens[0], "clear") == 0)) { 5475 clear = 1; 5476 5477 n_tokens--; 5478 tokens++; 5479 } 5480 5481 /* match */ 5482 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5483 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5484 return; 5485 } 5486 5487 n_tokens_parsed = parse_match(tokens, 5488 n_tokens, 5489 out, 5490 out_size, 5491 &m); 5492 if (n_tokens_parsed == 0) 5493 return; 5494 n_tokens -= n_tokens_parsed; 5495 tokens += n_tokens_parsed; 5496 5497 /* end */ 5498 if (n_tokens) { 5499 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5500 return; 5501 } 5502 5503 /* Read table rule meter stats. */ 5504 status = pipeline_table_rule_mtr_read(pipeline_name, 5505 table_id, 5506 &m, 5507 &stats, 5508 clear); 5509 if (status) { 5510 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5511 return; 5512 } 5513 5514 /* Print stats. */ 5515 } 5516 5517 5518 static const char cmd_pipeline_table_dscp_help[] = 5519 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n" 5520 "\n" 5521 " File <file_name>:\n" 5522 " - exactly 64 lines\n" 5523 " - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n"; 5524 5525 static int 5526 load_dscp_table(struct rte_table_action_dscp_table *dscp_table, 5527 const char *file_name, 5528 uint32_t *line_number) 5529 { 5530 FILE *f = NULL; 5531 uint32_t dscp, l; 5532 5533 /* Check input arguments */ 5534 if ((dscp_table == NULL) || 5535 (file_name == NULL) || 5536 (line_number == NULL)) { 5537 if (line_number) 5538 *line_number = 0; 5539 return -EINVAL; 5540 } 5541 5542 /* Open input file */ 5543 f = fopen(file_name, "r"); 5544 if (f == NULL) { 5545 *line_number = 0; 5546 return -EINVAL; 5547 } 5548 5549 /* Read file */ 5550 for (dscp = 0, l = 1; ; l++) { 5551 char line[64]; 5552 char *tokens[3]; 5553 enum rte_color color; 5554 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens); 5555 5556 if (fgets(line, sizeof(line), f) == NULL) 5557 break; 5558 5559 if (is_comment(line)) 5560 continue; 5561 5562 if (parse_tokenize_string(line, tokens, &n_tokens)) { 5563 *line_number = l; 5564 fclose(f); 5565 return -EINVAL; 5566 } 5567 5568 if (n_tokens == 0) 5569 continue; 5570 5571 if ((dscp >= RTE_DIM(dscp_table->entry)) || 5572 (n_tokens != RTE_DIM(tokens)) || 5573 parser_read_uint32(&tc_id, tokens[0]) || 5574 (tc_id >= RTE_TABLE_ACTION_TC_MAX) || 5575 parser_read_uint32(&tc_queue_id, tokens[1]) || 5576 (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) || 5577 (strlen(tokens[2]) != 1)) { 5578 *line_number = l; 5579 fclose(f); 5580 return -EINVAL; 5581 } 5582 5583 switch (tokens[2][0]) { 5584 case 'g': 5585 case 'G': 5586 color = RTE_COLOR_GREEN; 5587 break; 5588 5589 case 'y': 5590 case 'Y': 5591 color = RTE_COLOR_YELLOW; 5592 break; 5593 5594 case 'r': 5595 case 'R': 5596 color = RTE_COLOR_RED; 5597 break; 5598 5599 default: 5600 *line_number = l; 5601 fclose(f); 5602 return -EINVAL; 5603 } 5604 5605 dscp_table->entry[dscp].tc_id = tc_id; 5606 dscp_table->entry[dscp].tc_queue_id = tc_queue_id; 5607 dscp_table->entry[dscp].color = color; 5608 dscp++; 5609 } 5610 5611 /* Close file */ 5612 fclose(f); 5613 return 0; 5614 } 5615 5616 static void 5617 cmd_pipeline_table_dscp(char **tokens, 5618 uint32_t n_tokens, 5619 char *out, 5620 size_t out_size) 5621 { 5622 struct rte_table_action_dscp_table dscp_table; 5623 char *pipeline_name, *file_name; 5624 uint32_t table_id, line_number; 5625 int status; 5626 5627 if (n_tokens != 6) { 5628 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5629 return; 5630 } 5631 5632 pipeline_name = tokens[1]; 5633 5634 if (strcmp(tokens[2], "table") != 0) { 5635 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5636 return; 5637 } 5638 5639 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5640 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5641 return; 5642 } 5643 5644 if (strcmp(tokens[4], "dscp") != 0) { 5645 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp"); 5646 return; 5647 } 5648 5649 file_name = tokens[5]; 5650 5651 status = load_dscp_table(&dscp_table, file_name, &line_number); 5652 if (status) { 5653 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 5654 return; 5655 } 5656 5657 status = pipeline_table_dscp_table_update(pipeline_name, 5658 table_id, 5659 UINT64_MAX, 5660 &dscp_table); 5661 if (status) { 5662 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5663 return; 5664 } 5665 } 5666 5667 5668 static const char cmd_pipeline_table_rule_ttl_read_help[] = 5669 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n" 5670 " match <match>\n"; 5671 5672 static void 5673 cmd_pipeline_table_rule_ttl_read(char **tokens, 5674 uint32_t n_tokens, 5675 char *out, 5676 size_t out_size) 5677 { 5678 struct table_rule_match m; 5679 struct rte_table_action_ttl_counters stats; 5680 char *pipeline_name; 5681 uint32_t table_id, n_tokens_parsed; 5682 int clear = 0, status; 5683 5684 if (n_tokens < 7) { 5685 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5686 return; 5687 } 5688 5689 pipeline_name = tokens[1]; 5690 5691 if (strcmp(tokens[2], "table") != 0) { 5692 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5693 return; 5694 } 5695 5696 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5697 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5698 return; 5699 } 5700 5701 if (strcmp(tokens[4], "rule") != 0) { 5702 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5703 return; 5704 } 5705 5706 if (strcmp(tokens[5], "read") != 0) { 5707 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5708 return; 5709 } 5710 5711 if (strcmp(tokens[6], "ttl") != 0) { 5712 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl"); 5713 return; 5714 } 5715 5716 n_tokens -= 7; 5717 tokens += 7; 5718 5719 /* clear */ 5720 if (n_tokens && (strcmp(tokens[0], "clear") == 0)) { 5721 clear = 1; 5722 5723 n_tokens--; 5724 tokens++; 5725 } 5726 5727 /* match */ 5728 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5729 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5730 return; 5731 } 5732 5733 n_tokens_parsed = parse_match(tokens, 5734 n_tokens, 5735 out, 5736 out_size, 5737 &m); 5738 if (n_tokens_parsed == 0) 5739 return; 5740 n_tokens -= n_tokens_parsed; 5741 tokens += n_tokens_parsed; 5742 5743 /* end */ 5744 if (n_tokens) { 5745 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5746 return; 5747 } 5748 5749 /* Read table rule TTL stats. */ 5750 status = pipeline_table_rule_ttl_read(pipeline_name, 5751 table_id, 5752 &m, 5753 &stats, 5754 clear); 5755 if (status) { 5756 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5757 return; 5758 } 5759 5760 /* Print stats. */ 5761 snprintf(out, out_size, "Packets: %" PRIu64 "\n", 5762 stats.n_packets); 5763 } 5764 5765 static const char cmd_pipeline_table_rule_time_read_help[] = 5766 "pipeline <pipeline_name> table <table_id> rule read time\n" 5767 " match <match>\n"; 5768 5769 static void 5770 cmd_pipeline_table_rule_time_read(char **tokens, 5771 uint32_t n_tokens, 5772 char *out, 5773 size_t out_size) 5774 { 5775 struct table_rule_match m; 5776 char *pipeline_name; 5777 uint64_t timestamp; 5778 uint32_t table_id, n_tokens_parsed; 5779 int status; 5780 5781 if (n_tokens < 7) { 5782 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5783 return; 5784 } 5785 5786 pipeline_name = tokens[1]; 5787 5788 if (strcmp(tokens[2], "table") != 0) { 5789 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5790 return; 5791 } 5792 5793 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5794 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5795 return; 5796 } 5797 5798 if (strcmp(tokens[4], "rule") != 0) { 5799 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5800 return; 5801 } 5802 5803 if (strcmp(tokens[5], "read") != 0) { 5804 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5805 return; 5806 } 5807 5808 if (strcmp(tokens[6], "time") != 0) { 5809 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "time"); 5810 return; 5811 } 5812 5813 n_tokens -= 7; 5814 tokens += 7; 5815 5816 /* match */ 5817 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5818 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5819 return; 5820 } 5821 5822 n_tokens_parsed = parse_match(tokens, 5823 n_tokens, 5824 out, 5825 out_size, 5826 &m); 5827 if (n_tokens_parsed == 0) 5828 return; 5829 n_tokens -= n_tokens_parsed; 5830 tokens += n_tokens_parsed; 5831 5832 /* end */ 5833 if (n_tokens) { 5834 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5835 return; 5836 } 5837 5838 /* Read table rule timestamp. */ 5839 status = pipeline_table_rule_time_read(pipeline_name, 5840 table_id, 5841 &m, 5842 ×tamp); 5843 if (status) { 5844 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5845 return; 5846 } 5847 5848 /* Print stats. */ 5849 snprintf(out, out_size, "Packets: %" PRIu64 "\n", timestamp); 5850 } 5851 5852 static const char cmd_thread_pipeline_enable_help[] = 5853 "thread <thread_id> pipeline <pipeline_name> enable\n"; 5854 5855 static void 5856 cmd_thread_pipeline_enable(char **tokens, 5857 uint32_t n_tokens, 5858 char *out, 5859 size_t out_size) 5860 { 5861 char *pipeline_name; 5862 uint32_t thread_id; 5863 int status; 5864 5865 if (n_tokens != 5) { 5866 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5867 return; 5868 } 5869 5870 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 5871 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 5872 return; 5873 } 5874 5875 if (strcmp(tokens[2], "pipeline") != 0) { 5876 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5877 return; 5878 } 5879 5880 pipeline_name = tokens[3]; 5881 5882 if (strcmp(tokens[4], "enable") != 0) { 5883 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 5884 return; 5885 } 5886 5887 status = thread_pipeline_enable(thread_id, pipeline_name); 5888 if (status) { 5889 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 5890 return; 5891 } 5892 } 5893 5894 5895 static const char cmd_thread_pipeline_disable_help[] = 5896 "thread <thread_id> pipeline <pipeline_name> disable\n"; 5897 5898 static void 5899 cmd_thread_pipeline_disable(char **tokens, 5900 uint32_t n_tokens, 5901 char *out, 5902 size_t out_size) 5903 { 5904 char *pipeline_name; 5905 uint32_t thread_id; 5906 int status; 5907 5908 if (n_tokens != 5) { 5909 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5910 return; 5911 } 5912 5913 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 5914 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 5915 return; 5916 } 5917 5918 if (strcmp(tokens[2], "pipeline") != 0) { 5919 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5920 return; 5921 } 5922 5923 pipeline_name = tokens[3]; 5924 5925 if (strcmp(tokens[4], "disable") != 0) { 5926 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 5927 return; 5928 } 5929 5930 status = thread_pipeline_disable(thread_id, pipeline_name); 5931 if (status) { 5932 snprintf(out, out_size, MSG_CMD_FAIL, 5933 "thread pipeline disable"); 5934 return; 5935 } 5936 } 5937 5938 static void 5939 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size) 5940 { 5941 tokens++; 5942 n_tokens--; 5943 5944 if (n_tokens == 0) { 5945 snprintf(out, out_size, 5946 "Type 'help <command>' for details on each command.\n\n" 5947 "List of commands:\n" 5948 "\tmempool\n" 5949 "\tlink\n" 5950 "\tswq\n" 5951 "\ttmgr subport profile\n" 5952 "\ttmgr pipe profile\n" 5953 "\ttmgr\n" 5954 "\ttmgr subport\n" 5955 "\ttmgr subport pipe\n" 5956 "\ttap\n" 5957 "\tport in action profile\n" 5958 "\ttable action profile\n" 5959 "\tpipeline\n" 5960 "\tpipeline port in\n" 5961 "\tpipeline port out\n" 5962 "\tpipeline table\n" 5963 "\tpipeline port in table\n" 5964 "\tpipeline port in stats\n" 5965 "\tpipeline port in enable\n" 5966 "\tpipeline port in disable\n" 5967 "\tpipeline port out stats\n" 5968 "\tpipeline table stats\n" 5969 "\tpipeline table rule add\n" 5970 "\tpipeline table rule add default\n" 5971 "\tpipeline table rule add bulk\n" 5972 "\tpipeline table rule delete\n" 5973 "\tpipeline table rule delete default\n" 5974 "\tpipeline table rule show\n" 5975 "\tpipeline table rule stats read\n" 5976 "\tpipeline table meter profile add\n" 5977 "\tpipeline table meter profile delete\n" 5978 "\tpipeline table rule meter read\n" 5979 "\tpipeline table dscp\n" 5980 "\tpipeline table rule ttl read\n" 5981 "\tpipeline table rule time read\n" 5982 "\tthread pipeline enable\n" 5983 "\tthread pipeline disable\n\n"); 5984 return; 5985 } 5986 5987 if (strcmp(tokens[0], "mempool") == 0) { 5988 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 5989 return; 5990 } 5991 5992 if (strcmp(tokens[0], "link") == 0) { 5993 snprintf(out, out_size, "\n%s\n", cmd_link_help); 5994 return; 5995 } 5996 5997 if (strcmp(tokens[0], "swq") == 0) { 5998 snprintf(out, out_size, "\n%s\n", cmd_swq_help); 5999 return; 6000 } 6001 6002 if (strcmp(tokens[0], "tmgr") == 0) { 6003 if (n_tokens == 1) { 6004 snprintf(out, out_size, "\n%s\n", cmd_tmgr_help); 6005 return; 6006 } 6007 6008 if ((n_tokens == 2) && 6009 (strcmp(tokens[1], "subport")) == 0) { 6010 snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help); 6011 return; 6012 } 6013 6014 if ((n_tokens == 3) && 6015 (strcmp(tokens[1], "subport") == 0) && 6016 (strcmp(tokens[2], "profile") == 0)) { 6017 snprintf(out, out_size, "\n%s\n", 6018 cmd_tmgr_subport_profile_help); 6019 return; 6020 } 6021 6022 if ((n_tokens == 3) && 6023 (strcmp(tokens[1], "subport") == 0) && 6024 (strcmp(tokens[2], "pipe") == 0)) { 6025 snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help); 6026 return; 6027 } 6028 6029 if ((n_tokens == 3) && 6030 (strcmp(tokens[1], "pipe") == 0) && 6031 (strcmp(tokens[2], "profile") == 0)) { 6032 snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help); 6033 return; 6034 } 6035 } 6036 6037 if (strcmp(tokens[0], "tap") == 0) { 6038 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 6039 return; 6040 } 6041 6042 if (strcmp(tokens[0], "cryptodev") == 0) { 6043 snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help); 6044 return; 6045 } 6046 6047 if ((n_tokens == 4) && 6048 (strcmp(tokens[0], "port") == 0) && 6049 (strcmp(tokens[1], "in") == 0) && 6050 (strcmp(tokens[2], "action") == 0) && 6051 (strcmp(tokens[3], "profile") == 0)) { 6052 snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help); 6053 return; 6054 } 6055 6056 if ((n_tokens == 3) && 6057 (strcmp(tokens[0], "table") == 0) && 6058 (strcmp(tokens[1], "action") == 0) && 6059 (strcmp(tokens[2], "profile") == 0)) { 6060 snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help); 6061 return; 6062 } 6063 6064 if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) { 6065 snprintf(out, out_size, "\n%s\n", cmd_pipeline_help); 6066 return; 6067 } 6068 6069 if ((strcmp(tokens[0], "pipeline") == 0) && 6070 (strcmp(tokens[1], "port") == 0)) { 6071 if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) { 6072 snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help); 6073 return; 6074 } 6075 6076 if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) { 6077 snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help); 6078 return; 6079 } 6080 6081 if ((n_tokens == 4) && 6082 (strcmp(tokens[2], "in") == 0) && 6083 (strcmp(tokens[3], "table") == 0)) { 6084 snprintf(out, out_size, "\n%s\n", 6085 cmd_pipeline_port_in_table_help); 6086 return; 6087 } 6088 6089 if ((n_tokens == 4) && 6090 (strcmp(tokens[2], "in") == 0) && 6091 (strcmp(tokens[3], "stats") == 0)) { 6092 snprintf(out, out_size, "\n%s\n", 6093 cmd_pipeline_port_in_stats_help); 6094 return; 6095 } 6096 6097 if ((n_tokens == 4) && 6098 (strcmp(tokens[2], "in") == 0) && 6099 (strcmp(tokens[3], "enable") == 0)) { 6100 snprintf(out, out_size, "\n%s\n", 6101 cmd_pipeline_port_in_enable_help); 6102 return; 6103 } 6104 6105 if ((n_tokens == 4) && 6106 (strcmp(tokens[2], "in") == 0) && 6107 (strcmp(tokens[3], "disable") == 0)) { 6108 snprintf(out, out_size, "\n%s\n", 6109 cmd_pipeline_port_in_disable_help); 6110 return; 6111 } 6112 6113 if ((n_tokens == 4) && 6114 (strcmp(tokens[2], "out") == 0) && 6115 (strcmp(tokens[3], "stats") == 0)) { 6116 snprintf(out, out_size, "\n%s\n", 6117 cmd_pipeline_port_out_stats_help); 6118 return; 6119 } 6120 } 6121 6122 if ((strcmp(tokens[0], "pipeline") == 0) && 6123 (strcmp(tokens[1], "table") == 0)) { 6124 if (n_tokens == 2) { 6125 snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help); 6126 return; 6127 } 6128 6129 if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) { 6130 snprintf(out, out_size, "\n%s\n", 6131 cmd_pipeline_table_stats_help); 6132 return; 6133 } 6134 6135 if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) { 6136 snprintf(out, out_size, "\n%s\n", 6137 cmd_pipeline_table_dscp_help); 6138 return; 6139 } 6140 6141 if ((n_tokens == 4) && 6142 (strcmp(tokens[2], "rule") == 0) && 6143 (strcmp(tokens[3], "add") == 0)) { 6144 snprintf(out, out_size, "\n%s\n", 6145 cmd_pipeline_table_rule_add_help); 6146 return; 6147 } 6148 6149 if ((n_tokens == 5) && 6150 (strcmp(tokens[2], "rule") == 0) && 6151 (strcmp(tokens[3], "add") == 0) && 6152 (strcmp(tokens[4], "default") == 0)) { 6153 snprintf(out, out_size, "\n%s\n", 6154 cmd_pipeline_table_rule_add_default_help); 6155 return; 6156 } 6157 6158 if ((n_tokens == 5) && 6159 (strcmp(tokens[2], "rule") == 0) && 6160 (strcmp(tokens[3], "add") == 0) && 6161 (strcmp(tokens[4], "bulk") == 0)) { 6162 snprintf(out, out_size, "\n%s\n", 6163 cmd_pipeline_table_rule_add_bulk_help); 6164 return; 6165 } 6166 6167 if ((n_tokens == 4) && 6168 (strcmp(tokens[2], "rule") == 0) && 6169 (strcmp(tokens[3], "delete") == 0)) { 6170 snprintf(out, out_size, "\n%s\n", 6171 cmd_pipeline_table_rule_delete_help); 6172 return; 6173 } 6174 6175 if ((n_tokens == 5) && 6176 (strcmp(tokens[2], "rule") == 0) && 6177 (strcmp(tokens[3], "delete") == 0) && 6178 (strcmp(tokens[4], "default") == 0)) { 6179 snprintf(out, out_size, "\n%s\n", 6180 cmd_pipeline_table_rule_delete_default_help); 6181 return; 6182 } 6183 6184 if ((n_tokens == 4) && 6185 (strcmp(tokens[2], "rule") == 0) && 6186 (strcmp(tokens[3], "show") == 0)) { 6187 snprintf(out, out_size, "\n%s\n", 6188 cmd_pipeline_table_rule_show_help); 6189 return; 6190 } 6191 6192 if ((n_tokens == 5) && 6193 (strcmp(tokens[2], "rule") == 0) && 6194 (strcmp(tokens[3], "stats") == 0) && 6195 (strcmp(tokens[4], "read") == 0)) { 6196 snprintf(out, out_size, "\n%s\n", 6197 cmd_pipeline_table_rule_stats_read_help); 6198 return; 6199 } 6200 6201 if ((n_tokens == 5) && 6202 (strcmp(tokens[2], "meter") == 0) && 6203 (strcmp(tokens[3], "profile") == 0) && 6204 (strcmp(tokens[4], "add") == 0)) { 6205 snprintf(out, out_size, "\n%s\n", 6206 cmd_pipeline_table_meter_profile_add_help); 6207 return; 6208 } 6209 6210 if ((n_tokens == 5) && 6211 (strcmp(tokens[2], "meter") == 0) && 6212 (strcmp(tokens[3], "profile") == 0) && 6213 (strcmp(tokens[4], "delete") == 0)) { 6214 snprintf(out, out_size, "\n%s\n", 6215 cmd_pipeline_table_meter_profile_delete_help); 6216 return; 6217 } 6218 6219 if ((n_tokens == 5) && 6220 (strcmp(tokens[2], "rule") == 0) && 6221 (strcmp(tokens[3], "meter") == 0) && 6222 (strcmp(tokens[4], "read") == 0)) { 6223 snprintf(out, out_size, "\n%s\n", 6224 cmd_pipeline_table_rule_meter_read_help); 6225 return; 6226 } 6227 6228 if ((n_tokens == 5) && 6229 (strcmp(tokens[2], "rule") == 0) && 6230 (strcmp(tokens[3], "ttl") == 0) && 6231 (strcmp(tokens[4], "read") == 0)) { 6232 snprintf(out, out_size, "\n%s\n", 6233 cmd_pipeline_table_rule_ttl_read_help); 6234 return; 6235 } 6236 6237 if ((n_tokens == 5) && 6238 (strcmp(tokens[2], "rule") == 0) && 6239 (strcmp(tokens[3], "time") == 0) && 6240 (strcmp(tokens[4], "read") == 0)) { 6241 snprintf(out, out_size, "\n%s\n", 6242 cmd_pipeline_table_rule_time_read_help); 6243 return; 6244 } 6245 } 6246 6247 if ((n_tokens == 3) && 6248 (strcmp(tokens[0], "thread") == 0) && 6249 (strcmp(tokens[1], "pipeline") == 0)) { 6250 if (strcmp(tokens[2], "enable") == 0) { 6251 snprintf(out, out_size, "\n%s\n", 6252 cmd_thread_pipeline_enable_help); 6253 return; 6254 } 6255 6256 if (strcmp(tokens[2], "disable") == 0) { 6257 snprintf(out, out_size, "\n%s\n", 6258 cmd_thread_pipeline_disable_help); 6259 return; 6260 } 6261 } 6262 6263 snprintf(out, out_size, "Invalid command\n"); 6264 } 6265 6266 void 6267 cli_process(char *in, char *out, size_t out_size) 6268 { 6269 char *tokens[CMD_MAX_TOKENS]; 6270 uint32_t n_tokens = RTE_DIM(tokens); 6271 int status; 6272 6273 if (is_comment(in)) 6274 return; 6275 6276 status = parse_tokenize_string(in, tokens, &n_tokens); 6277 if (status) { 6278 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 6279 return; 6280 } 6281 6282 if (n_tokens == 0) 6283 return; 6284 6285 if (strcmp(tokens[0], "help") == 0) { 6286 cmd_help(tokens, n_tokens, out, out_size); 6287 return; 6288 } 6289 6290 if (strcmp(tokens[0], "mempool") == 0) { 6291 cmd_mempool(tokens, n_tokens, out, out_size); 6292 return; 6293 } 6294 6295 if (strcmp(tokens[0], "link") == 0) { 6296 if (strcmp(tokens[1], "show") == 0) { 6297 cmd_link_show(tokens, n_tokens, out, out_size); 6298 return; 6299 } 6300 6301 cmd_link(tokens, n_tokens, out, out_size); 6302 return; 6303 } 6304 6305 if (strcmp(tokens[0], "swq") == 0) { 6306 cmd_swq(tokens, n_tokens, out, out_size); 6307 return; 6308 } 6309 6310 if (strcmp(tokens[0], "tmgr") == 0) { 6311 if ((n_tokens >= 3) && 6312 (strcmp(tokens[1], "subport") == 0) && 6313 (strcmp(tokens[2], "profile") == 0)) { 6314 cmd_tmgr_subport_profile(tokens, n_tokens, 6315 out, out_size); 6316 return; 6317 } 6318 6319 if ((n_tokens >= 3) && 6320 (strcmp(tokens[1], "pipe") == 0) && 6321 (strcmp(tokens[2], "profile") == 0)) { 6322 cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size); 6323 return; 6324 } 6325 6326 if ((n_tokens >= 5) && 6327 (strcmp(tokens[2], "subport") == 0) && 6328 (strcmp(tokens[4], "profile") == 0)) { 6329 cmd_tmgr_subport(tokens, n_tokens, out, out_size); 6330 return; 6331 } 6332 6333 if ((n_tokens >= 5) && 6334 (strcmp(tokens[2], "subport") == 0) && 6335 (strcmp(tokens[4], "pipe") == 0)) { 6336 cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size); 6337 return; 6338 } 6339 6340 cmd_tmgr(tokens, n_tokens, out, out_size); 6341 return; 6342 } 6343 6344 if (strcmp(tokens[0], "tap") == 0) { 6345 cmd_tap(tokens, n_tokens, out, out_size); 6346 return; 6347 } 6348 6349 if (strcmp(tokens[0], "cryptodev") == 0) { 6350 cmd_cryptodev(tokens, n_tokens, out, out_size); 6351 return; 6352 } 6353 6354 if (strcmp(tokens[0], "port") == 0) { 6355 cmd_port_in_action_profile(tokens, n_tokens, out, out_size); 6356 return; 6357 } 6358 6359 if (strcmp(tokens[0], "table") == 0) { 6360 cmd_table_action_profile(tokens, n_tokens, out, out_size); 6361 return; 6362 } 6363 6364 if (strcmp(tokens[0], "pipeline") == 0) { 6365 if ((n_tokens >= 3) && 6366 (strcmp(tokens[2], "period") == 0)) { 6367 cmd_pipeline(tokens, n_tokens, out, out_size); 6368 return; 6369 } 6370 6371 if ((n_tokens >= 5) && 6372 (strcmp(tokens[2], "port") == 0) && 6373 (strcmp(tokens[3], "in") == 0) && 6374 (strcmp(tokens[4], "bsz") == 0)) { 6375 cmd_pipeline_port_in(tokens, n_tokens, out, out_size); 6376 return; 6377 } 6378 6379 if ((n_tokens >= 5) && 6380 (strcmp(tokens[2], "port") == 0) && 6381 (strcmp(tokens[3], "out") == 0) && 6382 (strcmp(tokens[4], "bsz") == 0)) { 6383 cmd_pipeline_port_out(tokens, n_tokens, out, out_size); 6384 return; 6385 } 6386 6387 if ((n_tokens >= 4) && 6388 (strcmp(tokens[2], "table") == 0) && 6389 (strcmp(tokens[3], "match") == 0)) { 6390 cmd_pipeline_table(tokens, n_tokens, out, out_size); 6391 return; 6392 } 6393 6394 if ((n_tokens >= 6) && 6395 (strcmp(tokens[2], "port") == 0) && 6396 (strcmp(tokens[3], "in") == 0) && 6397 (strcmp(tokens[5], "table") == 0)) { 6398 cmd_pipeline_port_in_table(tokens, n_tokens, 6399 out, out_size); 6400 return; 6401 } 6402 6403 if ((n_tokens >= 6) && 6404 (strcmp(tokens[2], "port") == 0) && 6405 (strcmp(tokens[3], "in") == 0) && 6406 (strcmp(tokens[5], "stats") == 0)) { 6407 cmd_pipeline_port_in_stats(tokens, n_tokens, 6408 out, out_size); 6409 return; 6410 } 6411 6412 if ((n_tokens >= 6) && 6413 (strcmp(tokens[2], "port") == 0) && 6414 (strcmp(tokens[3], "in") == 0) && 6415 (strcmp(tokens[5], "enable") == 0)) { 6416 cmd_pipeline_port_in_enable(tokens, n_tokens, 6417 out, out_size); 6418 return; 6419 } 6420 6421 if ((n_tokens >= 6) && 6422 (strcmp(tokens[2], "port") == 0) && 6423 (strcmp(tokens[3], "in") == 0) && 6424 (strcmp(tokens[5], "disable") == 0)) { 6425 cmd_pipeline_port_in_disable(tokens, n_tokens, 6426 out, out_size); 6427 return; 6428 } 6429 6430 if ((n_tokens >= 6) && 6431 (strcmp(tokens[2], "port") == 0) && 6432 (strcmp(tokens[3], "out") == 0) && 6433 (strcmp(tokens[5], "stats") == 0)) { 6434 cmd_pipeline_port_out_stats(tokens, n_tokens, 6435 out, out_size); 6436 return; 6437 } 6438 6439 if ((n_tokens >= 5) && 6440 (strcmp(tokens[2], "table") == 0) && 6441 (strcmp(tokens[4], "stats") == 0)) { 6442 cmd_pipeline_table_stats(tokens, n_tokens, 6443 out, out_size); 6444 return; 6445 } 6446 6447 if ((n_tokens >= 7) && 6448 (strcmp(tokens[2], "table") == 0) && 6449 (strcmp(tokens[4], "rule") == 0) && 6450 (strcmp(tokens[5], "add") == 0) && 6451 (strcmp(tokens[6], "match") == 0)) { 6452 if ((n_tokens >= 8) && 6453 (strcmp(tokens[7], "default") == 0)) { 6454 cmd_pipeline_table_rule_add_default(tokens, 6455 n_tokens, out, out_size); 6456 return; 6457 } 6458 6459 cmd_pipeline_table_rule_add(tokens, n_tokens, 6460 out, out_size); 6461 return; 6462 } 6463 6464 if ((n_tokens >= 7) && 6465 (strcmp(tokens[2], "table") == 0) && 6466 (strcmp(tokens[4], "rule") == 0) && 6467 (strcmp(tokens[5], "add") == 0) && 6468 (strcmp(tokens[6], "bulk") == 0)) { 6469 cmd_pipeline_table_rule_add_bulk(tokens, 6470 n_tokens, out, out_size); 6471 return; 6472 } 6473 6474 if ((n_tokens >= 7) && 6475 (strcmp(tokens[2], "table") == 0) && 6476 (strcmp(tokens[4], "rule") == 0) && 6477 (strcmp(tokens[5], "delete") == 0) && 6478 (strcmp(tokens[6], "match") == 0)) { 6479 if ((n_tokens >= 8) && 6480 (strcmp(tokens[7], "default") == 0)) { 6481 cmd_pipeline_table_rule_delete_default(tokens, 6482 n_tokens, out, out_size); 6483 return; 6484 } 6485 6486 cmd_pipeline_table_rule_delete(tokens, n_tokens, 6487 out, out_size); 6488 return; 6489 } 6490 6491 if ((n_tokens >= 6) && 6492 (strcmp(tokens[2], "table") == 0) && 6493 (strcmp(tokens[4], "rule") == 0) && 6494 (strcmp(tokens[5], "show") == 0)) { 6495 cmd_pipeline_table_rule_show(tokens, n_tokens, 6496 out, out_size); 6497 return; 6498 } 6499 6500 if ((n_tokens >= 7) && 6501 (strcmp(tokens[2], "table") == 0) && 6502 (strcmp(tokens[4], "rule") == 0) && 6503 (strcmp(tokens[5], "read") == 0) && 6504 (strcmp(tokens[6], "stats") == 0)) { 6505 cmd_pipeline_table_rule_stats_read(tokens, n_tokens, 6506 out, out_size); 6507 return; 6508 } 6509 6510 if ((n_tokens >= 8) && 6511 (strcmp(tokens[2], "table") == 0) && 6512 (strcmp(tokens[4], "meter") == 0) && 6513 (strcmp(tokens[5], "profile") == 0) && 6514 (strcmp(tokens[7], "add") == 0)) { 6515 cmd_pipeline_table_meter_profile_add(tokens, n_tokens, 6516 out, out_size); 6517 return; 6518 } 6519 6520 if ((n_tokens >= 8) && 6521 (strcmp(tokens[2], "table") == 0) && 6522 (strcmp(tokens[4], "meter") == 0) && 6523 (strcmp(tokens[5], "profile") == 0) && 6524 (strcmp(tokens[7], "delete") == 0)) { 6525 cmd_pipeline_table_meter_profile_delete(tokens, 6526 n_tokens, out, out_size); 6527 return; 6528 } 6529 6530 if ((n_tokens >= 7) && 6531 (strcmp(tokens[2], "table") == 0) && 6532 (strcmp(tokens[4], "rule") == 0) && 6533 (strcmp(tokens[5], "read") == 0) && 6534 (strcmp(tokens[6], "meter") == 0)) { 6535 cmd_pipeline_table_rule_meter_read(tokens, n_tokens, 6536 out, out_size); 6537 return; 6538 } 6539 6540 if ((n_tokens >= 5) && 6541 (strcmp(tokens[2], "table") == 0) && 6542 (strcmp(tokens[4], "dscp") == 0)) { 6543 cmd_pipeline_table_dscp(tokens, n_tokens, 6544 out, out_size); 6545 return; 6546 } 6547 6548 if ((n_tokens >= 7) && 6549 (strcmp(tokens[2], "table") == 0) && 6550 (strcmp(tokens[4], "rule") == 0) && 6551 (strcmp(tokens[5], "read") == 0) && 6552 (strcmp(tokens[6], "ttl") == 0)) { 6553 cmd_pipeline_table_rule_ttl_read(tokens, n_tokens, 6554 out, out_size); 6555 return; 6556 } 6557 6558 if ((n_tokens >= 7) && 6559 (strcmp(tokens[2], "table") == 0) && 6560 (strcmp(tokens[4], "rule") == 0) && 6561 (strcmp(tokens[5], "read") == 0) && 6562 (strcmp(tokens[6], "time") == 0)) { 6563 cmd_pipeline_table_rule_time_read(tokens, n_tokens, 6564 out, out_size); 6565 return; 6566 } 6567 } 6568 6569 if (strcmp(tokens[0], "thread") == 0) { 6570 if ((n_tokens >= 5) && 6571 (strcmp(tokens[4], "enable") == 0)) { 6572 cmd_thread_pipeline_enable(tokens, n_tokens, 6573 out, out_size); 6574 return; 6575 } 6576 6577 if ((n_tokens >= 5) && 6578 (strcmp(tokens[4], "disable") == 0)) { 6579 cmd_thread_pipeline_disable(tokens, n_tokens, 6580 out, out_size); 6581 return; 6582 } 6583 } 6584 6585 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 6586 } 6587 6588 int 6589 cli_script_process(const char *file_name, 6590 size_t msg_in_len_max, 6591 size_t msg_out_len_max) 6592 { 6593 char *msg_in = NULL, *msg_out = NULL; 6594 FILE *f = NULL; 6595 6596 /* Check input arguments */ 6597 if ((file_name == NULL) || 6598 (strlen(file_name) == 0) || 6599 (msg_in_len_max == 0) || 6600 (msg_out_len_max == 0)) 6601 return -EINVAL; 6602 6603 msg_in = malloc(msg_in_len_max + 1); 6604 msg_out = malloc(msg_out_len_max + 1); 6605 if ((msg_in == NULL) || 6606 (msg_out == NULL)) { 6607 free(msg_out); 6608 free(msg_in); 6609 return -ENOMEM; 6610 } 6611 6612 /* Open input file */ 6613 f = fopen(file_name, "r"); 6614 if (f == NULL) { 6615 free(msg_out); 6616 free(msg_in); 6617 return -EIO; 6618 } 6619 6620 /* Read file */ 6621 for ( ; ; ) { 6622 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 6623 break; 6624 6625 printf("%s", msg_in); 6626 msg_out[0] = 0; 6627 6628 cli_process(msg_in, 6629 msg_out, 6630 msg_out_len_max); 6631 6632 if (strlen(msg_out)) 6633 printf("%s", msg_out); 6634 } 6635 6636 /* Close file */ 6637 fclose(f); 6638 free(msg_out); 6639 free(msg_in); 6640 return 0; 6641 } 6642 6643 static int 6644 cli_rule_file_process(const char *file_name, 6645 size_t line_len_max, 6646 struct table_rule_list **rule_list, 6647 uint32_t *n_rules, 6648 uint32_t *line_number, 6649 char *out, 6650 size_t out_size) 6651 { 6652 struct table_rule_list *list = NULL; 6653 char *line = NULL; 6654 FILE *f = NULL; 6655 uint32_t rule_id = 0, line_id = 0; 6656 int status = 0; 6657 6658 /* Check input arguments */ 6659 if ((file_name == NULL) || 6660 (strlen(file_name) == 0) || 6661 (line_len_max == 0) || 6662 (rule_list == NULL) || 6663 (n_rules == NULL) || 6664 (line_number == NULL) || 6665 (out == NULL)) { 6666 status = -EINVAL; 6667 goto cli_rule_file_process_free; 6668 } 6669 6670 /* Memory allocation */ 6671 list = malloc(sizeof(struct table_rule_list)); 6672 if (list == NULL) { 6673 status = -ENOMEM; 6674 goto cli_rule_file_process_free; 6675 } 6676 6677 TAILQ_INIT(list); 6678 6679 line = malloc(line_len_max + 1); 6680 if (line == NULL) { 6681 status = -ENOMEM; 6682 goto cli_rule_file_process_free; 6683 } 6684 6685 /* Open file */ 6686 f = fopen(file_name, "r"); 6687 if (f == NULL) { 6688 status = -EIO; 6689 goto cli_rule_file_process_free; 6690 } 6691 6692 /* Read file */ 6693 for (line_id = 1, rule_id = 0; ; line_id++) { 6694 char *tokens[CMD_MAX_TOKENS]; 6695 struct table_rule *rule = NULL; 6696 uint32_t n_tokens, n_tokens_parsed, t0; 6697 6698 /* Read next line from file. */ 6699 if (fgets(line, line_len_max + 1, f) == NULL) 6700 break; 6701 6702 /* Comment. */ 6703 if (is_comment(line)) 6704 continue; 6705 6706 /* Parse line. */ 6707 n_tokens = RTE_DIM(tokens); 6708 status = parse_tokenize_string(line, tokens, &n_tokens); 6709 if (status) { 6710 status = -EINVAL; 6711 goto cli_rule_file_process_free; 6712 } 6713 6714 /* Empty line. */ 6715 if (n_tokens == 0) 6716 continue; 6717 t0 = 0; 6718 6719 /* Rule alloc and insert. */ 6720 rule = calloc(1, sizeof(struct table_rule)); 6721 if (rule == NULL) { 6722 status = -ENOMEM; 6723 goto cli_rule_file_process_free; 6724 } 6725 6726 TAILQ_INSERT_TAIL(list, rule, node); 6727 6728 /* Rule match. */ 6729 n_tokens_parsed = parse_match(tokens + t0, 6730 n_tokens - t0, 6731 out, 6732 out_size, 6733 &rule->match); 6734 if (n_tokens_parsed == 0) { 6735 status = -EINVAL; 6736 goto cli_rule_file_process_free; 6737 } 6738 t0 += n_tokens_parsed; 6739 6740 /* Rule action. */ 6741 n_tokens_parsed = parse_table_action(tokens + t0, 6742 n_tokens - t0, 6743 out, 6744 out_size, 6745 &rule->action); 6746 if (n_tokens_parsed == 0) { 6747 status = -EINVAL; 6748 goto cli_rule_file_process_free; 6749 } 6750 t0 += n_tokens_parsed; 6751 6752 /* Line completed. */ 6753 if (t0 < n_tokens) { 6754 status = -EINVAL; 6755 goto cli_rule_file_process_free; 6756 } 6757 6758 /* Increment rule count */ 6759 rule_id++; 6760 } 6761 6762 /* Close file */ 6763 fclose(f); 6764 6765 /* Memory free */ 6766 free(line); 6767 6768 *rule_list = list; 6769 *n_rules = rule_id; 6770 *line_number = line_id; 6771 return 0; 6772 6773 cli_rule_file_process_free: 6774 if (rule_list != NULL) 6775 *rule_list = NULL; 6776 6777 if (n_rules != NULL) 6778 *n_rules = rule_id; 6779 6780 if (line_number != NULL) 6781 *line_number = line_id; 6782 6783 if (list != NULL) 6784 for ( ; ; ) { 6785 struct table_rule *rule; 6786 6787 rule = TAILQ_FIRST(list); 6788 if (rule == NULL) 6789 break; 6790 6791 TAILQ_REMOVE(list, rule, node); 6792 free(rule); 6793 } 6794 6795 if (f) 6796 fclose(f); 6797 free(line); 6798 free(list); 6799 6800 return status; 6801 } 6802