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