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 }; 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 }; 2585 2586 struct pkt_key_ipv6_5tuple { 2587 uint16_t payload_length; 2588 uint8_t proto; 2589 uint8_t hop_limit; 2590 struct rte_ipv6_addr sa; 2591 struct rte_ipv6_addr da; 2592 uint16_t sp; 2593 uint16_t dp; 2594 }; 2595 2596 struct pkt_key_ipv4_addr { 2597 uint32_t addr; 2598 }; 2599 2600 struct pkt_key_ipv6_addr { 2601 struct rte_ipv6_addr addr; 2602 }; 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 rte_ipv6_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 m->match.acl.ipv6.sa = saddr; 2666 2667 if (parse_ipv6_addr(tokens[7], &daddr) != 0) { 2668 snprintf(out, out_size, MSG_ARG_INVALID, "da"); 2669 return 0; 2670 } 2671 m->match.acl.ipv6.da = daddr; 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 rte_ipv6_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 ipv6->sa = saddr; 2850 ipv6->da = daddr; 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 rte_ipv6_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 ipv6_addr->addr = addr; 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 rte_ipv6_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 m->match.lpm.ipv6 = addr; 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 rte_ipv6_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 a->encap.vxlan.ipv6.sa = sa; 3544 a->encap.vxlan.ipv6.da = da; 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 rte_ipv6_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 a->nat.addr.ipv6 = addr; 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, const struct rte_ipv6_addr *ip) 4704 { 4705 fprintf(f, RTE_IPV6_ADDR_FMT ":", RTE_IPV6_ADDR_SPLIT(ip)); 4706 } 4707 4708 static const char * 4709 policer_action_string(enum rte_table_action_policer action) { 4710 switch (action) { 4711 case RTE_TABLE_ACTION_POLICER_COLOR_GREEN: return "G"; 4712 case RTE_TABLE_ACTION_POLICER_COLOR_YELLOW: return "Y"; 4713 case RTE_TABLE_ACTION_POLICER_COLOR_RED: return "R"; 4714 case RTE_TABLE_ACTION_POLICER_DROP: return "D"; 4715 default: return "?"; 4716 } 4717 } 4718 4719 static int 4720 table_rule_show(const char *pipeline_name, 4721 uint32_t table_id, 4722 const char *file_name) 4723 { 4724 struct pipeline *p; 4725 struct table *table; 4726 struct table_rule *rule; 4727 FILE *f = NULL; 4728 uint32_t i; 4729 4730 /* Check input params. */ 4731 if ((pipeline_name == NULL) || 4732 (file_name == NULL)) 4733 return -1; 4734 4735 p = pipeline_find(pipeline_name); 4736 if ((p == NULL) || 4737 (table_id >= p->n_tables)) 4738 return -1; 4739 4740 table = &p->table[table_id]; 4741 4742 /* Open file. */ 4743 f = fopen(file_name, "w"); 4744 if (f == NULL) 4745 return -1; 4746 4747 /* Write table rules to file. */ 4748 TAILQ_FOREACH(rule, &table->rules, node) { 4749 struct table_rule_match *m = &rule->match; 4750 struct table_rule_action *a = &rule->action; 4751 4752 fprintf(f, "match "); 4753 switch (m->match_type) { 4754 case TABLE_ACL: 4755 fprintf(f, "acl priority %u ", 4756 m->match.acl.priority); 4757 4758 fprintf(f, m->match.acl.ip_version ? "ipv4 " : "ipv6 "); 4759 4760 if (m->match.acl.ip_version) 4761 ipv4_addr_show(f, m->match.acl.ipv4.sa); 4762 else 4763 ipv6_addr_show(f, &m->match.acl.ipv6.sa); 4764 4765 fprintf(f, "%u", m->match.acl.sa_depth); 4766 4767 if (m->match.acl.ip_version) 4768 ipv4_addr_show(f, m->match.acl.ipv4.da); 4769 else 4770 ipv6_addr_show(f, &m->match.acl.ipv6.da); 4771 4772 fprintf(f, "%u", m->match.acl.da_depth); 4773 4774 fprintf(f, "%u %u %u %u %u ", 4775 (uint32_t)m->match.acl.sp0, 4776 (uint32_t)m->match.acl.sp1, 4777 (uint32_t)m->match.acl.dp0, 4778 (uint32_t)m->match.acl.dp1, 4779 (uint32_t)m->match.acl.proto); 4780 break; 4781 4782 case TABLE_ARRAY: 4783 fprintf(f, "array %u ", 4784 m->match.array.pos); 4785 break; 4786 4787 case TABLE_HASH: 4788 fprintf(f, "hash raw "); 4789 for (i = 0; i < table->params.match.hash.key_size; i++) 4790 fprintf(f, "%02x", m->match.hash.key[i]); 4791 fprintf(f, " "); 4792 break; 4793 4794 case TABLE_LPM: 4795 fprintf(f, "lpm "); 4796 4797 fprintf(f, m->match.lpm.ip_version ? "ipv4 " : "ipv6 "); 4798 4799 if (m->match.acl.ip_version) 4800 ipv4_addr_show(f, m->match.lpm.ipv4); 4801 else 4802 ipv6_addr_show(f, &m->match.lpm.ipv6); 4803 4804 fprintf(f, "%u ", 4805 (uint32_t)m->match.lpm.depth); 4806 break; 4807 4808 default: 4809 fprintf(f, "unknown "); 4810 } 4811 4812 fprintf(f, "action "); 4813 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) { 4814 fprintf(f, "fwd "); 4815 switch (a->fwd.action) { 4816 case RTE_PIPELINE_ACTION_DROP: 4817 fprintf(f, "drop "); 4818 break; 4819 4820 case RTE_PIPELINE_ACTION_PORT: 4821 fprintf(f, "port %u ", a->fwd.id); 4822 break; 4823 4824 case RTE_PIPELINE_ACTION_PORT_META: 4825 fprintf(f, "meta "); 4826 break; 4827 4828 case RTE_PIPELINE_ACTION_TABLE: 4829 default: 4830 fprintf(f, "table %u ", a->fwd.id); 4831 } 4832 } 4833 4834 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) { 4835 fprintf(f, "balance "); 4836 for (i = 0; i < RTE_DIM(a->lb.out); i++) 4837 fprintf(f, "%u ", a->lb.out[i]); 4838 } 4839 4840 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) { 4841 fprintf(f, "mtr "); 4842 for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) 4843 if (a->mtr.tc_mask & (1 << i)) { 4844 struct rte_table_action_mtr_tc_params *p = 4845 &a->mtr.mtr[i]; 4846 enum rte_table_action_policer ga = 4847 p->policer[RTE_COLOR_GREEN]; 4848 enum rte_table_action_policer ya = 4849 p->policer[RTE_COLOR_YELLOW]; 4850 enum rte_table_action_policer ra = 4851 p->policer[RTE_COLOR_RED]; 4852 4853 fprintf(f, "tc%u meter %u policer g %s y %s r %s ", 4854 i, 4855 a->mtr.mtr[i].meter_profile_id, 4856 policer_action_string(ga), 4857 policer_action_string(ya), 4858 policer_action_string(ra)); 4859 } 4860 } 4861 4862 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) 4863 fprintf(f, "tm subport %u pipe %u ", 4864 a->tm.subport_id, 4865 a->tm.pipe_id); 4866 4867 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) { 4868 fprintf(f, "encap "); 4869 switch (a->encap.type) { 4870 case RTE_TABLE_ACTION_ENCAP_ETHER: 4871 fprintf(f, "ether "); 4872 ether_addr_show(f, &a->encap.ether.ether.da); 4873 fprintf(f, " "); 4874 ether_addr_show(f, &a->encap.ether.ether.sa); 4875 fprintf(f, " "); 4876 break; 4877 4878 case RTE_TABLE_ACTION_ENCAP_VLAN: 4879 fprintf(f, "vlan "); 4880 ether_addr_show(f, &a->encap.vlan.ether.da); 4881 fprintf(f, " "); 4882 ether_addr_show(f, &a->encap.vlan.ether.sa); 4883 fprintf(f, " pcp %u dei %u vid %u ", 4884 a->encap.vlan.vlan.pcp, 4885 a->encap.vlan.vlan.dei, 4886 a->encap.vlan.vlan.vid); 4887 break; 4888 4889 case RTE_TABLE_ACTION_ENCAP_QINQ: 4890 fprintf(f, "qinq "); 4891 ether_addr_show(f, &a->encap.qinq.ether.da); 4892 fprintf(f, " "); 4893 ether_addr_show(f, &a->encap.qinq.ether.sa); 4894 fprintf(f, " pcp %u dei %u vid %u pcp %u dei %u vid %u ", 4895 a->encap.qinq.svlan.pcp, 4896 a->encap.qinq.svlan.dei, 4897 a->encap.qinq.svlan.vid, 4898 a->encap.qinq.cvlan.pcp, 4899 a->encap.qinq.cvlan.dei, 4900 a->encap.qinq.cvlan.vid); 4901 break; 4902 4903 case RTE_TABLE_ACTION_ENCAP_MPLS: 4904 fprintf(f, "mpls %s ", (a->encap.mpls.unicast) ? 4905 "unicast " : "multicast "); 4906 ether_addr_show(f, &a->encap.mpls.ether.da); 4907 fprintf(f, " "); 4908 ether_addr_show(f, &a->encap.mpls.ether.sa); 4909 fprintf(f, " "); 4910 for (i = 0; i < a->encap.mpls.mpls_count; i++) { 4911 struct rte_table_action_mpls_hdr *l = 4912 &a->encap.mpls.mpls[i]; 4913 4914 fprintf(f, "label%u %u %u %u ", 4915 i, 4916 l->label, 4917 l->tc, 4918 l->ttl); 4919 } 4920 break; 4921 4922 case RTE_TABLE_ACTION_ENCAP_PPPOE: 4923 fprintf(f, "pppoe "); 4924 ether_addr_show(f, &a->encap.pppoe.ether.da); 4925 fprintf(f, " "); 4926 ether_addr_show(f, &a->encap.pppoe.ether.sa); 4927 fprintf(f, " %u ", a->encap.pppoe.pppoe.session_id); 4928 break; 4929 4930 case RTE_TABLE_ACTION_ENCAP_VXLAN: 4931 fprintf(f, "vxlan ether "); 4932 ether_addr_show(f, &a->encap.vxlan.ether.da); 4933 fprintf(f, " "); 4934 ether_addr_show(f, &a->encap.vxlan.ether.sa); 4935 if (table->ap->params.encap.vxlan.vlan) 4936 fprintf(f, " vlan pcp %u dei %u vid %u ", 4937 a->encap.vxlan.vlan.pcp, 4938 a->encap.vxlan.vlan.dei, 4939 a->encap.vxlan.vlan.vid); 4940 if (table->ap->params.encap.vxlan.ip_version) { 4941 fprintf(f, " ipv4 "); 4942 ipv4_addr_show(f, a->encap.vxlan.ipv4.sa); 4943 fprintf(f, " "); 4944 ipv4_addr_show(f, a->encap.vxlan.ipv4.da); 4945 fprintf(f, " %u %u ", 4946 (uint32_t)a->encap.vxlan.ipv4.dscp, 4947 (uint32_t)a->encap.vxlan.ipv4.ttl); 4948 } else { 4949 fprintf(f, " ipv6 "); 4950 ipv6_addr_show(f, &a->encap.vxlan.ipv6.sa); 4951 fprintf(f, " "); 4952 ipv6_addr_show(f, &a->encap.vxlan.ipv6.da); 4953 fprintf(f, " %u %u %u ", 4954 a->encap.vxlan.ipv6.flow_label, 4955 (uint32_t)a->encap.vxlan.ipv6.dscp, 4956 (uint32_t)a->encap.vxlan.ipv6.hop_limit); 4957 fprintf(f, " udp %u %u vxlan %u ", 4958 a->encap.vxlan.udp.sp, 4959 a->encap.vxlan.udp.dp, 4960 a->encap.vxlan.vxlan.vni); 4961 } 4962 break; 4963 4964 default: 4965 fprintf(f, "unknown "); 4966 } 4967 } 4968 4969 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) { 4970 fprintf(f, "nat %s ", (a->nat.ip_version) ? "ipv4 " : "ipv6 "); 4971 if (a->nat.ip_version) 4972 ipv4_addr_show(f, a->nat.addr.ipv4); 4973 else 4974 ipv6_addr_show(f, &a->nat.addr.ipv6); 4975 fprintf(f, " %u ", (uint32_t)(a->nat.port)); 4976 } 4977 4978 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) 4979 fprintf(f, "ttl %s ", (a->ttl.decrement) ? "dec" : "keep"); 4980 4981 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) 4982 fprintf(f, "stats "); 4983 4984 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) 4985 fprintf(f, "time "); 4986 4987 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) 4988 fprintf(f, "sym_crypto "); 4989 4990 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) 4991 fprintf(f, "tag %u ", a->tag.tag); 4992 4993 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) 4994 fprintf(f, "decap %u ", a->decap.n); 4995 4996 /* end */ 4997 fprintf(f, "\n"); 4998 } 4999 5000 /* Write table default rule to file. */ 5001 if (table->rule_default) { 5002 struct table_rule_action *a = &table->rule_default->action; 5003 5004 fprintf(f, "# match default action fwd "); 5005 5006 switch (a->fwd.action) { 5007 case RTE_PIPELINE_ACTION_DROP: 5008 fprintf(f, "drop "); 5009 break; 5010 5011 case RTE_PIPELINE_ACTION_PORT: 5012 fprintf(f, "port %u ", a->fwd.id); 5013 break; 5014 5015 case RTE_PIPELINE_ACTION_PORT_META: 5016 fprintf(f, "meta "); 5017 break; 5018 5019 case RTE_PIPELINE_ACTION_TABLE: 5020 default: 5021 fprintf(f, "table %u ", a->fwd.id); 5022 } 5023 } else 5024 fprintf(f, "# match default action fwd drop "); 5025 5026 fprintf(f, "\n"); 5027 5028 /* Close file. */ 5029 fclose(f); 5030 5031 return 0; 5032 } 5033 5034 static const char cmd_pipeline_table_rule_show_help[] = 5035 "pipeline <pipeline_name> table <table_id> rule show\n" 5036 " file <file_name>\n"; 5037 5038 static void 5039 cmd_pipeline_table_rule_show(char **tokens, 5040 uint32_t n_tokens, 5041 char *out, 5042 size_t out_size) 5043 { 5044 char *file_name = NULL, *pipeline_name; 5045 uint32_t table_id; 5046 int status; 5047 5048 if (n_tokens != 8) { 5049 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5050 return; 5051 } 5052 5053 pipeline_name = tokens[1]; 5054 5055 if (strcmp(tokens[2], "table") != 0) { 5056 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5057 return; 5058 } 5059 5060 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5061 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5062 return; 5063 } 5064 5065 if (strcmp(tokens[4], "rule") != 0) { 5066 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5067 return; 5068 } 5069 5070 if (strcmp(tokens[5], "show") != 0) { 5071 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "show"); 5072 return; 5073 } 5074 5075 if (strcmp(tokens[6], "file") != 0) { 5076 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file"); 5077 return; 5078 } 5079 5080 file_name = tokens[7]; 5081 5082 status = table_rule_show(pipeline_name, table_id, file_name); 5083 if (status) { 5084 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5085 return; 5086 } 5087 } 5088 5089 static const char cmd_pipeline_table_rule_stats_read_help[] = 5090 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n" 5091 " match <match>\n"; 5092 5093 static void 5094 cmd_pipeline_table_rule_stats_read(char **tokens, 5095 uint32_t n_tokens, 5096 char *out, 5097 size_t out_size) 5098 { 5099 struct table_rule_match m; 5100 struct rte_table_action_stats_counters stats; 5101 char *pipeline_name; 5102 uint32_t table_id, n_tokens_parsed; 5103 int clear = 0, status; 5104 5105 if (n_tokens < 7) { 5106 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5107 return; 5108 } 5109 5110 pipeline_name = tokens[1]; 5111 5112 if (strcmp(tokens[2], "table") != 0) { 5113 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5114 return; 5115 } 5116 5117 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5118 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5119 return; 5120 } 5121 5122 if (strcmp(tokens[4], "rule") != 0) { 5123 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5124 return; 5125 } 5126 5127 if (strcmp(tokens[5], "read") != 0) { 5128 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5129 return; 5130 } 5131 5132 if (strcmp(tokens[6], "stats") != 0) { 5133 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 5134 return; 5135 } 5136 5137 n_tokens -= 7; 5138 tokens += 7; 5139 5140 /* clear */ 5141 if (n_tokens && (strcmp(tokens[0], "clear") == 0)) { 5142 clear = 1; 5143 5144 n_tokens--; 5145 tokens++; 5146 } 5147 5148 /* match */ 5149 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5150 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5151 return; 5152 } 5153 5154 n_tokens_parsed = parse_match(tokens, 5155 n_tokens, 5156 out, 5157 out_size, 5158 &m); 5159 if (n_tokens_parsed == 0) 5160 return; 5161 n_tokens -= n_tokens_parsed; 5162 tokens += n_tokens_parsed; 5163 5164 /* end */ 5165 if (n_tokens) { 5166 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5167 return; 5168 } 5169 5170 /* Read table rule stats. */ 5171 status = pipeline_table_rule_stats_read(pipeline_name, 5172 table_id, 5173 &m, 5174 &stats, 5175 clear); 5176 if (status) { 5177 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5178 return; 5179 } 5180 5181 /* Print stats. */ 5182 if (stats.n_packets_valid && stats.n_bytes_valid) 5183 snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n", 5184 stats.n_packets, 5185 stats.n_bytes); 5186 5187 if (stats.n_packets_valid && !stats.n_bytes_valid) 5188 snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n", 5189 stats.n_packets); 5190 5191 if (!stats.n_packets_valid && stats.n_bytes_valid) 5192 snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n", 5193 stats.n_bytes); 5194 5195 if (!stats.n_packets_valid && !stats.n_bytes_valid) 5196 snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n"); 5197 } 5198 5199 static const char cmd_pipeline_table_meter_profile_add_help[] = 5200 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n" 5201 " add srtcm cir <cir> cbs <cbs> ebs <ebs>\n" 5202 " | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n"; 5203 5204 static void 5205 cmd_pipeline_table_meter_profile_add(char **tokens, 5206 uint32_t n_tokens, 5207 char *out, 5208 size_t out_size) 5209 { 5210 struct rte_table_action_meter_profile p; 5211 char *pipeline_name; 5212 uint32_t table_id, meter_profile_id; 5213 int status; 5214 5215 if (n_tokens < 9) { 5216 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5217 return; 5218 } 5219 5220 pipeline_name = tokens[1]; 5221 5222 if (strcmp(tokens[2], "table") != 0) { 5223 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5224 return; 5225 } 5226 5227 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5228 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5229 return; 5230 } 5231 5232 if (strcmp(tokens[4], "meter") != 0) { 5233 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5234 return; 5235 } 5236 5237 if (strcmp(tokens[5], "profile") != 0) { 5238 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 5239 return; 5240 } 5241 5242 if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 5243 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 5244 return; 5245 } 5246 5247 if (strcmp(tokens[7], "add") != 0) { 5248 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add"); 5249 return; 5250 } 5251 5252 if (strcmp(tokens[8], "srtcm") == 0) { 5253 if (n_tokens != 15) { 5254 snprintf(out, out_size, MSG_ARG_MISMATCH, 5255 tokens[0]); 5256 return; 5257 } 5258 5259 p.alg = RTE_TABLE_ACTION_METER_SRTCM; 5260 5261 if (strcmp(tokens[9], "cir") != 0) { 5262 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 5263 return; 5264 } 5265 5266 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) { 5267 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 5268 return; 5269 } 5270 5271 if (strcmp(tokens[11], "cbs") != 0) { 5272 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 5273 return; 5274 } 5275 5276 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) { 5277 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 5278 return; 5279 } 5280 5281 if (strcmp(tokens[13], "ebs") != 0) { 5282 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs"); 5283 return; 5284 } 5285 5286 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) { 5287 snprintf(out, out_size, MSG_ARG_INVALID, "ebs"); 5288 return; 5289 } 5290 } else if (strcmp(tokens[8], "trtcm") == 0) { 5291 if (n_tokens != 17) { 5292 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5293 return; 5294 } 5295 5296 p.alg = RTE_TABLE_ACTION_METER_TRTCM; 5297 5298 if (strcmp(tokens[9], "cir") != 0) { 5299 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir"); 5300 return; 5301 } 5302 5303 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) { 5304 snprintf(out, out_size, MSG_ARG_INVALID, "cir"); 5305 return; 5306 } 5307 5308 if (strcmp(tokens[11], "pir") != 0) { 5309 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir"); 5310 return; 5311 } 5312 5313 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) { 5314 snprintf(out, out_size, MSG_ARG_INVALID, "pir"); 5315 return; 5316 } 5317 if (strcmp(tokens[13], "cbs") != 0) { 5318 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs"); 5319 return; 5320 } 5321 5322 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) { 5323 snprintf(out, out_size, MSG_ARG_INVALID, "cbs"); 5324 return; 5325 } 5326 5327 if (strcmp(tokens[15], "pbs") != 0) { 5328 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs"); 5329 return; 5330 } 5331 5332 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) { 5333 snprintf(out, out_size, MSG_ARG_INVALID, "pbs"); 5334 return; 5335 } 5336 } else { 5337 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5338 return; 5339 } 5340 5341 status = pipeline_table_mtr_profile_add(pipeline_name, 5342 table_id, 5343 meter_profile_id, 5344 &p); 5345 if (status) { 5346 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5347 return; 5348 } 5349 } 5350 5351 5352 static const char cmd_pipeline_table_meter_profile_delete_help[] = 5353 "pipeline <pipeline_name> table <table_id>\n" 5354 " meter profile <meter_profile_id> delete\n"; 5355 5356 static void 5357 cmd_pipeline_table_meter_profile_delete(char **tokens, 5358 uint32_t n_tokens, 5359 char *out, 5360 size_t out_size) 5361 { 5362 char *pipeline_name; 5363 uint32_t table_id, meter_profile_id; 5364 int status; 5365 5366 if (n_tokens != 8) { 5367 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5368 return; 5369 } 5370 5371 pipeline_name = tokens[1]; 5372 5373 if (strcmp(tokens[2], "table") != 0) { 5374 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5375 return; 5376 } 5377 5378 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5379 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5380 return; 5381 } 5382 5383 if (strcmp(tokens[4], "meter") != 0) { 5384 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5385 return; 5386 } 5387 5388 if (strcmp(tokens[5], "profile") != 0) { 5389 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); 5390 return; 5391 } 5392 5393 if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) { 5394 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id"); 5395 return; 5396 } 5397 5398 if (strcmp(tokens[7], "delete") != 0) { 5399 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete"); 5400 return; 5401 } 5402 5403 status = pipeline_table_mtr_profile_delete(pipeline_name, 5404 table_id, 5405 meter_profile_id); 5406 if (status) { 5407 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5408 return; 5409 } 5410 } 5411 5412 5413 static const char cmd_pipeline_table_rule_meter_read_help[] = 5414 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n" 5415 " match <match>\n"; 5416 5417 static void 5418 cmd_pipeline_table_rule_meter_read(char **tokens, 5419 uint32_t n_tokens, 5420 char *out, 5421 size_t out_size) 5422 { 5423 struct table_rule_match m; 5424 struct rte_table_action_mtr_counters stats; 5425 char *pipeline_name; 5426 uint32_t table_id, n_tokens_parsed; 5427 int clear = 0, status; 5428 5429 if (n_tokens < 7) { 5430 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5431 return; 5432 } 5433 5434 pipeline_name = tokens[1]; 5435 5436 if (strcmp(tokens[2], "table") != 0) { 5437 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5438 return; 5439 } 5440 5441 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5442 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5443 return; 5444 } 5445 5446 if (strcmp(tokens[4], "rule") != 0) { 5447 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5448 return; 5449 } 5450 5451 if (strcmp(tokens[5], "read") != 0) { 5452 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5453 return; 5454 } 5455 5456 if (strcmp(tokens[6], "meter") != 0) { 5457 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter"); 5458 return; 5459 } 5460 5461 n_tokens -= 7; 5462 tokens += 7; 5463 5464 /* clear */ 5465 if (n_tokens && (strcmp(tokens[0], "clear") == 0)) { 5466 clear = 1; 5467 5468 n_tokens--; 5469 tokens++; 5470 } 5471 5472 /* match */ 5473 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5474 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5475 return; 5476 } 5477 5478 n_tokens_parsed = parse_match(tokens, 5479 n_tokens, 5480 out, 5481 out_size, 5482 &m); 5483 if (n_tokens_parsed == 0) 5484 return; 5485 n_tokens -= n_tokens_parsed; 5486 tokens += n_tokens_parsed; 5487 5488 /* end */ 5489 if (n_tokens) { 5490 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5491 return; 5492 } 5493 5494 /* Read table rule meter stats. */ 5495 status = pipeline_table_rule_mtr_read(pipeline_name, 5496 table_id, 5497 &m, 5498 &stats, 5499 clear); 5500 if (status) { 5501 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5502 return; 5503 } 5504 5505 /* Print stats. */ 5506 } 5507 5508 5509 static const char cmd_pipeline_table_dscp_help[] = 5510 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n" 5511 "\n" 5512 " File <file_name>:\n" 5513 " - exactly 64 lines\n" 5514 " - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n"; 5515 5516 static int 5517 load_dscp_table(struct rte_table_action_dscp_table *dscp_table, 5518 const char *file_name, 5519 uint32_t *line_number) 5520 { 5521 FILE *f = NULL; 5522 uint32_t dscp, l; 5523 5524 /* Check input arguments */ 5525 if ((dscp_table == NULL) || 5526 (file_name == NULL) || 5527 (line_number == NULL)) { 5528 if (line_number) 5529 *line_number = 0; 5530 return -EINVAL; 5531 } 5532 5533 /* Open input file */ 5534 f = fopen(file_name, "r"); 5535 if (f == NULL) { 5536 *line_number = 0; 5537 return -EINVAL; 5538 } 5539 5540 /* Read file */ 5541 for (dscp = 0, l = 1; ; l++) { 5542 char line[64]; 5543 char *tokens[3]; 5544 enum rte_color color; 5545 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens); 5546 5547 if (fgets(line, sizeof(line), f) == NULL) 5548 break; 5549 5550 if (is_comment(line)) 5551 continue; 5552 5553 if (parse_tokenize_string(line, tokens, &n_tokens)) { 5554 *line_number = l; 5555 fclose(f); 5556 return -EINVAL; 5557 } 5558 5559 if (n_tokens == 0) 5560 continue; 5561 5562 if ((dscp >= RTE_DIM(dscp_table->entry)) || 5563 (n_tokens != RTE_DIM(tokens)) || 5564 parser_read_uint32(&tc_id, tokens[0]) || 5565 (tc_id >= RTE_TABLE_ACTION_TC_MAX) || 5566 parser_read_uint32(&tc_queue_id, tokens[1]) || 5567 (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) || 5568 (strlen(tokens[2]) != 1)) { 5569 *line_number = l; 5570 fclose(f); 5571 return -EINVAL; 5572 } 5573 5574 switch (tokens[2][0]) { 5575 case 'g': 5576 case 'G': 5577 color = RTE_COLOR_GREEN; 5578 break; 5579 5580 case 'y': 5581 case 'Y': 5582 color = RTE_COLOR_YELLOW; 5583 break; 5584 5585 case 'r': 5586 case 'R': 5587 color = RTE_COLOR_RED; 5588 break; 5589 5590 default: 5591 *line_number = l; 5592 fclose(f); 5593 return -EINVAL; 5594 } 5595 5596 dscp_table->entry[dscp].tc_id = tc_id; 5597 dscp_table->entry[dscp].tc_queue_id = tc_queue_id; 5598 dscp_table->entry[dscp].color = color; 5599 dscp++; 5600 } 5601 5602 /* Close file */ 5603 fclose(f); 5604 return 0; 5605 } 5606 5607 static void 5608 cmd_pipeline_table_dscp(char **tokens, 5609 uint32_t n_tokens, 5610 char *out, 5611 size_t out_size) 5612 { 5613 struct rte_table_action_dscp_table dscp_table; 5614 char *pipeline_name, *file_name; 5615 uint32_t table_id, line_number; 5616 int status; 5617 5618 if (n_tokens != 6) { 5619 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5620 return; 5621 } 5622 5623 pipeline_name = tokens[1]; 5624 5625 if (strcmp(tokens[2], "table") != 0) { 5626 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 5627 return; 5628 } 5629 5630 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5631 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5632 return; 5633 } 5634 5635 if (strcmp(tokens[4], "dscp") != 0) { 5636 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp"); 5637 return; 5638 } 5639 5640 file_name = tokens[5]; 5641 5642 status = load_dscp_table(&dscp_table, file_name, &line_number); 5643 if (status) { 5644 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number); 5645 return; 5646 } 5647 5648 status = pipeline_table_dscp_table_update(pipeline_name, 5649 table_id, 5650 UINT64_MAX, 5651 &dscp_table); 5652 if (status) { 5653 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5654 return; 5655 } 5656 } 5657 5658 5659 static const char cmd_pipeline_table_rule_ttl_read_help[] = 5660 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n" 5661 " match <match>\n"; 5662 5663 static void 5664 cmd_pipeline_table_rule_ttl_read(char **tokens, 5665 uint32_t n_tokens, 5666 char *out, 5667 size_t out_size) 5668 { 5669 struct table_rule_match m; 5670 struct rte_table_action_ttl_counters stats; 5671 char *pipeline_name; 5672 uint32_t table_id, n_tokens_parsed; 5673 int clear = 0, status; 5674 5675 if (n_tokens < 7) { 5676 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5677 return; 5678 } 5679 5680 pipeline_name = tokens[1]; 5681 5682 if (strcmp(tokens[2], "table") != 0) { 5683 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5684 return; 5685 } 5686 5687 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5688 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5689 return; 5690 } 5691 5692 if (strcmp(tokens[4], "rule") != 0) { 5693 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5694 return; 5695 } 5696 5697 if (strcmp(tokens[5], "read") != 0) { 5698 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5699 return; 5700 } 5701 5702 if (strcmp(tokens[6], "ttl") != 0) { 5703 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl"); 5704 return; 5705 } 5706 5707 n_tokens -= 7; 5708 tokens += 7; 5709 5710 /* clear */ 5711 if (n_tokens && (strcmp(tokens[0], "clear") == 0)) { 5712 clear = 1; 5713 5714 n_tokens--; 5715 tokens++; 5716 } 5717 5718 /* match */ 5719 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5720 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5721 return; 5722 } 5723 5724 n_tokens_parsed = parse_match(tokens, 5725 n_tokens, 5726 out, 5727 out_size, 5728 &m); 5729 if (n_tokens_parsed == 0) 5730 return; 5731 n_tokens -= n_tokens_parsed; 5732 tokens += n_tokens_parsed; 5733 5734 /* end */ 5735 if (n_tokens) { 5736 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5737 return; 5738 } 5739 5740 /* Read table rule TTL stats. */ 5741 status = pipeline_table_rule_ttl_read(pipeline_name, 5742 table_id, 5743 &m, 5744 &stats, 5745 clear); 5746 if (status) { 5747 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5748 return; 5749 } 5750 5751 /* Print stats. */ 5752 snprintf(out, out_size, "Packets: %" PRIu64 "\n", 5753 stats.n_packets); 5754 } 5755 5756 static const char cmd_pipeline_table_rule_time_read_help[] = 5757 "pipeline <pipeline_name> table <table_id> rule read time\n" 5758 " match <match>\n"; 5759 5760 static void 5761 cmd_pipeline_table_rule_time_read(char **tokens, 5762 uint32_t n_tokens, 5763 char *out, 5764 size_t out_size) 5765 { 5766 struct table_rule_match m; 5767 char *pipeline_name; 5768 uint64_t timestamp; 5769 uint32_t table_id, n_tokens_parsed; 5770 int status; 5771 5772 if (n_tokens < 7) { 5773 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5774 return; 5775 } 5776 5777 pipeline_name = tokens[1]; 5778 5779 if (strcmp(tokens[2], "table") != 0) { 5780 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); 5781 return; 5782 } 5783 5784 if (parser_read_uint32(&table_id, tokens[3]) != 0) { 5785 snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); 5786 return; 5787 } 5788 5789 if (strcmp(tokens[4], "rule") != 0) { 5790 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule"); 5791 return; 5792 } 5793 5794 if (strcmp(tokens[5], "read") != 0) { 5795 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); 5796 return; 5797 } 5798 5799 if (strcmp(tokens[6], "time") != 0) { 5800 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "time"); 5801 return; 5802 } 5803 5804 n_tokens -= 7; 5805 tokens += 7; 5806 5807 /* match */ 5808 if ((n_tokens == 0) || strcmp(tokens[0], "match")) { 5809 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); 5810 return; 5811 } 5812 5813 n_tokens_parsed = parse_match(tokens, 5814 n_tokens, 5815 out, 5816 out_size, 5817 &m); 5818 if (n_tokens_parsed == 0) 5819 return; 5820 n_tokens -= n_tokens_parsed; 5821 tokens += n_tokens_parsed; 5822 5823 /* end */ 5824 if (n_tokens) { 5825 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 5826 return; 5827 } 5828 5829 /* Read table rule timestamp. */ 5830 status = pipeline_table_rule_time_read(pipeline_name, 5831 table_id, 5832 &m, 5833 ×tamp); 5834 if (status) { 5835 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 5836 return; 5837 } 5838 5839 /* Print stats. */ 5840 snprintf(out, out_size, "Packets: %" PRIu64 "\n", timestamp); 5841 } 5842 5843 static const char cmd_thread_pipeline_enable_help[] = 5844 "thread <thread_id> pipeline <pipeline_name> enable\n"; 5845 5846 static void 5847 cmd_thread_pipeline_enable(char **tokens, 5848 uint32_t n_tokens, 5849 char *out, 5850 size_t out_size) 5851 { 5852 char *pipeline_name; 5853 uint32_t thread_id; 5854 int status; 5855 5856 if (n_tokens != 5) { 5857 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5858 return; 5859 } 5860 5861 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 5862 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 5863 return; 5864 } 5865 5866 if (strcmp(tokens[2], "pipeline") != 0) { 5867 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5868 return; 5869 } 5870 5871 pipeline_name = tokens[3]; 5872 5873 if (strcmp(tokens[4], "enable") != 0) { 5874 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); 5875 return; 5876 } 5877 5878 status = thread_pipeline_enable(thread_id, pipeline_name); 5879 if (status) { 5880 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable"); 5881 return; 5882 } 5883 } 5884 5885 5886 static const char cmd_thread_pipeline_disable_help[] = 5887 "thread <thread_id> pipeline <pipeline_name> disable\n"; 5888 5889 static void 5890 cmd_thread_pipeline_disable(char **tokens, 5891 uint32_t n_tokens, 5892 char *out, 5893 size_t out_size) 5894 { 5895 char *pipeline_name; 5896 uint32_t thread_id; 5897 int status; 5898 5899 if (n_tokens != 5) { 5900 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); 5901 return; 5902 } 5903 5904 if (parser_read_uint32(&thread_id, tokens[1]) != 0) { 5905 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id"); 5906 return; 5907 } 5908 5909 if (strcmp(tokens[2], "pipeline") != 0) { 5910 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); 5911 return; 5912 } 5913 5914 pipeline_name = tokens[3]; 5915 5916 if (strcmp(tokens[4], "disable") != 0) { 5917 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); 5918 return; 5919 } 5920 5921 status = thread_pipeline_disable(thread_id, pipeline_name); 5922 if (status) { 5923 snprintf(out, out_size, MSG_CMD_FAIL, 5924 "thread pipeline disable"); 5925 return; 5926 } 5927 } 5928 5929 static void 5930 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size) 5931 { 5932 tokens++; 5933 n_tokens--; 5934 5935 if (n_tokens == 0) { 5936 snprintf(out, out_size, 5937 "Type 'help <command>' for details on each command.\n\n" 5938 "List of commands:\n" 5939 "\tmempool\n" 5940 "\tlink\n" 5941 "\tswq\n" 5942 "\ttmgr subport profile\n" 5943 "\ttmgr pipe profile\n" 5944 "\ttmgr\n" 5945 "\ttmgr subport\n" 5946 "\ttmgr subport pipe\n" 5947 "\ttap\n" 5948 "\tport in action profile\n" 5949 "\ttable action profile\n" 5950 "\tpipeline\n" 5951 "\tpipeline port in\n" 5952 "\tpipeline port out\n" 5953 "\tpipeline table\n" 5954 "\tpipeline port in table\n" 5955 "\tpipeline port in stats\n" 5956 "\tpipeline port in enable\n" 5957 "\tpipeline port in disable\n" 5958 "\tpipeline port out stats\n" 5959 "\tpipeline table stats\n" 5960 "\tpipeline table rule add\n" 5961 "\tpipeline table rule add default\n" 5962 "\tpipeline table rule add bulk\n" 5963 "\tpipeline table rule delete\n" 5964 "\tpipeline table rule delete default\n" 5965 "\tpipeline table rule show\n" 5966 "\tpipeline table rule stats read\n" 5967 "\tpipeline table meter profile add\n" 5968 "\tpipeline table meter profile delete\n" 5969 "\tpipeline table rule meter read\n" 5970 "\tpipeline table dscp\n" 5971 "\tpipeline table rule ttl read\n" 5972 "\tpipeline table rule time read\n" 5973 "\tthread pipeline enable\n" 5974 "\tthread pipeline disable\n\n"); 5975 return; 5976 } 5977 5978 if (strcmp(tokens[0], "mempool") == 0) { 5979 snprintf(out, out_size, "\n%s\n", cmd_mempool_help); 5980 return; 5981 } 5982 5983 if (strcmp(tokens[0], "link") == 0) { 5984 snprintf(out, out_size, "\n%s\n", cmd_link_help); 5985 return; 5986 } 5987 5988 if (strcmp(tokens[0], "swq") == 0) { 5989 snprintf(out, out_size, "\n%s\n", cmd_swq_help); 5990 return; 5991 } 5992 5993 if (strcmp(tokens[0], "tmgr") == 0) { 5994 if (n_tokens == 1) { 5995 snprintf(out, out_size, "\n%s\n", cmd_tmgr_help); 5996 return; 5997 } 5998 5999 if ((n_tokens == 2) && 6000 (strcmp(tokens[1], "subport")) == 0) { 6001 snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help); 6002 return; 6003 } 6004 6005 if ((n_tokens == 3) && 6006 (strcmp(tokens[1], "subport") == 0) && 6007 (strcmp(tokens[2], "profile") == 0)) { 6008 snprintf(out, out_size, "\n%s\n", 6009 cmd_tmgr_subport_profile_help); 6010 return; 6011 } 6012 6013 if ((n_tokens == 3) && 6014 (strcmp(tokens[1], "subport") == 0) && 6015 (strcmp(tokens[2], "pipe") == 0)) { 6016 snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help); 6017 return; 6018 } 6019 6020 if ((n_tokens == 3) && 6021 (strcmp(tokens[1], "pipe") == 0) && 6022 (strcmp(tokens[2], "profile") == 0)) { 6023 snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help); 6024 return; 6025 } 6026 } 6027 6028 if (strcmp(tokens[0], "tap") == 0) { 6029 snprintf(out, out_size, "\n%s\n", cmd_tap_help); 6030 return; 6031 } 6032 6033 if (strcmp(tokens[0], "cryptodev") == 0) { 6034 snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help); 6035 return; 6036 } 6037 6038 if ((n_tokens == 4) && 6039 (strcmp(tokens[0], "port") == 0) && 6040 (strcmp(tokens[1], "in") == 0) && 6041 (strcmp(tokens[2], "action") == 0) && 6042 (strcmp(tokens[3], "profile") == 0)) { 6043 snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help); 6044 return; 6045 } 6046 6047 if ((n_tokens == 3) && 6048 (strcmp(tokens[0], "table") == 0) && 6049 (strcmp(tokens[1], "action") == 0) && 6050 (strcmp(tokens[2], "profile") == 0)) { 6051 snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help); 6052 return; 6053 } 6054 6055 if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) { 6056 snprintf(out, out_size, "\n%s\n", cmd_pipeline_help); 6057 return; 6058 } 6059 6060 if ((strcmp(tokens[0], "pipeline") == 0) && 6061 (strcmp(tokens[1], "port") == 0)) { 6062 if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) { 6063 snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help); 6064 return; 6065 } 6066 6067 if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) { 6068 snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help); 6069 return; 6070 } 6071 6072 if ((n_tokens == 4) && 6073 (strcmp(tokens[2], "in") == 0) && 6074 (strcmp(tokens[3], "table") == 0)) { 6075 snprintf(out, out_size, "\n%s\n", 6076 cmd_pipeline_port_in_table_help); 6077 return; 6078 } 6079 6080 if ((n_tokens == 4) && 6081 (strcmp(tokens[2], "in") == 0) && 6082 (strcmp(tokens[3], "stats") == 0)) { 6083 snprintf(out, out_size, "\n%s\n", 6084 cmd_pipeline_port_in_stats_help); 6085 return; 6086 } 6087 6088 if ((n_tokens == 4) && 6089 (strcmp(tokens[2], "in") == 0) && 6090 (strcmp(tokens[3], "enable") == 0)) { 6091 snprintf(out, out_size, "\n%s\n", 6092 cmd_pipeline_port_in_enable_help); 6093 return; 6094 } 6095 6096 if ((n_tokens == 4) && 6097 (strcmp(tokens[2], "in") == 0) && 6098 (strcmp(tokens[3], "disable") == 0)) { 6099 snprintf(out, out_size, "\n%s\n", 6100 cmd_pipeline_port_in_disable_help); 6101 return; 6102 } 6103 6104 if ((n_tokens == 4) && 6105 (strcmp(tokens[2], "out") == 0) && 6106 (strcmp(tokens[3], "stats") == 0)) { 6107 snprintf(out, out_size, "\n%s\n", 6108 cmd_pipeline_port_out_stats_help); 6109 return; 6110 } 6111 } 6112 6113 if ((strcmp(tokens[0], "pipeline") == 0) && 6114 (strcmp(tokens[1], "table") == 0)) { 6115 if (n_tokens == 2) { 6116 snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help); 6117 return; 6118 } 6119 6120 if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) { 6121 snprintf(out, out_size, "\n%s\n", 6122 cmd_pipeline_table_stats_help); 6123 return; 6124 } 6125 6126 if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) { 6127 snprintf(out, out_size, "\n%s\n", 6128 cmd_pipeline_table_dscp_help); 6129 return; 6130 } 6131 6132 if ((n_tokens == 4) && 6133 (strcmp(tokens[2], "rule") == 0) && 6134 (strcmp(tokens[3], "add") == 0)) { 6135 snprintf(out, out_size, "\n%s\n", 6136 cmd_pipeline_table_rule_add_help); 6137 return; 6138 } 6139 6140 if ((n_tokens == 5) && 6141 (strcmp(tokens[2], "rule") == 0) && 6142 (strcmp(tokens[3], "add") == 0) && 6143 (strcmp(tokens[4], "default") == 0)) { 6144 snprintf(out, out_size, "\n%s\n", 6145 cmd_pipeline_table_rule_add_default_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], "bulk") == 0)) { 6153 snprintf(out, out_size, "\n%s\n", 6154 cmd_pipeline_table_rule_add_bulk_help); 6155 return; 6156 } 6157 6158 if ((n_tokens == 4) && 6159 (strcmp(tokens[2], "rule") == 0) && 6160 (strcmp(tokens[3], "delete") == 0)) { 6161 snprintf(out, out_size, "\n%s\n", 6162 cmd_pipeline_table_rule_delete_help); 6163 return; 6164 } 6165 6166 if ((n_tokens == 5) && 6167 (strcmp(tokens[2], "rule") == 0) && 6168 (strcmp(tokens[3], "delete") == 0) && 6169 (strcmp(tokens[4], "default") == 0)) { 6170 snprintf(out, out_size, "\n%s\n", 6171 cmd_pipeline_table_rule_delete_default_help); 6172 return; 6173 } 6174 6175 if ((n_tokens == 4) && 6176 (strcmp(tokens[2], "rule") == 0) && 6177 (strcmp(tokens[3], "show") == 0)) { 6178 snprintf(out, out_size, "\n%s\n", 6179 cmd_pipeline_table_rule_show_help); 6180 return; 6181 } 6182 6183 if ((n_tokens == 5) && 6184 (strcmp(tokens[2], "rule") == 0) && 6185 (strcmp(tokens[3], "stats") == 0) && 6186 (strcmp(tokens[4], "read") == 0)) { 6187 snprintf(out, out_size, "\n%s\n", 6188 cmd_pipeline_table_rule_stats_read_help); 6189 return; 6190 } 6191 6192 if ((n_tokens == 5) && 6193 (strcmp(tokens[2], "meter") == 0) && 6194 (strcmp(tokens[3], "profile") == 0) && 6195 (strcmp(tokens[4], "add") == 0)) { 6196 snprintf(out, out_size, "\n%s\n", 6197 cmd_pipeline_table_meter_profile_add_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], "delete") == 0)) { 6205 snprintf(out, out_size, "\n%s\n", 6206 cmd_pipeline_table_meter_profile_delete_help); 6207 return; 6208 } 6209 6210 if ((n_tokens == 5) && 6211 (strcmp(tokens[2], "rule") == 0) && 6212 (strcmp(tokens[3], "meter") == 0) && 6213 (strcmp(tokens[4], "read") == 0)) { 6214 snprintf(out, out_size, "\n%s\n", 6215 cmd_pipeline_table_rule_meter_read_help); 6216 return; 6217 } 6218 6219 if ((n_tokens == 5) && 6220 (strcmp(tokens[2], "rule") == 0) && 6221 (strcmp(tokens[3], "ttl") == 0) && 6222 (strcmp(tokens[4], "read") == 0)) { 6223 snprintf(out, out_size, "\n%s\n", 6224 cmd_pipeline_table_rule_ttl_read_help); 6225 return; 6226 } 6227 6228 if ((n_tokens == 5) && 6229 (strcmp(tokens[2], "rule") == 0) && 6230 (strcmp(tokens[3], "time") == 0) && 6231 (strcmp(tokens[4], "read") == 0)) { 6232 snprintf(out, out_size, "\n%s\n", 6233 cmd_pipeline_table_rule_time_read_help); 6234 return; 6235 } 6236 } 6237 6238 if ((n_tokens == 3) && 6239 (strcmp(tokens[0], "thread") == 0) && 6240 (strcmp(tokens[1], "pipeline") == 0)) { 6241 if (strcmp(tokens[2], "enable") == 0) { 6242 snprintf(out, out_size, "\n%s\n", 6243 cmd_thread_pipeline_enable_help); 6244 return; 6245 } 6246 6247 if (strcmp(tokens[2], "disable") == 0) { 6248 snprintf(out, out_size, "\n%s\n", 6249 cmd_thread_pipeline_disable_help); 6250 return; 6251 } 6252 } 6253 6254 snprintf(out, out_size, "Invalid command\n"); 6255 } 6256 6257 void 6258 cli_process(char *in, char *out, size_t out_size) 6259 { 6260 char *tokens[CMD_MAX_TOKENS]; 6261 uint32_t n_tokens = RTE_DIM(tokens); 6262 int status; 6263 6264 if (is_comment(in)) 6265 return; 6266 6267 status = parse_tokenize_string(in, tokens, &n_tokens); 6268 if (status) { 6269 snprintf(out, out_size, MSG_ARG_TOO_MANY, ""); 6270 return; 6271 } 6272 6273 if (n_tokens == 0) 6274 return; 6275 6276 if (strcmp(tokens[0], "help") == 0) { 6277 cmd_help(tokens, n_tokens, out, out_size); 6278 return; 6279 } 6280 6281 if (strcmp(tokens[0], "mempool") == 0) { 6282 cmd_mempool(tokens, n_tokens, out, out_size); 6283 return; 6284 } 6285 6286 if (strcmp(tokens[0], "link") == 0) { 6287 if (strcmp(tokens[1], "show") == 0) { 6288 cmd_link_show(tokens, n_tokens, out, out_size); 6289 return; 6290 } 6291 6292 cmd_link(tokens, n_tokens, out, out_size); 6293 return; 6294 } 6295 6296 if (strcmp(tokens[0], "swq") == 0) { 6297 cmd_swq(tokens, n_tokens, out, out_size); 6298 return; 6299 } 6300 6301 if (strcmp(tokens[0], "tmgr") == 0) { 6302 if ((n_tokens >= 3) && 6303 (strcmp(tokens[1], "subport") == 0) && 6304 (strcmp(tokens[2], "profile") == 0)) { 6305 cmd_tmgr_subport_profile(tokens, n_tokens, 6306 out, out_size); 6307 return; 6308 } 6309 6310 if ((n_tokens >= 3) && 6311 (strcmp(tokens[1], "pipe") == 0) && 6312 (strcmp(tokens[2], "profile") == 0)) { 6313 cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size); 6314 return; 6315 } 6316 6317 if ((n_tokens >= 5) && 6318 (strcmp(tokens[2], "subport") == 0) && 6319 (strcmp(tokens[4], "profile") == 0)) { 6320 cmd_tmgr_subport(tokens, n_tokens, out, out_size); 6321 return; 6322 } 6323 6324 if ((n_tokens >= 5) && 6325 (strcmp(tokens[2], "subport") == 0) && 6326 (strcmp(tokens[4], "pipe") == 0)) { 6327 cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size); 6328 return; 6329 } 6330 6331 cmd_tmgr(tokens, n_tokens, out, out_size); 6332 return; 6333 } 6334 6335 if (strcmp(tokens[0], "tap") == 0) { 6336 cmd_tap(tokens, n_tokens, out, out_size); 6337 return; 6338 } 6339 6340 if (strcmp(tokens[0], "cryptodev") == 0) { 6341 cmd_cryptodev(tokens, n_tokens, out, out_size); 6342 return; 6343 } 6344 6345 if (strcmp(tokens[0], "port") == 0) { 6346 cmd_port_in_action_profile(tokens, n_tokens, out, out_size); 6347 return; 6348 } 6349 6350 if (strcmp(tokens[0], "table") == 0) { 6351 cmd_table_action_profile(tokens, n_tokens, out, out_size); 6352 return; 6353 } 6354 6355 if (strcmp(tokens[0], "pipeline") == 0) { 6356 if ((n_tokens >= 3) && 6357 (strcmp(tokens[2], "period") == 0)) { 6358 cmd_pipeline(tokens, n_tokens, out, out_size); 6359 return; 6360 } 6361 6362 if ((n_tokens >= 5) && 6363 (strcmp(tokens[2], "port") == 0) && 6364 (strcmp(tokens[3], "in") == 0) && 6365 (strcmp(tokens[4], "bsz") == 0)) { 6366 cmd_pipeline_port_in(tokens, n_tokens, out, out_size); 6367 return; 6368 } 6369 6370 if ((n_tokens >= 5) && 6371 (strcmp(tokens[2], "port") == 0) && 6372 (strcmp(tokens[3], "out") == 0) && 6373 (strcmp(tokens[4], "bsz") == 0)) { 6374 cmd_pipeline_port_out(tokens, n_tokens, out, out_size); 6375 return; 6376 } 6377 6378 if ((n_tokens >= 4) && 6379 (strcmp(tokens[2], "table") == 0) && 6380 (strcmp(tokens[3], "match") == 0)) { 6381 cmd_pipeline_table(tokens, n_tokens, out, out_size); 6382 return; 6383 } 6384 6385 if ((n_tokens >= 6) && 6386 (strcmp(tokens[2], "port") == 0) && 6387 (strcmp(tokens[3], "in") == 0) && 6388 (strcmp(tokens[5], "table") == 0)) { 6389 cmd_pipeline_port_in_table(tokens, n_tokens, 6390 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], "stats") == 0)) { 6398 cmd_pipeline_port_in_stats(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], "enable") == 0)) { 6407 cmd_pipeline_port_in_enable(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], "disable") == 0)) { 6416 cmd_pipeline_port_in_disable(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], "out") == 0) && 6424 (strcmp(tokens[5], "stats") == 0)) { 6425 cmd_pipeline_port_out_stats(tokens, n_tokens, 6426 out, out_size); 6427 return; 6428 } 6429 6430 if ((n_tokens >= 5) && 6431 (strcmp(tokens[2], "table") == 0) && 6432 (strcmp(tokens[4], "stats") == 0)) { 6433 cmd_pipeline_table_stats(tokens, n_tokens, 6434 out, out_size); 6435 return; 6436 } 6437 6438 if ((n_tokens >= 7) && 6439 (strcmp(tokens[2], "table") == 0) && 6440 (strcmp(tokens[4], "rule") == 0) && 6441 (strcmp(tokens[5], "add") == 0) && 6442 (strcmp(tokens[6], "match") == 0)) { 6443 if ((n_tokens >= 8) && 6444 (strcmp(tokens[7], "default") == 0)) { 6445 cmd_pipeline_table_rule_add_default(tokens, 6446 n_tokens, out, out_size); 6447 return; 6448 } 6449 6450 cmd_pipeline_table_rule_add(tokens, n_tokens, 6451 out, out_size); 6452 return; 6453 } 6454 6455 if ((n_tokens >= 7) && 6456 (strcmp(tokens[2], "table") == 0) && 6457 (strcmp(tokens[4], "rule") == 0) && 6458 (strcmp(tokens[5], "add") == 0) && 6459 (strcmp(tokens[6], "bulk") == 0)) { 6460 cmd_pipeline_table_rule_add_bulk(tokens, 6461 n_tokens, out, out_size); 6462 return; 6463 } 6464 6465 if ((n_tokens >= 7) && 6466 (strcmp(tokens[2], "table") == 0) && 6467 (strcmp(tokens[4], "rule") == 0) && 6468 (strcmp(tokens[5], "delete") == 0) && 6469 (strcmp(tokens[6], "match") == 0)) { 6470 if ((n_tokens >= 8) && 6471 (strcmp(tokens[7], "default") == 0)) { 6472 cmd_pipeline_table_rule_delete_default(tokens, 6473 n_tokens, out, out_size); 6474 return; 6475 } 6476 6477 cmd_pipeline_table_rule_delete(tokens, n_tokens, 6478 out, out_size); 6479 return; 6480 } 6481 6482 if ((n_tokens >= 6) && 6483 (strcmp(tokens[2], "table") == 0) && 6484 (strcmp(tokens[4], "rule") == 0) && 6485 (strcmp(tokens[5], "show") == 0)) { 6486 cmd_pipeline_table_rule_show(tokens, n_tokens, 6487 out, out_size); 6488 return; 6489 } 6490 6491 if ((n_tokens >= 7) && 6492 (strcmp(tokens[2], "table") == 0) && 6493 (strcmp(tokens[4], "rule") == 0) && 6494 (strcmp(tokens[5], "read") == 0) && 6495 (strcmp(tokens[6], "stats") == 0)) { 6496 cmd_pipeline_table_rule_stats_read(tokens, n_tokens, 6497 out, out_size); 6498 return; 6499 } 6500 6501 if ((n_tokens >= 8) && 6502 (strcmp(tokens[2], "table") == 0) && 6503 (strcmp(tokens[4], "meter") == 0) && 6504 (strcmp(tokens[5], "profile") == 0) && 6505 (strcmp(tokens[7], "add") == 0)) { 6506 cmd_pipeline_table_meter_profile_add(tokens, n_tokens, 6507 out, out_size); 6508 return; 6509 } 6510 6511 if ((n_tokens >= 8) && 6512 (strcmp(tokens[2], "table") == 0) && 6513 (strcmp(tokens[4], "meter") == 0) && 6514 (strcmp(tokens[5], "profile") == 0) && 6515 (strcmp(tokens[7], "delete") == 0)) { 6516 cmd_pipeline_table_meter_profile_delete(tokens, 6517 n_tokens, out, out_size); 6518 return; 6519 } 6520 6521 if ((n_tokens >= 7) && 6522 (strcmp(tokens[2], "table") == 0) && 6523 (strcmp(tokens[4], "rule") == 0) && 6524 (strcmp(tokens[5], "read") == 0) && 6525 (strcmp(tokens[6], "meter") == 0)) { 6526 cmd_pipeline_table_rule_meter_read(tokens, n_tokens, 6527 out, out_size); 6528 return; 6529 } 6530 6531 if ((n_tokens >= 5) && 6532 (strcmp(tokens[2], "table") == 0) && 6533 (strcmp(tokens[4], "dscp") == 0)) { 6534 cmd_pipeline_table_dscp(tokens, n_tokens, 6535 out, out_size); 6536 return; 6537 } 6538 6539 if ((n_tokens >= 7) && 6540 (strcmp(tokens[2], "table") == 0) && 6541 (strcmp(tokens[4], "rule") == 0) && 6542 (strcmp(tokens[5], "read") == 0) && 6543 (strcmp(tokens[6], "ttl") == 0)) { 6544 cmd_pipeline_table_rule_ttl_read(tokens, n_tokens, 6545 out, out_size); 6546 return; 6547 } 6548 6549 if ((n_tokens >= 7) && 6550 (strcmp(tokens[2], "table") == 0) && 6551 (strcmp(tokens[4], "rule") == 0) && 6552 (strcmp(tokens[5], "read") == 0) && 6553 (strcmp(tokens[6], "time") == 0)) { 6554 cmd_pipeline_table_rule_time_read(tokens, n_tokens, 6555 out, out_size); 6556 return; 6557 } 6558 } 6559 6560 if (strcmp(tokens[0], "thread") == 0) { 6561 if ((n_tokens >= 5) && 6562 (strcmp(tokens[4], "enable") == 0)) { 6563 cmd_thread_pipeline_enable(tokens, n_tokens, 6564 out, out_size); 6565 return; 6566 } 6567 6568 if ((n_tokens >= 5) && 6569 (strcmp(tokens[4], "disable") == 0)) { 6570 cmd_thread_pipeline_disable(tokens, n_tokens, 6571 out, out_size); 6572 return; 6573 } 6574 } 6575 6576 snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); 6577 } 6578 6579 int 6580 cli_script_process(const char *file_name, 6581 size_t msg_in_len_max, 6582 size_t msg_out_len_max) 6583 { 6584 char *msg_in = NULL, *msg_out = NULL; 6585 FILE *f = NULL; 6586 6587 /* Check input arguments */ 6588 if ((file_name == NULL) || 6589 (strlen(file_name) == 0) || 6590 (msg_in_len_max == 0) || 6591 (msg_out_len_max == 0)) 6592 return -EINVAL; 6593 6594 msg_in = malloc(msg_in_len_max + 1); 6595 msg_out = malloc(msg_out_len_max + 1); 6596 if ((msg_in == NULL) || 6597 (msg_out == NULL)) { 6598 free(msg_out); 6599 free(msg_in); 6600 return -ENOMEM; 6601 } 6602 6603 /* Open input file */ 6604 f = fopen(file_name, "r"); 6605 if (f == NULL) { 6606 free(msg_out); 6607 free(msg_in); 6608 return -EIO; 6609 } 6610 6611 /* Read file */ 6612 for ( ; ; ) { 6613 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL) 6614 break; 6615 6616 printf("%s", msg_in); 6617 msg_out[0] = 0; 6618 6619 cli_process(msg_in, 6620 msg_out, 6621 msg_out_len_max); 6622 6623 if (strlen(msg_out)) 6624 printf("%s", msg_out); 6625 } 6626 6627 /* Close file */ 6628 fclose(f); 6629 free(msg_out); 6630 free(msg_in); 6631 return 0; 6632 } 6633 6634 static int 6635 cli_rule_file_process(const char *file_name, 6636 size_t line_len_max, 6637 struct table_rule_list **rule_list, 6638 uint32_t *n_rules, 6639 uint32_t *line_number, 6640 char *out, 6641 size_t out_size) 6642 { 6643 struct table_rule_list *list = NULL; 6644 char *line = NULL; 6645 FILE *f = NULL; 6646 uint32_t rule_id = 0, line_id = 0; 6647 int status = 0; 6648 6649 /* Check input arguments */ 6650 if ((file_name == NULL) || 6651 (strlen(file_name) == 0) || 6652 (line_len_max == 0) || 6653 (rule_list == NULL) || 6654 (n_rules == NULL) || 6655 (line_number == NULL) || 6656 (out == NULL)) { 6657 status = -EINVAL; 6658 goto cli_rule_file_process_free; 6659 } 6660 6661 /* Memory allocation */ 6662 list = malloc(sizeof(struct table_rule_list)); 6663 if (list == NULL) { 6664 status = -ENOMEM; 6665 goto cli_rule_file_process_free; 6666 } 6667 6668 TAILQ_INIT(list); 6669 6670 line = malloc(line_len_max + 1); 6671 if (line == NULL) { 6672 status = -ENOMEM; 6673 goto cli_rule_file_process_free; 6674 } 6675 6676 /* Open file */ 6677 f = fopen(file_name, "r"); 6678 if (f == NULL) { 6679 status = -EIO; 6680 goto cli_rule_file_process_free; 6681 } 6682 6683 /* Read file */ 6684 for (line_id = 1, rule_id = 0; ; line_id++) { 6685 char *tokens[CMD_MAX_TOKENS]; 6686 struct table_rule *rule = NULL; 6687 uint32_t n_tokens, n_tokens_parsed, t0; 6688 6689 /* Read next line from file. */ 6690 if (fgets(line, line_len_max + 1, f) == NULL) 6691 break; 6692 6693 /* Comment. */ 6694 if (is_comment(line)) 6695 continue; 6696 6697 /* Parse line. */ 6698 n_tokens = RTE_DIM(tokens); 6699 status = parse_tokenize_string(line, tokens, &n_tokens); 6700 if (status) { 6701 status = -EINVAL; 6702 goto cli_rule_file_process_free; 6703 } 6704 6705 /* Empty line. */ 6706 if (n_tokens == 0) 6707 continue; 6708 t0 = 0; 6709 6710 /* Rule alloc and insert. */ 6711 rule = calloc(1, sizeof(struct table_rule)); 6712 if (rule == NULL) { 6713 status = -ENOMEM; 6714 goto cli_rule_file_process_free; 6715 } 6716 6717 TAILQ_INSERT_TAIL(list, rule, node); 6718 6719 /* Rule match. */ 6720 n_tokens_parsed = parse_match(tokens + t0, 6721 n_tokens - t0, 6722 out, 6723 out_size, 6724 &rule->match); 6725 if (n_tokens_parsed == 0) { 6726 status = -EINVAL; 6727 goto cli_rule_file_process_free; 6728 } 6729 t0 += n_tokens_parsed; 6730 6731 /* Rule action. */ 6732 n_tokens_parsed = parse_table_action(tokens + t0, 6733 n_tokens - t0, 6734 out, 6735 out_size, 6736 &rule->action); 6737 if (n_tokens_parsed == 0) { 6738 status = -EINVAL; 6739 goto cli_rule_file_process_free; 6740 } 6741 t0 += n_tokens_parsed; 6742 6743 /* Line completed. */ 6744 if (t0 < n_tokens) { 6745 status = -EINVAL; 6746 goto cli_rule_file_process_free; 6747 } 6748 6749 /* Increment rule count */ 6750 rule_id++; 6751 } 6752 6753 /* Close file */ 6754 fclose(f); 6755 6756 /* Memory free */ 6757 free(line); 6758 6759 *rule_list = list; 6760 *n_rules = rule_id; 6761 *line_number = line_id; 6762 return 0; 6763 6764 cli_rule_file_process_free: 6765 if (rule_list != NULL) 6766 *rule_list = NULL; 6767 6768 if (n_rules != NULL) 6769 *n_rules = rule_id; 6770 6771 if (line_number != NULL) 6772 *line_number = line_id; 6773 6774 if (list != NULL) 6775 for ( ; ; ) { 6776 struct table_rule *rule; 6777 6778 rule = TAILQ_FIRST(list); 6779 if (rule == NULL) 6780 break; 6781 6782 TAILQ_REMOVE(list, rule, node); 6783 free(rule); 6784 } 6785 6786 if (f) 6787 fclose(f); 6788 free(line); 6789 free(list); 6790 6791 return status; 6792 } 6793