1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2016 6WIND S.A. 5 * Copyright 2016 Mellanox. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stddef.h> 35 #include <stdint.h> 36 #include <stdio.h> 37 #include <inttypes.h> 38 #include <errno.h> 39 #include <ctype.h> 40 #include <string.h> 41 #include <arpa/inet.h> 42 #include <sys/socket.h> 43 44 #include <rte_common.h> 45 #include <rte_ethdev.h> 46 #include <rte_byteorder.h> 47 #include <cmdline_parse.h> 48 #include <cmdline_parse_etheraddr.h> 49 #include <rte_flow.h> 50 51 #include "testpmd.h" 52 53 /** Parser token indices. */ 54 enum index { 55 /* Special tokens. */ 56 ZERO = 0, 57 END, 58 59 /* Common tokens. */ 60 INTEGER, 61 UNSIGNED, 62 PREFIX, 63 BOOLEAN, 64 STRING, 65 MAC_ADDR, 66 IPV4_ADDR, 67 IPV6_ADDR, 68 RULE_ID, 69 PORT_ID, 70 GROUP_ID, 71 PRIORITY_LEVEL, 72 73 /* Top-level command. */ 74 FLOW, 75 76 /* Sub-level commands. */ 77 VALIDATE, 78 CREATE, 79 DESTROY, 80 FLUSH, 81 QUERY, 82 LIST, 83 84 /* Destroy arguments. */ 85 DESTROY_RULE, 86 87 /* Query arguments. */ 88 QUERY_ACTION, 89 90 /* List arguments. */ 91 LIST_GROUP, 92 93 /* Validate/create arguments. */ 94 GROUP, 95 PRIORITY, 96 INGRESS, 97 EGRESS, 98 99 /* Validate/create pattern. */ 100 PATTERN, 101 ITEM_PARAM_IS, 102 ITEM_PARAM_SPEC, 103 ITEM_PARAM_LAST, 104 ITEM_PARAM_MASK, 105 ITEM_PARAM_PREFIX, 106 ITEM_NEXT, 107 ITEM_END, 108 ITEM_VOID, 109 ITEM_INVERT, 110 ITEM_ANY, 111 ITEM_ANY_NUM, 112 ITEM_PF, 113 ITEM_VF, 114 ITEM_VF_ID, 115 ITEM_PORT, 116 ITEM_PORT_INDEX, 117 ITEM_RAW, 118 ITEM_RAW_RELATIVE, 119 ITEM_RAW_SEARCH, 120 ITEM_RAW_OFFSET, 121 ITEM_RAW_LIMIT, 122 ITEM_RAW_PATTERN, 123 ITEM_ETH, 124 ITEM_ETH_DST, 125 ITEM_ETH_SRC, 126 ITEM_ETH_TYPE, 127 ITEM_VLAN, 128 ITEM_VLAN_TPID, 129 ITEM_VLAN_TCI, 130 ITEM_VLAN_PCP, 131 ITEM_VLAN_DEI, 132 ITEM_VLAN_VID, 133 ITEM_IPV4, 134 ITEM_IPV4_TOS, 135 ITEM_IPV4_TTL, 136 ITEM_IPV4_PROTO, 137 ITEM_IPV4_SRC, 138 ITEM_IPV4_DST, 139 ITEM_IPV6, 140 ITEM_IPV6_TC, 141 ITEM_IPV6_FLOW, 142 ITEM_IPV6_PROTO, 143 ITEM_IPV6_HOP, 144 ITEM_IPV6_SRC, 145 ITEM_IPV6_DST, 146 ITEM_ICMP, 147 ITEM_ICMP_TYPE, 148 ITEM_ICMP_CODE, 149 ITEM_UDP, 150 ITEM_UDP_SRC, 151 ITEM_UDP_DST, 152 ITEM_TCP, 153 ITEM_TCP_SRC, 154 ITEM_TCP_DST, 155 ITEM_SCTP, 156 ITEM_SCTP_SRC, 157 ITEM_SCTP_DST, 158 ITEM_SCTP_TAG, 159 ITEM_SCTP_CKSUM, 160 ITEM_VXLAN, 161 ITEM_VXLAN_VNI, 162 ITEM_E_TAG, 163 ITEM_E_TAG_GRP_ECID_B, 164 ITEM_NVGRE, 165 ITEM_NVGRE_TNI, 166 ITEM_MPLS, 167 ITEM_MPLS_LABEL, 168 ITEM_GRE, 169 ITEM_GRE_PROTO, 170 171 /* Validate/create actions. */ 172 ACTIONS, 173 ACTION_NEXT, 174 ACTION_END, 175 ACTION_VOID, 176 ACTION_PASSTHRU, 177 ACTION_MARK, 178 ACTION_MARK_ID, 179 ACTION_FLAG, 180 ACTION_QUEUE, 181 ACTION_QUEUE_INDEX, 182 ACTION_DROP, 183 ACTION_COUNT, 184 ACTION_DUP, 185 ACTION_DUP_INDEX, 186 ACTION_RSS, 187 ACTION_RSS_QUEUES, 188 ACTION_RSS_QUEUE, 189 ACTION_PF, 190 ACTION_VF, 191 ACTION_VF_ORIGINAL, 192 ACTION_VF_ID, 193 }; 194 195 /** Size of pattern[] field in struct rte_flow_item_raw. */ 196 #define ITEM_RAW_PATTERN_SIZE 36 197 198 /** Storage size for struct rte_flow_item_raw including pattern. */ 199 #define ITEM_RAW_SIZE \ 200 (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) 201 202 /** Number of queue[] entries in struct rte_flow_action_rss. */ 203 #define ACTION_RSS_NUM 32 204 205 /** Storage size for struct rte_flow_action_rss including queues. */ 206 #define ACTION_RSS_SIZE \ 207 (offsetof(struct rte_flow_action_rss, queue) + \ 208 sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM) 209 210 /** Maximum number of subsequent tokens and arguments on the stack. */ 211 #define CTX_STACK_SIZE 16 212 213 /** Parser context. */ 214 struct context { 215 /** Stack of subsequent token lists to process. */ 216 const enum index *next[CTX_STACK_SIZE]; 217 /** Arguments for stacked tokens. */ 218 const void *args[CTX_STACK_SIZE]; 219 enum index curr; /**< Current token index. */ 220 enum index prev; /**< Index of the last token seen. */ 221 int next_num; /**< Number of entries in next[]. */ 222 int args_num; /**< Number of entries in args[]. */ 223 uint32_t reparse:1; /**< Start over from the beginning. */ 224 uint32_t eol:1; /**< EOL has been detected. */ 225 uint32_t last:1; /**< No more arguments. */ 226 uint16_t port; /**< Current port ID (for completions). */ 227 uint32_t objdata; /**< Object-specific data. */ 228 void *object; /**< Address of current object for relative offsets. */ 229 void *objmask; /**< Object a full mask must be written to. */ 230 }; 231 232 /** Token argument. */ 233 struct arg { 234 uint32_t hton:1; /**< Use network byte ordering. */ 235 uint32_t sign:1; /**< Value is signed. */ 236 uint32_t offset; /**< Relative offset from ctx->object. */ 237 uint32_t size; /**< Field size. */ 238 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */ 239 }; 240 241 /** Parser token definition. */ 242 struct token { 243 /** Type displayed during completion (defaults to "TOKEN"). */ 244 const char *type; 245 /** Help displayed during completion (defaults to token name). */ 246 const char *help; 247 /** Private data used by parser functions. */ 248 const void *priv; 249 /** 250 * Lists of subsequent tokens to push on the stack. Each call to the 251 * parser consumes the last entry of that stack. 252 */ 253 const enum index *const *next; 254 /** Arguments stack for subsequent tokens that need them. */ 255 const struct arg *const *args; 256 /** 257 * Token-processing callback, returns -1 in case of error, the 258 * length of the matched string otherwise. If NULL, attempts to 259 * match the token name. 260 * 261 * If buf is not NULL, the result should be stored in it according 262 * to context. An error is returned if not large enough. 263 */ 264 int (*call)(struct context *ctx, const struct token *token, 265 const char *str, unsigned int len, 266 void *buf, unsigned int size); 267 /** 268 * Callback that provides possible values for this token, used for 269 * completion. Returns -1 in case of error, the number of possible 270 * values otherwise. If NULL, the token name is used. 271 * 272 * If buf is not NULL, entry index ent is written to buf and the 273 * full length of the entry is returned (same behavior as 274 * snprintf()). 275 */ 276 int (*comp)(struct context *ctx, const struct token *token, 277 unsigned int ent, char *buf, unsigned int size); 278 /** Mandatory token name, no default value. */ 279 const char *name; 280 }; 281 282 /** Static initializer for the next field. */ 283 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, } 284 285 /** Static initializer for a NEXT() entry. */ 286 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, } 287 288 /** Static initializer for the args field. */ 289 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, } 290 291 /** Static initializer for ARGS() to target a field. */ 292 #define ARGS_ENTRY(s, f) \ 293 (&(const struct arg){ \ 294 .offset = offsetof(s, f), \ 295 .size = sizeof(((s *)0)->f), \ 296 }) 297 298 /** Static initializer for ARGS() to target a bit-field. */ 299 #define ARGS_ENTRY_BF(s, f, b) \ 300 (&(const struct arg){ \ 301 .size = sizeof(s), \ 302 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ 303 }) 304 305 /** Static initializer for ARGS() to target an arbitrary bit-mask. */ 306 #define ARGS_ENTRY_MASK(s, f, m) \ 307 (&(const struct arg){ \ 308 .offset = offsetof(s, f), \ 309 .size = sizeof(((s *)0)->f), \ 310 .mask = (const void *)(m), \ 311 }) 312 313 /** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */ 314 #define ARGS_ENTRY_MASK_HTON(s, f, m) \ 315 (&(const struct arg){ \ 316 .hton = 1, \ 317 .offset = offsetof(s, f), \ 318 .size = sizeof(((s *)0)->f), \ 319 .mask = (const void *)(m), \ 320 }) 321 322 /** Static initializer for ARGS() to target a pointer. */ 323 #define ARGS_ENTRY_PTR(s, f) \ 324 (&(const struct arg){ \ 325 .size = sizeof(*((s *)0)->f), \ 326 }) 327 328 /** Static initializer for ARGS() with arbitrary size. */ 329 #define ARGS_ENTRY_USZ(s, f, sz) \ 330 (&(const struct arg){ \ 331 .offset = offsetof(s, f), \ 332 .size = (sz), \ 333 }) 334 335 /** Same as ARGS_ENTRY() using network byte ordering. */ 336 #define ARGS_ENTRY_HTON(s, f) \ 337 (&(const struct arg){ \ 338 .hton = 1, \ 339 .offset = offsetof(s, f), \ 340 .size = sizeof(((s *)0)->f), \ 341 }) 342 343 /** Parser output buffer layout expected by cmd_flow_parsed(). */ 344 struct buffer { 345 enum index command; /**< Flow command. */ 346 uint16_t port; /**< Affected port ID. */ 347 union { 348 struct { 349 struct rte_flow_attr attr; 350 struct rte_flow_item *pattern; 351 struct rte_flow_action *actions; 352 uint32_t pattern_n; 353 uint32_t actions_n; 354 uint8_t *data; 355 } vc; /**< Validate/create arguments. */ 356 struct { 357 uint32_t *rule; 358 uint32_t rule_n; 359 } destroy; /**< Destroy arguments. */ 360 struct { 361 uint32_t rule; 362 enum rte_flow_action_type action; 363 } query; /**< Query arguments. */ 364 struct { 365 uint32_t *group; 366 uint32_t group_n; 367 } list; /**< List arguments. */ 368 } args; /**< Command arguments. */ 369 }; 370 371 /** Private data for pattern items. */ 372 struct parse_item_priv { 373 enum rte_flow_item_type type; /**< Item type. */ 374 uint32_t size; /**< Size of item specification structure. */ 375 }; 376 377 #define PRIV_ITEM(t, s) \ 378 (&(const struct parse_item_priv){ \ 379 .type = RTE_FLOW_ITEM_TYPE_ ## t, \ 380 .size = s, \ 381 }) 382 383 /** Private data for actions. */ 384 struct parse_action_priv { 385 enum rte_flow_action_type type; /**< Action type. */ 386 uint32_t size; /**< Size of action configuration structure. */ 387 }; 388 389 #define PRIV_ACTION(t, s) \ 390 (&(const struct parse_action_priv){ \ 391 .type = RTE_FLOW_ACTION_TYPE_ ## t, \ 392 .size = s, \ 393 }) 394 395 static const enum index next_vc_attr[] = { 396 GROUP, 397 PRIORITY, 398 INGRESS, 399 EGRESS, 400 PATTERN, 401 ZERO, 402 }; 403 404 static const enum index next_destroy_attr[] = { 405 DESTROY_RULE, 406 END, 407 ZERO, 408 }; 409 410 static const enum index next_list_attr[] = { 411 LIST_GROUP, 412 END, 413 ZERO, 414 }; 415 416 static const enum index item_param[] = { 417 ITEM_PARAM_IS, 418 ITEM_PARAM_SPEC, 419 ITEM_PARAM_LAST, 420 ITEM_PARAM_MASK, 421 ITEM_PARAM_PREFIX, 422 ZERO, 423 }; 424 425 static const enum index next_item[] = { 426 ITEM_END, 427 ITEM_VOID, 428 ITEM_INVERT, 429 ITEM_ANY, 430 ITEM_PF, 431 ITEM_VF, 432 ITEM_PORT, 433 ITEM_RAW, 434 ITEM_ETH, 435 ITEM_VLAN, 436 ITEM_IPV4, 437 ITEM_IPV6, 438 ITEM_ICMP, 439 ITEM_UDP, 440 ITEM_TCP, 441 ITEM_SCTP, 442 ITEM_VXLAN, 443 ITEM_E_TAG, 444 ITEM_NVGRE, 445 ITEM_MPLS, 446 ITEM_GRE, 447 ZERO, 448 }; 449 450 static const enum index item_any[] = { 451 ITEM_ANY_NUM, 452 ITEM_NEXT, 453 ZERO, 454 }; 455 456 static const enum index item_vf[] = { 457 ITEM_VF_ID, 458 ITEM_NEXT, 459 ZERO, 460 }; 461 462 static const enum index item_port[] = { 463 ITEM_PORT_INDEX, 464 ITEM_NEXT, 465 ZERO, 466 }; 467 468 static const enum index item_raw[] = { 469 ITEM_RAW_RELATIVE, 470 ITEM_RAW_SEARCH, 471 ITEM_RAW_OFFSET, 472 ITEM_RAW_LIMIT, 473 ITEM_RAW_PATTERN, 474 ITEM_NEXT, 475 ZERO, 476 }; 477 478 static const enum index item_eth[] = { 479 ITEM_ETH_DST, 480 ITEM_ETH_SRC, 481 ITEM_ETH_TYPE, 482 ITEM_NEXT, 483 ZERO, 484 }; 485 486 static const enum index item_vlan[] = { 487 ITEM_VLAN_TPID, 488 ITEM_VLAN_TCI, 489 ITEM_VLAN_PCP, 490 ITEM_VLAN_DEI, 491 ITEM_VLAN_VID, 492 ITEM_NEXT, 493 ZERO, 494 }; 495 496 static const enum index item_ipv4[] = { 497 ITEM_IPV4_TOS, 498 ITEM_IPV4_TTL, 499 ITEM_IPV4_PROTO, 500 ITEM_IPV4_SRC, 501 ITEM_IPV4_DST, 502 ITEM_NEXT, 503 ZERO, 504 }; 505 506 static const enum index item_ipv6[] = { 507 ITEM_IPV6_TC, 508 ITEM_IPV6_FLOW, 509 ITEM_IPV6_PROTO, 510 ITEM_IPV6_HOP, 511 ITEM_IPV6_SRC, 512 ITEM_IPV6_DST, 513 ITEM_NEXT, 514 ZERO, 515 }; 516 517 static const enum index item_icmp[] = { 518 ITEM_ICMP_TYPE, 519 ITEM_ICMP_CODE, 520 ITEM_NEXT, 521 ZERO, 522 }; 523 524 static const enum index item_udp[] = { 525 ITEM_UDP_SRC, 526 ITEM_UDP_DST, 527 ITEM_NEXT, 528 ZERO, 529 }; 530 531 static const enum index item_tcp[] = { 532 ITEM_TCP_SRC, 533 ITEM_TCP_DST, 534 ITEM_NEXT, 535 ZERO, 536 }; 537 538 static const enum index item_sctp[] = { 539 ITEM_SCTP_SRC, 540 ITEM_SCTP_DST, 541 ITEM_SCTP_TAG, 542 ITEM_SCTP_CKSUM, 543 ITEM_NEXT, 544 ZERO, 545 }; 546 547 static const enum index item_vxlan[] = { 548 ITEM_VXLAN_VNI, 549 ITEM_NEXT, 550 ZERO, 551 }; 552 553 static const enum index item_e_tag[] = { 554 ITEM_E_TAG_GRP_ECID_B, 555 ITEM_NEXT, 556 ZERO, 557 }; 558 559 static const enum index item_nvgre[] = { 560 ITEM_NVGRE_TNI, 561 ITEM_NEXT, 562 ZERO, 563 }; 564 565 static const enum index item_mpls[] = { 566 ITEM_MPLS_LABEL, 567 ITEM_NEXT, 568 ZERO, 569 }; 570 571 static const enum index item_gre[] = { 572 ITEM_GRE_PROTO, 573 ITEM_NEXT, 574 ZERO, 575 }; 576 577 static const enum index next_action[] = { 578 ACTION_END, 579 ACTION_VOID, 580 ACTION_PASSTHRU, 581 ACTION_MARK, 582 ACTION_FLAG, 583 ACTION_QUEUE, 584 ACTION_DROP, 585 ACTION_COUNT, 586 ACTION_DUP, 587 ACTION_RSS, 588 ACTION_PF, 589 ACTION_VF, 590 ZERO, 591 }; 592 593 static const enum index action_mark[] = { 594 ACTION_MARK_ID, 595 ACTION_NEXT, 596 ZERO, 597 }; 598 599 static const enum index action_queue[] = { 600 ACTION_QUEUE_INDEX, 601 ACTION_NEXT, 602 ZERO, 603 }; 604 605 static const enum index action_dup[] = { 606 ACTION_DUP_INDEX, 607 ACTION_NEXT, 608 ZERO, 609 }; 610 611 static const enum index action_rss[] = { 612 ACTION_RSS_QUEUES, 613 ACTION_NEXT, 614 ZERO, 615 }; 616 617 static const enum index action_vf[] = { 618 ACTION_VF_ORIGINAL, 619 ACTION_VF_ID, 620 ACTION_NEXT, 621 ZERO, 622 }; 623 624 static int parse_init(struct context *, const struct token *, 625 const char *, unsigned int, 626 void *, unsigned int); 627 static int parse_vc(struct context *, const struct token *, 628 const char *, unsigned int, 629 void *, unsigned int); 630 static int parse_vc_spec(struct context *, const struct token *, 631 const char *, unsigned int, void *, unsigned int); 632 static int parse_vc_conf(struct context *, const struct token *, 633 const char *, unsigned int, void *, unsigned int); 634 static int parse_vc_action_rss_queue(struct context *, const struct token *, 635 const char *, unsigned int, void *, 636 unsigned int); 637 static int parse_destroy(struct context *, const struct token *, 638 const char *, unsigned int, 639 void *, unsigned int); 640 static int parse_flush(struct context *, const struct token *, 641 const char *, unsigned int, 642 void *, unsigned int); 643 static int parse_query(struct context *, const struct token *, 644 const char *, unsigned int, 645 void *, unsigned int); 646 static int parse_action(struct context *, const struct token *, 647 const char *, unsigned int, 648 void *, unsigned int); 649 static int parse_list(struct context *, const struct token *, 650 const char *, unsigned int, 651 void *, unsigned int); 652 static int parse_int(struct context *, const struct token *, 653 const char *, unsigned int, 654 void *, unsigned int); 655 static int parse_prefix(struct context *, const struct token *, 656 const char *, unsigned int, 657 void *, unsigned int); 658 static int parse_boolean(struct context *, const struct token *, 659 const char *, unsigned int, 660 void *, unsigned int); 661 static int parse_string(struct context *, const struct token *, 662 const char *, unsigned int, 663 void *, unsigned int); 664 static int parse_mac_addr(struct context *, const struct token *, 665 const char *, unsigned int, 666 void *, unsigned int); 667 static int parse_ipv4_addr(struct context *, const struct token *, 668 const char *, unsigned int, 669 void *, unsigned int); 670 static int parse_ipv6_addr(struct context *, const struct token *, 671 const char *, unsigned int, 672 void *, unsigned int); 673 static int parse_port(struct context *, const struct token *, 674 const char *, unsigned int, 675 void *, unsigned int); 676 static int comp_none(struct context *, const struct token *, 677 unsigned int, char *, unsigned int); 678 static int comp_boolean(struct context *, const struct token *, 679 unsigned int, char *, unsigned int); 680 static int comp_action(struct context *, const struct token *, 681 unsigned int, char *, unsigned int); 682 static int comp_port(struct context *, const struct token *, 683 unsigned int, char *, unsigned int); 684 static int comp_rule_id(struct context *, const struct token *, 685 unsigned int, char *, unsigned int); 686 static int comp_vc_action_rss_queue(struct context *, const struct token *, 687 unsigned int, char *, unsigned int); 688 689 /** Token definitions. */ 690 static const struct token token_list[] = { 691 /* Special tokens. */ 692 [ZERO] = { 693 .name = "ZERO", 694 .help = "null entry, abused as the entry point", 695 .next = NEXT(NEXT_ENTRY(FLOW)), 696 }, 697 [END] = { 698 .name = "", 699 .type = "RETURN", 700 .help = "command may end here", 701 }, 702 /* Common tokens. */ 703 [INTEGER] = { 704 .name = "{int}", 705 .type = "INTEGER", 706 .help = "integer value", 707 .call = parse_int, 708 .comp = comp_none, 709 }, 710 [UNSIGNED] = { 711 .name = "{unsigned}", 712 .type = "UNSIGNED", 713 .help = "unsigned integer value", 714 .call = parse_int, 715 .comp = comp_none, 716 }, 717 [PREFIX] = { 718 .name = "{prefix}", 719 .type = "PREFIX", 720 .help = "prefix length for bit-mask", 721 .call = parse_prefix, 722 .comp = comp_none, 723 }, 724 [BOOLEAN] = { 725 .name = "{boolean}", 726 .type = "BOOLEAN", 727 .help = "any boolean value", 728 .call = parse_boolean, 729 .comp = comp_boolean, 730 }, 731 [STRING] = { 732 .name = "{string}", 733 .type = "STRING", 734 .help = "fixed string", 735 .call = parse_string, 736 .comp = comp_none, 737 }, 738 [MAC_ADDR] = { 739 .name = "{MAC address}", 740 .type = "MAC-48", 741 .help = "standard MAC address notation", 742 .call = parse_mac_addr, 743 .comp = comp_none, 744 }, 745 [IPV4_ADDR] = { 746 .name = "{IPv4 address}", 747 .type = "IPV4 ADDRESS", 748 .help = "standard IPv4 address notation", 749 .call = parse_ipv4_addr, 750 .comp = comp_none, 751 }, 752 [IPV6_ADDR] = { 753 .name = "{IPv6 address}", 754 .type = "IPV6 ADDRESS", 755 .help = "standard IPv6 address notation", 756 .call = parse_ipv6_addr, 757 .comp = comp_none, 758 }, 759 [RULE_ID] = { 760 .name = "{rule id}", 761 .type = "RULE ID", 762 .help = "rule identifier", 763 .call = parse_int, 764 .comp = comp_rule_id, 765 }, 766 [PORT_ID] = { 767 .name = "{port_id}", 768 .type = "PORT ID", 769 .help = "port identifier", 770 .call = parse_port, 771 .comp = comp_port, 772 }, 773 [GROUP_ID] = { 774 .name = "{group_id}", 775 .type = "GROUP ID", 776 .help = "group identifier", 777 .call = parse_int, 778 .comp = comp_none, 779 }, 780 [PRIORITY_LEVEL] = { 781 .name = "{level}", 782 .type = "PRIORITY", 783 .help = "priority level", 784 .call = parse_int, 785 .comp = comp_none, 786 }, 787 /* Top-level command. */ 788 [FLOW] = { 789 .name = "flow", 790 .type = "{command} {port_id} [{arg} [...]]", 791 .help = "manage ingress/egress flow rules", 792 .next = NEXT(NEXT_ENTRY 793 (VALIDATE, 794 CREATE, 795 DESTROY, 796 FLUSH, 797 LIST, 798 QUERY)), 799 .call = parse_init, 800 }, 801 /* Sub-level commands. */ 802 [VALIDATE] = { 803 .name = "validate", 804 .help = "check whether a flow rule can be created", 805 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)), 806 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 807 .call = parse_vc, 808 }, 809 [CREATE] = { 810 .name = "create", 811 .help = "create a flow rule", 812 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)), 813 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 814 .call = parse_vc, 815 }, 816 [DESTROY] = { 817 .name = "destroy", 818 .help = "destroy specific flow rules", 819 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)), 820 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 821 .call = parse_destroy, 822 }, 823 [FLUSH] = { 824 .name = "flush", 825 .help = "destroy all flow rules", 826 .next = NEXT(NEXT_ENTRY(PORT_ID)), 827 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 828 .call = parse_flush, 829 }, 830 [QUERY] = { 831 .name = "query", 832 .help = "query an existing flow rule", 833 .next = NEXT(NEXT_ENTRY(QUERY_ACTION), 834 NEXT_ENTRY(RULE_ID), 835 NEXT_ENTRY(PORT_ID)), 836 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action), 837 ARGS_ENTRY(struct buffer, args.query.rule), 838 ARGS_ENTRY(struct buffer, port)), 839 .call = parse_query, 840 }, 841 [LIST] = { 842 .name = "list", 843 .help = "list existing flow rules", 844 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)), 845 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 846 .call = parse_list, 847 }, 848 /* Destroy arguments. */ 849 [DESTROY_RULE] = { 850 .name = "rule", 851 .help = "specify a rule identifier", 852 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)), 853 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)), 854 .call = parse_destroy, 855 }, 856 /* Query arguments. */ 857 [QUERY_ACTION] = { 858 .name = "{action}", 859 .type = "ACTION", 860 .help = "action to query, must be part of the rule", 861 .call = parse_action, 862 .comp = comp_action, 863 }, 864 /* List arguments. */ 865 [LIST_GROUP] = { 866 .name = "group", 867 .help = "specify a group", 868 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)), 869 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)), 870 .call = parse_list, 871 }, 872 /* Validate/create attributes. */ 873 [GROUP] = { 874 .name = "group", 875 .help = "specify a group", 876 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)), 877 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)), 878 .call = parse_vc, 879 }, 880 [PRIORITY] = { 881 .name = "priority", 882 .help = "specify a priority level", 883 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)), 884 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)), 885 .call = parse_vc, 886 }, 887 [INGRESS] = { 888 .name = "ingress", 889 .help = "affect rule to ingress", 890 .next = NEXT(next_vc_attr), 891 .call = parse_vc, 892 }, 893 [EGRESS] = { 894 .name = "egress", 895 .help = "affect rule to egress", 896 .next = NEXT(next_vc_attr), 897 .call = parse_vc, 898 }, 899 /* Validate/create pattern. */ 900 [PATTERN] = { 901 .name = "pattern", 902 .help = "submit a list of pattern items", 903 .next = NEXT(next_item), 904 .call = parse_vc, 905 }, 906 [ITEM_PARAM_IS] = { 907 .name = "is", 908 .help = "match value perfectly (with full bit-mask)", 909 .call = parse_vc_spec, 910 }, 911 [ITEM_PARAM_SPEC] = { 912 .name = "spec", 913 .help = "match value according to configured bit-mask", 914 .call = parse_vc_spec, 915 }, 916 [ITEM_PARAM_LAST] = { 917 .name = "last", 918 .help = "specify upper bound to establish a range", 919 .call = parse_vc_spec, 920 }, 921 [ITEM_PARAM_MASK] = { 922 .name = "mask", 923 .help = "specify bit-mask with relevant bits set to one", 924 .call = parse_vc_spec, 925 }, 926 [ITEM_PARAM_PREFIX] = { 927 .name = "prefix", 928 .help = "generate bit-mask from a prefix length", 929 .call = parse_vc_spec, 930 }, 931 [ITEM_NEXT] = { 932 .name = "/", 933 .help = "specify next pattern item", 934 .next = NEXT(next_item), 935 }, 936 [ITEM_END] = { 937 .name = "end", 938 .help = "end list of pattern items", 939 .priv = PRIV_ITEM(END, 0), 940 .next = NEXT(NEXT_ENTRY(ACTIONS)), 941 .call = parse_vc, 942 }, 943 [ITEM_VOID] = { 944 .name = "void", 945 .help = "no-op pattern item", 946 .priv = PRIV_ITEM(VOID, 0), 947 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), 948 .call = parse_vc, 949 }, 950 [ITEM_INVERT] = { 951 .name = "invert", 952 .help = "perform actions when pattern does not match", 953 .priv = PRIV_ITEM(INVERT, 0), 954 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), 955 .call = parse_vc, 956 }, 957 [ITEM_ANY] = { 958 .name = "any", 959 .help = "match any protocol for the current layer", 960 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)), 961 .next = NEXT(item_any), 962 .call = parse_vc, 963 }, 964 [ITEM_ANY_NUM] = { 965 .name = "num", 966 .help = "number of layers covered", 967 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), 968 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), 969 }, 970 [ITEM_PF] = { 971 .name = "pf", 972 .help = "match packets addressed to the physical function", 973 .priv = PRIV_ITEM(PF, 0), 974 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), 975 .call = parse_vc, 976 }, 977 [ITEM_VF] = { 978 .name = "vf", 979 .help = "match packets addressed to a virtual function ID", 980 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)), 981 .next = NEXT(item_vf), 982 .call = parse_vc, 983 }, 984 [ITEM_VF_ID] = { 985 .name = "id", 986 .help = "destination VF ID", 987 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param), 988 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)), 989 }, 990 [ITEM_PORT] = { 991 .name = "port", 992 .help = "device-specific physical port index to use", 993 .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)), 994 .next = NEXT(item_port), 995 .call = parse_vc, 996 }, 997 [ITEM_PORT_INDEX] = { 998 .name = "index", 999 .help = "physical port index", 1000 .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), 1001 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), 1002 }, 1003 [ITEM_RAW] = { 1004 .name = "raw", 1005 .help = "match an arbitrary byte string", 1006 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE), 1007 .next = NEXT(item_raw), 1008 .call = parse_vc, 1009 }, 1010 [ITEM_RAW_RELATIVE] = { 1011 .name = "relative", 1012 .help = "look for pattern after the previous item", 1013 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), 1014 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, 1015 relative, 1)), 1016 }, 1017 [ITEM_RAW_SEARCH] = { 1018 .name = "search", 1019 .help = "search pattern from offset (see also limit)", 1020 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), 1021 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, 1022 search, 1)), 1023 }, 1024 [ITEM_RAW_OFFSET] = { 1025 .name = "offset", 1026 .help = "absolute or relative offset for pattern", 1027 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param), 1028 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)), 1029 }, 1030 [ITEM_RAW_LIMIT] = { 1031 .name = "limit", 1032 .help = "search area limit for start of pattern", 1033 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param), 1034 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)), 1035 }, 1036 [ITEM_RAW_PATTERN] = { 1037 .name = "pattern", 1038 .help = "byte string to look for", 1039 .next = NEXT(item_raw, 1040 NEXT_ENTRY(STRING), 1041 NEXT_ENTRY(ITEM_PARAM_IS, 1042 ITEM_PARAM_SPEC, 1043 ITEM_PARAM_MASK)), 1044 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length), 1045 ARGS_ENTRY_USZ(struct rte_flow_item_raw, 1046 pattern, 1047 ITEM_RAW_PATTERN_SIZE)), 1048 }, 1049 [ITEM_ETH] = { 1050 .name = "eth", 1051 .help = "match Ethernet header", 1052 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)), 1053 .next = NEXT(item_eth), 1054 .call = parse_vc, 1055 }, 1056 [ITEM_ETH_DST] = { 1057 .name = "dst", 1058 .help = "destination MAC", 1059 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param), 1060 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, dst)), 1061 }, 1062 [ITEM_ETH_SRC] = { 1063 .name = "src", 1064 .help = "source MAC", 1065 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param), 1066 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, src)), 1067 }, 1068 [ITEM_ETH_TYPE] = { 1069 .name = "type", 1070 .help = "EtherType", 1071 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param), 1072 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)), 1073 }, 1074 [ITEM_VLAN] = { 1075 .name = "vlan", 1076 .help = "match 802.1Q/ad VLAN tag", 1077 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)), 1078 .next = NEXT(item_vlan), 1079 .call = parse_vc, 1080 }, 1081 [ITEM_VLAN_TPID] = { 1082 .name = "tpid", 1083 .help = "tag protocol identifier", 1084 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1085 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)), 1086 }, 1087 [ITEM_VLAN_TCI] = { 1088 .name = "tci", 1089 .help = "tag control information", 1090 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1091 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), 1092 }, 1093 [ITEM_VLAN_PCP] = { 1094 .name = "pcp", 1095 .help = "priority code point", 1096 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1097 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, 1098 tci, "\xe0\x00")), 1099 }, 1100 [ITEM_VLAN_DEI] = { 1101 .name = "dei", 1102 .help = "drop eligible indicator", 1103 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1104 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, 1105 tci, "\x10\x00")), 1106 }, 1107 [ITEM_VLAN_VID] = { 1108 .name = "vid", 1109 .help = "VLAN identifier", 1110 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1111 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, 1112 tci, "\x0f\xff")), 1113 }, 1114 [ITEM_IPV4] = { 1115 .name = "ipv4", 1116 .help = "match IPv4 header", 1117 .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), 1118 .next = NEXT(item_ipv4), 1119 .call = parse_vc, 1120 }, 1121 [ITEM_IPV4_TOS] = { 1122 .name = "tos", 1123 .help = "type of service", 1124 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), 1125 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1126 hdr.type_of_service)), 1127 }, 1128 [ITEM_IPV4_TTL] = { 1129 .name = "ttl", 1130 .help = "time to live", 1131 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), 1132 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1133 hdr.time_to_live)), 1134 }, 1135 [ITEM_IPV4_PROTO] = { 1136 .name = "proto", 1137 .help = "next protocol ID", 1138 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), 1139 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1140 hdr.next_proto_id)), 1141 }, 1142 [ITEM_IPV4_SRC] = { 1143 .name = "src", 1144 .help = "source address", 1145 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), 1146 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1147 hdr.src_addr)), 1148 }, 1149 [ITEM_IPV4_DST] = { 1150 .name = "dst", 1151 .help = "destination address", 1152 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), 1153 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1154 hdr.dst_addr)), 1155 }, 1156 [ITEM_IPV6] = { 1157 .name = "ipv6", 1158 .help = "match IPv6 header", 1159 .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), 1160 .next = NEXT(item_ipv6), 1161 .call = parse_vc, 1162 }, 1163 [ITEM_IPV6_TC] = { 1164 .name = "tc", 1165 .help = "traffic class", 1166 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1167 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6, 1168 hdr.vtc_flow, 1169 "\x0f\xf0\x00\x00")), 1170 }, 1171 [ITEM_IPV6_FLOW] = { 1172 .name = "flow", 1173 .help = "flow label", 1174 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1175 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6, 1176 hdr.vtc_flow, 1177 "\x00\x0f\xff\xff")), 1178 }, 1179 [ITEM_IPV6_PROTO] = { 1180 .name = "proto", 1181 .help = "protocol (next header)", 1182 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1183 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1184 hdr.proto)), 1185 }, 1186 [ITEM_IPV6_HOP] = { 1187 .name = "hop", 1188 .help = "hop limit", 1189 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1190 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1191 hdr.hop_limits)), 1192 }, 1193 [ITEM_IPV6_SRC] = { 1194 .name = "src", 1195 .help = "source address", 1196 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), 1197 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1198 hdr.src_addr)), 1199 }, 1200 [ITEM_IPV6_DST] = { 1201 .name = "dst", 1202 .help = "destination address", 1203 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), 1204 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1205 hdr.dst_addr)), 1206 }, 1207 [ITEM_ICMP] = { 1208 .name = "icmp", 1209 .help = "match ICMP header", 1210 .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), 1211 .next = NEXT(item_icmp), 1212 .call = parse_vc, 1213 }, 1214 [ITEM_ICMP_TYPE] = { 1215 .name = "type", 1216 .help = "ICMP packet type", 1217 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), 1218 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, 1219 hdr.icmp_type)), 1220 }, 1221 [ITEM_ICMP_CODE] = { 1222 .name = "code", 1223 .help = "ICMP packet code", 1224 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), 1225 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, 1226 hdr.icmp_code)), 1227 }, 1228 [ITEM_UDP] = { 1229 .name = "udp", 1230 .help = "match UDP header", 1231 .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)), 1232 .next = NEXT(item_udp), 1233 .call = parse_vc, 1234 }, 1235 [ITEM_UDP_SRC] = { 1236 .name = "src", 1237 .help = "UDP source port", 1238 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), 1239 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, 1240 hdr.src_port)), 1241 }, 1242 [ITEM_UDP_DST] = { 1243 .name = "dst", 1244 .help = "UDP destination port", 1245 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), 1246 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, 1247 hdr.dst_port)), 1248 }, 1249 [ITEM_TCP] = { 1250 .name = "tcp", 1251 .help = "match TCP header", 1252 .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), 1253 .next = NEXT(item_tcp), 1254 .call = parse_vc, 1255 }, 1256 [ITEM_TCP_SRC] = { 1257 .name = "src", 1258 .help = "TCP source port", 1259 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), 1260 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, 1261 hdr.src_port)), 1262 }, 1263 [ITEM_TCP_DST] = { 1264 .name = "dst", 1265 .help = "TCP destination port", 1266 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), 1267 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, 1268 hdr.dst_port)), 1269 }, 1270 [ITEM_SCTP] = { 1271 .name = "sctp", 1272 .help = "match SCTP header", 1273 .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), 1274 .next = NEXT(item_sctp), 1275 .call = parse_vc, 1276 }, 1277 [ITEM_SCTP_SRC] = { 1278 .name = "src", 1279 .help = "SCTP source port", 1280 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1281 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1282 hdr.src_port)), 1283 }, 1284 [ITEM_SCTP_DST] = { 1285 .name = "dst", 1286 .help = "SCTP destination port", 1287 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1288 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1289 hdr.dst_port)), 1290 }, 1291 [ITEM_SCTP_TAG] = { 1292 .name = "tag", 1293 .help = "validation tag", 1294 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1295 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1296 hdr.tag)), 1297 }, 1298 [ITEM_SCTP_CKSUM] = { 1299 .name = "cksum", 1300 .help = "checksum", 1301 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1302 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1303 hdr.cksum)), 1304 }, 1305 [ITEM_VXLAN] = { 1306 .name = "vxlan", 1307 .help = "match VXLAN header", 1308 .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), 1309 .next = NEXT(item_vxlan), 1310 .call = parse_vc, 1311 }, 1312 [ITEM_VXLAN_VNI] = { 1313 .name = "vni", 1314 .help = "VXLAN identifier", 1315 .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param), 1316 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)), 1317 }, 1318 [ITEM_E_TAG] = { 1319 .name = "e_tag", 1320 .help = "match E-Tag header", 1321 .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)), 1322 .next = NEXT(item_e_tag), 1323 .call = parse_vc, 1324 }, 1325 [ITEM_E_TAG_GRP_ECID_B] = { 1326 .name = "grp_ecid_b", 1327 .help = "GRP and E-CID base", 1328 .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param), 1329 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag, 1330 rsvd_grp_ecid_b, 1331 "\x3f\xff")), 1332 }, 1333 [ITEM_NVGRE] = { 1334 .name = "nvgre", 1335 .help = "match NVGRE header", 1336 .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)), 1337 .next = NEXT(item_nvgre), 1338 .call = parse_vc, 1339 }, 1340 [ITEM_NVGRE_TNI] = { 1341 .name = "tni", 1342 .help = "virtual subnet ID", 1343 .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param), 1344 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)), 1345 }, 1346 [ITEM_MPLS] = { 1347 .name = "mpls", 1348 .help = "match MPLS header", 1349 .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)), 1350 .next = NEXT(item_mpls), 1351 .call = parse_vc, 1352 }, 1353 [ITEM_MPLS_LABEL] = { 1354 .name = "label", 1355 .help = "MPLS label", 1356 .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param), 1357 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls, 1358 label_tc_s, 1359 "\xff\xff\xf0")), 1360 }, 1361 [ITEM_GRE] = { 1362 .name = "gre", 1363 .help = "match GRE header", 1364 .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)), 1365 .next = NEXT(item_gre), 1366 .call = parse_vc, 1367 }, 1368 [ITEM_GRE_PROTO] = { 1369 .name = "protocol", 1370 .help = "GRE protocol type", 1371 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param), 1372 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre, 1373 protocol)), 1374 }, 1375 /* Validate/create actions. */ 1376 [ACTIONS] = { 1377 .name = "actions", 1378 .help = "submit a list of associated actions", 1379 .next = NEXT(next_action), 1380 .call = parse_vc, 1381 }, 1382 [ACTION_NEXT] = { 1383 .name = "/", 1384 .help = "specify next action", 1385 .next = NEXT(next_action), 1386 }, 1387 [ACTION_END] = { 1388 .name = "end", 1389 .help = "end list of actions", 1390 .priv = PRIV_ACTION(END, 0), 1391 .call = parse_vc, 1392 }, 1393 [ACTION_VOID] = { 1394 .name = "void", 1395 .help = "no-op action", 1396 .priv = PRIV_ACTION(VOID, 0), 1397 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1398 .call = parse_vc, 1399 }, 1400 [ACTION_PASSTHRU] = { 1401 .name = "passthru", 1402 .help = "let subsequent rule process matched packets", 1403 .priv = PRIV_ACTION(PASSTHRU, 0), 1404 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1405 .call = parse_vc, 1406 }, 1407 [ACTION_MARK] = { 1408 .name = "mark", 1409 .help = "attach 32 bit value to packets", 1410 .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)), 1411 .next = NEXT(action_mark), 1412 .call = parse_vc, 1413 }, 1414 [ACTION_MARK_ID] = { 1415 .name = "id", 1416 .help = "32 bit value to return with packets", 1417 .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)), 1418 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)), 1419 .call = parse_vc_conf, 1420 }, 1421 [ACTION_FLAG] = { 1422 .name = "flag", 1423 .help = "flag packets", 1424 .priv = PRIV_ACTION(FLAG, 0), 1425 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1426 .call = parse_vc, 1427 }, 1428 [ACTION_QUEUE] = { 1429 .name = "queue", 1430 .help = "assign packets to a given queue index", 1431 .priv = PRIV_ACTION(QUEUE, 1432 sizeof(struct rte_flow_action_queue)), 1433 .next = NEXT(action_queue), 1434 .call = parse_vc, 1435 }, 1436 [ACTION_QUEUE_INDEX] = { 1437 .name = "index", 1438 .help = "queue index to use", 1439 .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)), 1440 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)), 1441 .call = parse_vc_conf, 1442 }, 1443 [ACTION_DROP] = { 1444 .name = "drop", 1445 .help = "drop packets (note: passthru has priority)", 1446 .priv = PRIV_ACTION(DROP, 0), 1447 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1448 .call = parse_vc, 1449 }, 1450 [ACTION_COUNT] = { 1451 .name = "count", 1452 .help = "enable counters for this rule", 1453 .priv = PRIV_ACTION(COUNT, 0), 1454 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1455 .call = parse_vc, 1456 }, 1457 [ACTION_DUP] = { 1458 .name = "dup", 1459 .help = "duplicate packets to a given queue index", 1460 .priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)), 1461 .next = NEXT(action_dup), 1462 .call = parse_vc, 1463 }, 1464 [ACTION_DUP_INDEX] = { 1465 .name = "index", 1466 .help = "queue index to duplicate packets to", 1467 .next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)), 1468 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)), 1469 .call = parse_vc_conf, 1470 }, 1471 [ACTION_RSS] = { 1472 .name = "rss", 1473 .help = "spread packets among several queues", 1474 .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE), 1475 .next = NEXT(action_rss), 1476 .call = parse_vc, 1477 }, 1478 [ACTION_RSS_QUEUES] = { 1479 .name = "queues", 1480 .help = "queue indices to use", 1481 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)), 1482 .call = parse_vc_conf, 1483 }, 1484 [ACTION_RSS_QUEUE] = { 1485 .name = "{queue}", 1486 .help = "queue index", 1487 .call = parse_vc_action_rss_queue, 1488 .comp = comp_vc_action_rss_queue, 1489 }, 1490 [ACTION_PF] = { 1491 .name = "pf", 1492 .help = "redirect packets to physical device function", 1493 .priv = PRIV_ACTION(PF, 0), 1494 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1495 .call = parse_vc, 1496 }, 1497 [ACTION_VF] = { 1498 .name = "vf", 1499 .help = "redirect packets to virtual device function", 1500 .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)), 1501 .next = NEXT(action_vf), 1502 .call = parse_vc, 1503 }, 1504 [ACTION_VF_ORIGINAL] = { 1505 .name = "original", 1506 .help = "use original VF ID if possible", 1507 .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)), 1508 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf, 1509 original, 1)), 1510 .call = parse_vc_conf, 1511 }, 1512 [ACTION_VF_ID] = { 1513 .name = "id", 1514 .help = "VF ID to redirect packets to", 1515 .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)), 1516 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)), 1517 .call = parse_vc_conf, 1518 }, 1519 }; 1520 1521 /** Remove and return last entry from argument stack. */ 1522 static const struct arg * 1523 pop_args(struct context *ctx) 1524 { 1525 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL; 1526 } 1527 1528 /** Add entry on top of the argument stack. */ 1529 static int 1530 push_args(struct context *ctx, const struct arg *arg) 1531 { 1532 if (ctx->args_num == CTX_STACK_SIZE) 1533 return -1; 1534 ctx->args[ctx->args_num++] = arg; 1535 return 0; 1536 } 1537 1538 /** Spread value into buffer according to bit-mask. */ 1539 static size_t 1540 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg) 1541 { 1542 uint32_t i = arg->size; 1543 uint32_t end = 0; 1544 int sub = 1; 1545 int add = 0; 1546 size_t len = 0; 1547 1548 if (!arg->mask) 1549 return 0; 1550 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 1551 if (!arg->hton) { 1552 i = 0; 1553 end = arg->size; 1554 sub = 0; 1555 add = 1; 1556 } 1557 #endif 1558 while (i != end) { 1559 unsigned int shift = 0; 1560 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub); 1561 1562 for (shift = 0; arg->mask[i] >> shift; ++shift) { 1563 if (!(arg->mask[i] & (1 << shift))) 1564 continue; 1565 ++len; 1566 if (!dst) 1567 continue; 1568 *buf &= ~(1 << shift); 1569 *buf |= (val & 1) << shift; 1570 val >>= 1; 1571 } 1572 i += add; 1573 } 1574 return len; 1575 } 1576 1577 /** 1578 * Parse a prefix length and generate a bit-mask. 1579 * 1580 * Last argument (ctx->args) is retrieved to determine mask size, storage 1581 * location and whether the result must use network byte ordering. 1582 */ 1583 static int 1584 parse_prefix(struct context *ctx, const struct token *token, 1585 const char *str, unsigned int len, 1586 void *buf, unsigned int size) 1587 { 1588 const struct arg *arg = pop_args(ctx); 1589 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff"; 1590 char *end; 1591 uintmax_t u; 1592 unsigned int bytes; 1593 unsigned int extra; 1594 1595 (void)token; 1596 /* Argument is expected. */ 1597 if (!arg) 1598 return -1; 1599 errno = 0; 1600 u = strtoumax(str, &end, 0); 1601 if (errno || (size_t)(end - str) != len) 1602 goto error; 1603 if (arg->mask) { 1604 uintmax_t v = 0; 1605 1606 extra = arg_entry_bf_fill(NULL, 0, arg); 1607 if (u > extra) 1608 goto error; 1609 if (!ctx->object) 1610 return len; 1611 extra -= u; 1612 while (u--) 1613 (v <<= 1, v |= 1); 1614 v <<= extra; 1615 if (!arg_entry_bf_fill(ctx->object, v, arg) || 1616 !arg_entry_bf_fill(ctx->objmask, -1, arg)) 1617 goto error; 1618 return len; 1619 } 1620 bytes = u / 8; 1621 extra = u % 8; 1622 size = arg->size; 1623 if (bytes > size || bytes + !!extra > size) 1624 goto error; 1625 if (!ctx->object) 1626 return len; 1627 buf = (uint8_t *)ctx->object + arg->offset; 1628 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 1629 if (!arg->hton) { 1630 memset((uint8_t *)buf + size - bytes, 0xff, bytes); 1631 memset(buf, 0x00, size - bytes); 1632 if (extra) 1633 ((uint8_t *)buf)[size - bytes - 1] = conv[extra]; 1634 } else 1635 #endif 1636 { 1637 memset(buf, 0xff, bytes); 1638 memset((uint8_t *)buf + bytes, 0x00, size - bytes); 1639 if (extra) 1640 ((uint8_t *)buf)[bytes] = conv[extra]; 1641 } 1642 if (ctx->objmask) 1643 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 1644 return len; 1645 error: 1646 push_args(ctx, arg); 1647 return -1; 1648 } 1649 1650 /** Default parsing function for token name matching. */ 1651 static int 1652 parse_default(struct context *ctx, const struct token *token, 1653 const char *str, unsigned int len, 1654 void *buf, unsigned int size) 1655 { 1656 (void)ctx; 1657 (void)buf; 1658 (void)size; 1659 if (strncmp(str, token->name, len)) 1660 return -1; 1661 return len; 1662 } 1663 1664 /** Parse flow command, initialize output buffer for subsequent tokens. */ 1665 static int 1666 parse_init(struct context *ctx, const struct token *token, 1667 const char *str, unsigned int len, 1668 void *buf, unsigned int size) 1669 { 1670 struct buffer *out = buf; 1671 1672 /* Token name must match. */ 1673 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1674 return -1; 1675 /* Nothing else to do if there is no buffer. */ 1676 if (!out) 1677 return len; 1678 /* Make sure buffer is large enough. */ 1679 if (size < sizeof(*out)) 1680 return -1; 1681 /* Initialize buffer. */ 1682 memset(out, 0x00, sizeof(*out)); 1683 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out)); 1684 ctx->objdata = 0; 1685 ctx->object = out; 1686 ctx->objmask = NULL; 1687 return len; 1688 } 1689 1690 /** Parse tokens for validate/create commands. */ 1691 static int 1692 parse_vc(struct context *ctx, const struct token *token, 1693 const char *str, unsigned int len, 1694 void *buf, unsigned int size) 1695 { 1696 struct buffer *out = buf; 1697 uint8_t *data; 1698 uint32_t data_size; 1699 1700 /* Token name must match. */ 1701 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1702 return -1; 1703 /* Nothing else to do if there is no buffer. */ 1704 if (!out) 1705 return len; 1706 if (!out->command) { 1707 if (ctx->curr != VALIDATE && ctx->curr != CREATE) 1708 return -1; 1709 if (sizeof(*out) > size) 1710 return -1; 1711 out->command = ctx->curr; 1712 ctx->objdata = 0; 1713 ctx->object = out; 1714 ctx->objmask = NULL; 1715 out->args.vc.data = (uint8_t *)out + size; 1716 return len; 1717 } 1718 ctx->objdata = 0; 1719 ctx->object = &out->args.vc.attr; 1720 ctx->objmask = NULL; 1721 switch (ctx->curr) { 1722 case GROUP: 1723 case PRIORITY: 1724 return len; 1725 case INGRESS: 1726 out->args.vc.attr.ingress = 1; 1727 return len; 1728 case EGRESS: 1729 out->args.vc.attr.egress = 1; 1730 return len; 1731 case PATTERN: 1732 out->args.vc.pattern = 1733 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), 1734 sizeof(double)); 1735 ctx->object = out->args.vc.pattern; 1736 ctx->objmask = NULL; 1737 return len; 1738 case ACTIONS: 1739 out->args.vc.actions = 1740 (void *)RTE_ALIGN_CEIL((uintptr_t) 1741 (out->args.vc.pattern + 1742 out->args.vc.pattern_n), 1743 sizeof(double)); 1744 ctx->object = out->args.vc.actions; 1745 ctx->objmask = NULL; 1746 return len; 1747 default: 1748 if (!token->priv) 1749 return -1; 1750 break; 1751 } 1752 if (!out->args.vc.actions) { 1753 const struct parse_item_priv *priv = token->priv; 1754 struct rte_flow_item *item = 1755 out->args.vc.pattern + out->args.vc.pattern_n; 1756 1757 data_size = priv->size * 3; /* spec, last, mask */ 1758 data = (void *)RTE_ALIGN_FLOOR((uintptr_t) 1759 (out->args.vc.data - data_size), 1760 sizeof(double)); 1761 if ((uint8_t *)item + sizeof(*item) > data) 1762 return -1; 1763 *item = (struct rte_flow_item){ 1764 .type = priv->type, 1765 }; 1766 ++out->args.vc.pattern_n; 1767 ctx->object = item; 1768 ctx->objmask = NULL; 1769 } else { 1770 const struct parse_action_priv *priv = token->priv; 1771 struct rte_flow_action *action = 1772 out->args.vc.actions + out->args.vc.actions_n; 1773 1774 data_size = priv->size; /* configuration */ 1775 data = (void *)RTE_ALIGN_FLOOR((uintptr_t) 1776 (out->args.vc.data - data_size), 1777 sizeof(double)); 1778 if ((uint8_t *)action + sizeof(*action) > data) 1779 return -1; 1780 *action = (struct rte_flow_action){ 1781 .type = priv->type, 1782 }; 1783 ++out->args.vc.actions_n; 1784 ctx->object = action; 1785 ctx->objmask = NULL; 1786 } 1787 memset(data, 0, data_size); 1788 out->args.vc.data = data; 1789 ctx->objdata = data_size; 1790 return len; 1791 } 1792 1793 /** Parse pattern item parameter type. */ 1794 static int 1795 parse_vc_spec(struct context *ctx, const struct token *token, 1796 const char *str, unsigned int len, 1797 void *buf, unsigned int size) 1798 { 1799 struct buffer *out = buf; 1800 struct rte_flow_item *item; 1801 uint32_t data_size; 1802 int index; 1803 int objmask = 0; 1804 1805 (void)size; 1806 /* Token name must match. */ 1807 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1808 return -1; 1809 /* Parse parameter types. */ 1810 switch (ctx->curr) { 1811 case ITEM_PARAM_IS: 1812 index = 0; 1813 objmask = 1; 1814 break; 1815 case ITEM_PARAM_SPEC: 1816 index = 0; 1817 break; 1818 case ITEM_PARAM_LAST: 1819 index = 1; 1820 break; 1821 case ITEM_PARAM_PREFIX: 1822 /* Modify next token to expect a prefix. */ 1823 if (ctx->next_num < 2) 1824 return -1; 1825 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX); 1826 /* Fall through. */ 1827 case ITEM_PARAM_MASK: 1828 index = 2; 1829 break; 1830 default: 1831 return -1; 1832 } 1833 /* Nothing else to do if there is no buffer. */ 1834 if (!out) 1835 return len; 1836 if (!out->args.vc.pattern_n) 1837 return -1; 1838 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1]; 1839 data_size = ctx->objdata / 3; /* spec, last, mask */ 1840 /* Point to selected object. */ 1841 ctx->object = out->args.vc.data + (data_size * index); 1842 if (objmask) { 1843 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */ 1844 item->mask = ctx->objmask; 1845 } else 1846 ctx->objmask = NULL; 1847 /* Update relevant item pointer. */ 1848 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] = 1849 ctx->object; 1850 return len; 1851 } 1852 1853 /** Parse action configuration field. */ 1854 static int 1855 parse_vc_conf(struct context *ctx, const struct token *token, 1856 const char *str, unsigned int len, 1857 void *buf, unsigned int size) 1858 { 1859 struct buffer *out = buf; 1860 struct rte_flow_action *action; 1861 1862 (void)size; 1863 /* Token name must match. */ 1864 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1865 return -1; 1866 /* Nothing else to do if there is no buffer. */ 1867 if (!out) 1868 return len; 1869 if (!out->args.vc.actions_n) 1870 return -1; 1871 action = &out->args.vc.actions[out->args.vc.actions_n - 1]; 1872 /* Point to selected object. */ 1873 ctx->object = out->args.vc.data; 1874 ctx->objmask = NULL; 1875 /* Update configuration pointer. */ 1876 action->conf = ctx->object; 1877 return len; 1878 } 1879 1880 /** 1881 * Parse queue field for RSS action. 1882 * 1883 * Valid tokens are queue indices and the "end" token. 1884 */ 1885 static int 1886 parse_vc_action_rss_queue(struct context *ctx, const struct token *token, 1887 const char *str, unsigned int len, 1888 void *buf, unsigned int size) 1889 { 1890 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE); 1891 int ret; 1892 int i; 1893 1894 (void)token; 1895 (void)buf; 1896 (void)size; 1897 if (ctx->curr != ACTION_RSS_QUEUE) 1898 return -1; 1899 i = ctx->objdata >> 16; 1900 if (!strncmp(str, "end", len)) { 1901 ctx->objdata &= 0xffff; 1902 return len; 1903 } 1904 if (i >= ACTION_RSS_NUM) 1905 return -1; 1906 if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i]))) 1907 return -1; 1908 ret = parse_int(ctx, token, str, len, NULL, 0); 1909 if (ret < 0) { 1910 pop_args(ctx); 1911 return -1; 1912 } 1913 ++i; 1914 ctx->objdata = i << 16 | (ctx->objdata & 0xffff); 1915 /* Repeat token. */ 1916 if (ctx->next_num == RTE_DIM(ctx->next)) 1917 return -1; 1918 ctx->next[ctx->next_num++] = next; 1919 if (!ctx->object) 1920 return len; 1921 ((struct rte_flow_action_rss *)ctx->object)->num = i; 1922 return len; 1923 } 1924 1925 /** Parse tokens for destroy command. */ 1926 static int 1927 parse_destroy(struct context *ctx, const struct token *token, 1928 const char *str, unsigned int len, 1929 void *buf, unsigned int size) 1930 { 1931 struct buffer *out = buf; 1932 1933 /* Token name must match. */ 1934 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1935 return -1; 1936 /* Nothing else to do if there is no buffer. */ 1937 if (!out) 1938 return len; 1939 if (!out->command) { 1940 if (ctx->curr != DESTROY) 1941 return -1; 1942 if (sizeof(*out) > size) 1943 return -1; 1944 out->command = ctx->curr; 1945 ctx->objdata = 0; 1946 ctx->object = out; 1947 ctx->objmask = NULL; 1948 out->args.destroy.rule = 1949 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), 1950 sizeof(double)); 1951 return len; 1952 } 1953 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) + 1954 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size) 1955 return -1; 1956 ctx->objdata = 0; 1957 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++; 1958 ctx->objmask = NULL; 1959 return len; 1960 } 1961 1962 /** Parse tokens for flush command. */ 1963 static int 1964 parse_flush(struct context *ctx, const struct token *token, 1965 const char *str, unsigned int len, 1966 void *buf, unsigned int size) 1967 { 1968 struct buffer *out = buf; 1969 1970 /* Token name must match. */ 1971 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1972 return -1; 1973 /* Nothing else to do if there is no buffer. */ 1974 if (!out) 1975 return len; 1976 if (!out->command) { 1977 if (ctx->curr != FLUSH) 1978 return -1; 1979 if (sizeof(*out) > size) 1980 return -1; 1981 out->command = ctx->curr; 1982 ctx->objdata = 0; 1983 ctx->object = out; 1984 ctx->objmask = NULL; 1985 } 1986 return len; 1987 } 1988 1989 /** Parse tokens for query command. */ 1990 static int 1991 parse_query(struct context *ctx, const struct token *token, 1992 const char *str, unsigned int len, 1993 void *buf, unsigned int size) 1994 { 1995 struct buffer *out = buf; 1996 1997 /* Token name must match. */ 1998 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 1999 return -1; 2000 /* Nothing else to do if there is no buffer. */ 2001 if (!out) 2002 return len; 2003 if (!out->command) { 2004 if (ctx->curr != QUERY) 2005 return -1; 2006 if (sizeof(*out) > size) 2007 return -1; 2008 out->command = ctx->curr; 2009 ctx->objdata = 0; 2010 ctx->object = out; 2011 ctx->objmask = NULL; 2012 } 2013 return len; 2014 } 2015 2016 /** Parse action names. */ 2017 static int 2018 parse_action(struct context *ctx, const struct token *token, 2019 const char *str, unsigned int len, 2020 void *buf, unsigned int size) 2021 { 2022 struct buffer *out = buf; 2023 const struct arg *arg = pop_args(ctx); 2024 unsigned int i; 2025 2026 (void)size; 2027 /* Argument is expected. */ 2028 if (!arg) 2029 return -1; 2030 /* Parse action name. */ 2031 for (i = 0; next_action[i]; ++i) { 2032 const struct parse_action_priv *priv; 2033 2034 token = &token_list[next_action[i]]; 2035 if (strncmp(token->name, str, len)) 2036 continue; 2037 priv = token->priv; 2038 if (!priv) 2039 goto error; 2040 if (out) 2041 memcpy((uint8_t *)ctx->object + arg->offset, 2042 &priv->type, 2043 arg->size); 2044 return len; 2045 } 2046 error: 2047 push_args(ctx, arg); 2048 return -1; 2049 } 2050 2051 /** Parse tokens for list command. */ 2052 static int 2053 parse_list(struct context *ctx, const struct token *token, 2054 const char *str, unsigned int len, 2055 void *buf, unsigned int size) 2056 { 2057 struct buffer *out = buf; 2058 2059 /* Token name must match. */ 2060 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2061 return -1; 2062 /* Nothing else to do if there is no buffer. */ 2063 if (!out) 2064 return len; 2065 if (!out->command) { 2066 if (ctx->curr != LIST) 2067 return -1; 2068 if (sizeof(*out) > size) 2069 return -1; 2070 out->command = ctx->curr; 2071 ctx->objdata = 0; 2072 ctx->object = out; 2073 ctx->objmask = NULL; 2074 out->args.list.group = 2075 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), 2076 sizeof(double)); 2077 return len; 2078 } 2079 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) + 2080 sizeof(*out->args.list.group)) > (uint8_t *)out + size) 2081 return -1; 2082 ctx->objdata = 0; 2083 ctx->object = out->args.list.group + out->args.list.group_n++; 2084 ctx->objmask = NULL; 2085 return len; 2086 } 2087 2088 /** 2089 * Parse signed/unsigned integers 8 to 64-bit long. 2090 * 2091 * Last argument (ctx->args) is retrieved to determine integer type and 2092 * storage location. 2093 */ 2094 static int 2095 parse_int(struct context *ctx, const struct token *token, 2096 const char *str, unsigned int len, 2097 void *buf, unsigned int size) 2098 { 2099 const struct arg *arg = pop_args(ctx); 2100 uintmax_t u; 2101 char *end; 2102 2103 (void)token; 2104 /* Argument is expected. */ 2105 if (!arg) 2106 return -1; 2107 errno = 0; 2108 u = arg->sign ? 2109 (uintmax_t)strtoimax(str, &end, 0) : 2110 strtoumax(str, &end, 0); 2111 if (errno || (size_t)(end - str) != len) 2112 goto error; 2113 if (!ctx->object) 2114 return len; 2115 if (arg->mask) { 2116 if (!arg_entry_bf_fill(ctx->object, u, arg) || 2117 !arg_entry_bf_fill(ctx->objmask, -1, arg)) 2118 goto error; 2119 return len; 2120 } 2121 buf = (uint8_t *)ctx->object + arg->offset; 2122 size = arg->size; 2123 objmask: 2124 switch (size) { 2125 case sizeof(uint8_t): 2126 *(uint8_t *)buf = u; 2127 break; 2128 case sizeof(uint16_t): 2129 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u; 2130 break; 2131 case sizeof(uint8_t [3]): 2132 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 2133 if (!arg->hton) { 2134 ((uint8_t *)buf)[0] = u; 2135 ((uint8_t *)buf)[1] = u >> 8; 2136 ((uint8_t *)buf)[2] = u >> 16; 2137 break; 2138 } 2139 #endif 2140 ((uint8_t *)buf)[0] = u >> 16; 2141 ((uint8_t *)buf)[1] = u >> 8; 2142 ((uint8_t *)buf)[2] = u; 2143 break; 2144 case sizeof(uint32_t): 2145 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u; 2146 break; 2147 case sizeof(uint64_t): 2148 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u; 2149 break; 2150 default: 2151 goto error; 2152 } 2153 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) { 2154 u = -1; 2155 buf = (uint8_t *)ctx->objmask + arg->offset; 2156 goto objmask; 2157 } 2158 return len; 2159 error: 2160 push_args(ctx, arg); 2161 return -1; 2162 } 2163 2164 /** 2165 * Parse a string. 2166 * 2167 * Two arguments (ctx->args) are retrieved from the stack to store data and 2168 * its length (in that order). 2169 */ 2170 static int 2171 parse_string(struct context *ctx, const struct token *token, 2172 const char *str, unsigned int len, 2173 void *buf, unsigned int size) 2174 { 2175 const struct arg *arg_data = pop_args(ctx); 2176 const struct arg *arg_len = pop_args(ctx); 2177 char tmp[16]; /* Ought to be enough. */ 2178 int ret; 2179 2180 /* Arguments are expected. */ 2181 if (!arg_data) 2182 return -1; 2183 if (!arg_len) { 2184 push_args(ctx, arg_data); 2185 return -1; 2186 } 2187 size = arg_data->size; 2188 /* Bit-mask fill is not supported. */ 2189 if (arg_data->mask || size < len) 2190 goto error; 2191 if (!ctx->object) 2192 return len; 2193 /* Let parse_int() fill length information first. */ 2194 ret = snprintf(tmp, sizeof(tmp), "%u", len); 2195 if (ret < 0) 2196 goto error; 2197 push_args(ctx, arg_len); 2198 ret = parse_int(ctx, token, tmp, ret, NULL, 0); 2199 if (ret < 0) { 2200 pop_args(ctx); 2201 goto error; 2202 } 2203 buf = (uint8_t *)ctx->object + arg_data->offset; 2204 /* Output buffer is not necessarily NUL-terminated. */ 2205 memcpy(buf, str, len); 2206 memset((uint8_t *)buf + len, 0x55, size - len); 2207 if (ctx->objmask) 2208 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len); 2209 return len; 2210 error: 2211 push_args(ctx, arg_len); 2212 push_args(ctx, arg_data); 2213 return -1; 2214 } 2215 2216 /** 2217 * Parse a MAC address. 2218 * 2219 * Last argument (ctx->args) is retrieved to determine storage size and 2220 * location. 2221 */ 2222 static int 2223 parse_mac_addr(struct context *ctx, const struct token *token, 2224 const char *str, unsigned int len, 2225 void *buf, unsigned int size) 2226 { 2227 const struct arg *arg = pop_args(ctx); 2228 struct ether_addr tmp; 2229 int ret; 2230 2231 (void)token; 2232 /* Argument is expected. */ 2233 if (!arg) 2234 return -1; 2235 size = arg->size; 2236 /* Bit-mask fill is not supported. */ 2237 if (arg->mask || size != sizeof(tmp)) 2238 goto error; 2239 ret = cmdline_parse_etheraddr(NULL, str, &tmp, size); 2240 if (ret < 0 || (unsigned int)ret != len) 2241 goto error; 2242 if (!ctx->object) 2243 return len; 2244 buf = (uint8_t *)ctx->object + arg->offset; 2245 memcpy(buf, &tmp, size); 2246 if (ctx->objmask) 2247 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 2248 return len; 2249 error: 2250 push_args(ctx, arg); 2251 return -1; 2252 } 2253 2254 /** 2255 * Parse an IPv4 address. 2256 * 2257 * Last argument (ctx->args) is retrieved to determine storage size and 2258 * location. 2259 */ 2260 static int 2261 parse_ipv4_addr(struct context *ctx, const struct token *token, 2262 const char *str, unsigned int len, 2263 void *buf, unsigned int size) 2264 { 2265 const struct arg *arg = pop_args(ctx); 2266 char str2[len + 1]; 2267 struct in_addr tmp; 2268 int ret; 2269 2270 /* Argument is expected. */ 2271 if (!arg) 2272 return -1; 2273 size = arg->size; 2274 /* Bit-mask fill is not supported. */ 2275 if (arg->mask || size != sizeof(tmp)) 2276 goto error; 2277 /* Only network endian is supported. */ 2278 if (!arg->hton) 2279 goto error; 2280 memcpy(str2, str, len); 2281 str2[len] = '\0'; 2282 ret = inet_pton(AF_INET, str2, &tmp); 2283 if (ret != 1) { 2284 /* Attempt integer parsing. */ 2285 push_args(ctx, arg); 2286 return parse_int(ctx, token, str, len, buf, size); 2287 } 2288 if (!ctx->object) 2289 return len; 2290 buf = (uint8_t *)ctx->object + arg->offset; 2291 memcpy(buf, &tmp, size); 2292 if (ctx->objmask) 2293 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 2294 return len; 2295 error: 2296 push_args(ctx, arg); 2297 return -1; 2298 } 2299 2300 /** 2301 * Parse an IPv6 address. 2302 * 2303 * Last argument (ctx->args) is retrieved to determine storage size and 2304 * location. 2305 */ 2306 static int 2307 parse_ipv6_addr(struct context *ctx, const struct token *token, 2308 const char *str, unsigned int len, 2309 void *buf, unsigned int size) 2310 { 2311 const struct arg *arg = pop_args(ctx); 2312 char str2[len + 1]; 2313 struct in6_addr tmp; 2314 int ret; 2315 2316 (void)token; 2317 /* Argument is expected. */ 2318 if (!arg) 2319 return -1; 2320 size = arg->size; 2321 /* Bit-mask fill is not supported. */ 2322 if (arg->mask || size != sizeof(tmp)) 2323 goto error; 2324 /* Only network endian is supported. */ 2325 if (!arg->hton) 2326 goto error; 2327 memcpy(str2, str, len); 2328 str2[len] = '\0'; 2329 ret = inet_pton(AF_INET6, str2, &tmp); 2330 if (ret != 1) 2331 goto error; 2332 if (!ctx->object) 2333 return len; 2334 buf = (uint8_t *)ctx->object + arg->offset; 2335 memcpy(buf, &tmp, size); 2336 if (ctx->objmask) 2337 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 2338 return len; 2339 error: 2340 push_args(ctx, arg); 2341 return -1; 2342 } 2343 2344 /** Boolean values (even indices stand for false). */ 2345 static const char *const boolean_name[] = { 2346 "0", "1", 2347 "false", "true", 2348 "no", "yes", 2349 "N", "Y", 2350 NULL, 2351 }; 2352 2353 /** 2354 * Parse a boolean value. 2355 * 2356 * Last argument (ctx->args) is retrieved to determine storage size and 2357 * location. 2358 */ 2359 static int 2360 parse_boolean(struct context *ctx, const struct token *token, 2361 const char *str, unsigned int len, 2362 void *buf, unsigned int size) 2363 { 2364 const struct arg *arg = pop_args(ctx); 2365 unsigned int i; 2366 int ret; 2367 2368 /* Argument is expected. */ 2369 if (!arg) 2370 return -1; 2371 for (i = 0; boolean_name[i]; ++i) 2372 if (!strncmp(str, boolean_name[i], len)) 2373 break; 2374 /* Process token as integer. */ 2375 if (boolean_name[i]) 2376 str = i & 1 ? "1" : "0"; 2377 push_args(ctx, arg); 2378 ret = parse_int(ctx, token, str, strlen(str), buf, size); 2379 return ret > 0 ? (int)len : ret; 2380 } 2381 2382 /** Parse port and update context. */ 2383 static int 2384 parse_port(struct context *ctx, const struct token *token, 2385 const char *str, unsigned int len, 2386 void *buf, unsigned int size) 2387 { 2388 struct buffer *out = &(struct buffer){ .port = 0 }; 2389 int ret; 2390 2391 if (buf) 2392 out = buf; 2393 else { 2394 ctx->objdata = 0; 2395 ctx->object = out; 2396 ctx->objmask = NULL; 2397 size = sizeof(*out); 2398 } 2399 ret = parse_int(ctx, token, str, len, out, size); 2400 if (ret >= 0) 2401 ctx->port = out->port; 2402 if (!buf) 2403 ctx->object = NULL; 2404 return ret; 2405 } 2406 2407 /** No completion. */ 2408 static int 2409 comp_none(struct context *ctx, const struct token *token, 2410 unsigned int ent, char *buf, unsigned int size) 2411 { 2412 (void)ctx; 2413 (void)token; 2414 (void)ent; 2415 (void)buf; 2416 (void)size; 2417 return 0; 2418 } 2419 2420 /** Complete boolean values. */ 2421 static int 2422 comp_boolean(struct context *ctx, const struct token *token, 2423 unsigned int ent, char *buf, unsigned int size) 2424 { 2425 unsigned int i; 2426 2427 (void)ctx; 2428 (void)token; 2429 for (i = 0; boolean_name[i]; ++i) 2430 if (buf && i == ent) 2431 return snprintf(buf, size, "%s", boolean_name[i]); 2432 if (buf) 2433 return -1; 2434 return i; 2435 } 2436 2437 /** Complete action names. */ 2438 static int 2439 comp_action(struct context *ctx, const struct token *token, 2440 unsigned int ent, char *buf, unsigned int size) 2441 { 2442 unsigned int i; 2443 2444 (void)ctx; 2445 (void)token; 2446 for (i = 0; next_action[i]; ++i) 2447 if (buf && i == ent) 2448 return snprintf(buf, size, "%s", 2449 token_list[next_action[i]].name); 2450 if (buf) 2451 return -1; 2452 return i; 2453 } 2454 2455 /** Complete available ports. */ 2456 static int 2457 comp_port(struct context *ctx, const struct token *token, 2458 unsigned int ent, char *buf, unsigned int size) 2459 { 2460 unsigned int i = 0; 2461 portid_t p; 2462 2463 (void)ctx; 2464 (void)token; 2465 RTE_ETH_FOREACH_DEV(p) { 2466 if (buf && i == ent) 2467 return snprintf(buf, size, "%u", p); 2468 ++i; 2469 } 2470 if (buf) 2471 return -1; 2472 return i; 2473 } 2474 2475 /** Complete available rule IDs. */ 2476 static int 2477 comp_rule_id(struct context *ctx, const struct token *token, 2478 unsigned int ent, char *buf, unsigned int size) 2479 { 2480 unsigned int i = 0; 2481 struct rte_port *port; 2482 struct port_flow *pf; 2483 2484 (void)token; 2485 if (port_id_is_invalid(ctx->port, DISABLED_WARN) || 2486 ctx->port == (uint16_t)RTE_PORT_ALL) 2487 return -1; 2488 port = &ports[ctx->port]; 2489 for (pf = port->flow_list; pf != NULL; pf = pf->next) { 2490 if (buf && i == ent) 2491 return snprintf(buf, size, "%u", pf->id); 2492 ++i; 2493 } 2494 if (buf) 2495 return -1; 2496 return i; 2497 } 2498 2499 /** Complete queue field for RSS action. */ 2500 static int 2501 comp_vc_action_rss_queue(struct context *ctx, const struct token *token, 2502 unsigned int ent, char *buf, unsigned int size) 2503 { 2504 static const char *const str[] = { "", "end", NULL }; 2505 unsigned int i; 2506 2507 (void)ctx; 2508 (void)token; 2509 for (i = 0; str[i] != NULL; ++i) 2510 if (buf && i == ent) 2511 return snprintf(buf, size, "%s", str[i]); 2512 if (buf) 2513 return -1; 2514 return i; 2515 } 2516 2517 /** Internal context. */ 2518 static struct context cmd_flow_context; 2519 2520 /** Global parser instance (cmdline API). */ 2521 cmdline_parse_inst_t cmd_flow; 2522 2523 /** Initialize context. */ 2524 static void 2525 cmd_flow_context_init(struct context *ctx) 2526 { 2527 /* A full memset() is not necessary. */ 2528 ctx->curr = ZERO; 2529 ctx->prev = ZERO; 2530 ctx->next_num = 0; 2531 ctx->args_num = 0; 2532 ctx->reparse = 0; 2533 ctx->eol = 0; 2534 ctx->last = 0; 2535 ctx->port = 0; 2536 ctx->objdata = 0; 2537 ctx->object = NULL; 2538 ctx->objmask = NULL; 2539 } 2540 2541 /** Parse a token (cmdline API). */ 2542 static int 2543 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result, 2544 unsigned int size) 2545 { 2546 struct context *ctx = &cmd_flow_context; 2547 const struct token *token; 2548 const enum index *list; 2549 int len; 2550 int i; 2551 2552 (void)hdr; 2553 /* Restart as requested. */ 2554 if (ctx->reparse) 2555 cmd_flow_context_init(ctx); 2556 token = &token_list[ctx->curr]; 2557 /* Check argument length. */ 2558 ctx->eol = 0; 2559 ctx->last = 1; 2560 for (len = 0; src[len]; ++len) 2561 if (src[len] == '#' || isspace(src[len])) 2562 break; 2563 if (!len) 2564 return -1; 2565 /* Last argument and EOL detection. */ 2566 for (i = len; src[i]; ++i) 2567 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n') 2568 break; 2569 else if (!isspace(src[i])) { 2570 ctx->last = 0; 2571 break; 2572 } 2573 for (; src[i]; ++i) 2574 if (src[i] == '\r' || src[i] == '\n') { 2575 ctx->eol = 1; 2576 break; 2577 } 2578 /* Initialize context if necessary. */ 2579 if (!ctx->next_num) { 2580 if (!token->next) 2581 return 0; 2582 ctx->next[ctx->next_num++] = token->next[0]; 2583 } 2584 /* Process argument through candidates. */ 2585 ctx->prev = ctx->curr; 2586 list = ctx->next[ctx->next_num - 1]; 2587 for (i = 0; list[i]; ++i) { 2588 const struct token *next = &token_list[list[i]]; 2589 int tmp; 2590 2591 ctx->curr = list[i]; 2592 if (next->call) 2593 tmp = next->call(ctx, next, src, len, result, size); 2594 else 2595 tmp = parse_default(ctx, next, src, len, result, size); 2596 if (tmp == -1 || tmp != len) 2597 continue; 2598 token = next; 2599 break; 2600 } 2601 if (!list[i]) 2602 return -1; 2603 --ctx->next_num; 2604 /* Push subsequent tokens if any. */ 2605 if (token->next) 2606 for (i = 0; token->next[i]; ++i) { 2607 if (ctx->next_num == RTE_DIM(ctx->next)) 2608 return -1; 2609 ctx->next[ctx->next_num++] = token->next[i]; 2610 } 2611 /* Push arguments if any. */ 2612 if (token->args) 2613 for (i = 0; token->args[i]; ++i) { 2614 if (ctx->args_num == RTE_DIM(ctx->args)) 2615 return -1; 2616 ctx->args[ctx->args_num++] = token->args[i]; 2617 } 2618 return len; 2619 } 2620 2621 /** Return number of completion entries (cmdline API). */ 2622 static int 2623 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr) 2624 { 2625 struct context *ctx = &cmd_flow_context; 2626 const struct token *token = &token_list[ctx->curr]; 2627 const enum index *list; 2628 int i; 2629 2630 (void)hdr; 2631 /* Tell cmd_flow_parse() that context must be reinitialized. */ 2632 ctx->reparse = 1; 2633 /* Count number of tokens in current list. */ 2634 if (ctx->next_num) 2635 list = ctx->next[ctx->next_num - 1]; 2636 else 2637 list = token->next[0]; 2638 for (i = 0; list[i]; ++i) 2639 ; 2640 if (!i) 2641 return 0; 2642 /* 2643 * If there is a single token, use its completion callback, otherwise 2644 * return the number of entries. 2645 */ 2646 token = &token_list[list[0]]; 2647 if (i == 1 && token->comp) { 2648 /* Save index for cmd_flow_get_help(). */ 2649 ctx->prev = list[0]; 2650 return token->comp(ctx, token, 0, NULL, 0); 2651 } 2652 return i; 2653 } 2654 2655 /** Return a completion entry (cmdline API). */ 2656 static int 2657 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index, 2658 char *dst, unsigned int size) 2659 { 2660 struct context *ctx = &cmd_flow_context; 2661 const struct token *token = &token_list[ctx->curr]; 2662 const enum index *list; 2663 int i; 2664 2665 (void)hdr; 2666 /* Tell cmd_flow_parse() that context must be reinitialized. */ 2667 ctx->reparse = 1; 2668 /* Count number of tokens in current list. */ 2669 if (ctx->next_num) 2670 list = ctx->next[ctx->next_num - 1]; 2671 else 2672 list = token->next[0]; 2673 for (i = 0; list[i]; ++i) 2674 ; 2675 if (!i) 2676 return -1; 2677 /* If there is a single token, use its completion callback. */ 2678 token = &token_list[list[0]]; 2679 if (i == 1 && token->comp) { 2680 /* Save index for cmd_flow_get_help(). */ 2681 ctx->prev = list[0]; 2682 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0; 2683 } 2684 /* Otherwise make sure the index is valid and use defaults. */ 2685 if (index >= i) 2686 return -1; 2687 token = &token_list[list[index]]; 2688 snprintf(dst, size, "%s", token->name); 2689 /* Save index for cmd_flow_get_help(). */ 2690 ctx->prev = list[index]; 2691 return 0; 2692 } 2693 2694 /** Populate help strings for current token (cmdline API). */ 2695 static int 2696 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size) 2697 { 2698 struct context *ctx = &cmd_flow_context; 2699 const struct token *token = &token_list[ctx->prev]; 2700 2701 (void)hdr; 2702 /* Tell cmd_flow_parse() that context must be reinitialized. */ 2703 ctx->reparse = 1; 2704 if (!size) 2705 return -1; 2706 /* Set token type and update global help with details. */ 2707 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN")); 2708 if (token->help) 2709 cmd_flow.help_str = token->help; 2710 else 2711 cmd_flow.help_str = token->name; 2712 return 0; 2713 } 2714 2715 /** Token definition template (cmdline API). */ 2716 static struct cmdline_token_hdr cmd_flow_token_hdr = { 2717 .ops = &(struct cmdline_token_ops){ 2718 .parse = cmd_flow_parse, 2719 .complete_get_nb = cmd_flow_complete_get_nb, 2720 .complete_get_elt = cmd_flow_complete_get_elt, 2721 .get_help = cmd_flow_get_help, 2722 }, 2723 .offset = 0, 2724 }; 2725 2726 /** Populate the next dynamic token. */ 2727 static void 2728 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr, 2729 cmdline_parse_token_hdr_t *(*hdrs)[]) 2730 { 2731 struct context *ctx = &cmd_flow_context; 2732 2733 /* Always reinitialize context before requesting the first token. */ 2734 if (!(hdr - *hdrs)) 2735 cmd_flow_context_init(ctx); 2736 /* Return NULL when no more tokens are expected. */ 2737 if (!ctx->next_num && ctx->curr) { 2738 *hdr = NULL; 2739 return; 2740 } 2741 /* Determine if command should end here. */ 2742 if (ctx->eol && ctx->last && ctx->next_num) { 2743 const enum index *list = ctx->next[ctx->next_num - 1]; 2744 int i; 2745 2746 for (i = 0; list[i]; ++i) { 2747 if (list[i] != END) 2748 continue; 2749 *hdr = NULL; 2750 return; 2751 } 2752 } 2753 *hdr = &cmd_flow_token_hdr; 2754 } 2755 2756 /** Dispatch parsed buffer to function calls. */ 2757 static void 2758 cmd_flow_parsed(const struct buffer *in) 2759 { 2760 switch (in->command) { 2761 case VALIDATE: 2762 port_flow_validate(in->port, &in->args.vc.attr, 2763 in->args.vc.pattern, in->args.vc.actions); 2764 break; 2765 case CREATE: 2766 port_flow_create(in->port, &in->args.vc.attr, 2767 in->args.vc.pattern, in->args.vc.actions); 2768 break; 2769 case DESTROY: 2770 port_flow_destroy(in->port, in->args.destroy.rule_n, 2771 in->args.destroy.rule); 2772 break; 2773 case FLUSH: 2774 port_flow_flush(in->port); 2775 break; 2776 case QUERY: 2777 port_flow_query(in->port, in->args.query.rule, 2778 in->args.query.action); 2779 break; 2780 case LIST: 2781 port_flow_list(in->port, in->args.list.group_n, 2782 in->args.list.group); 2783 break; 2784 default: 2785 break; 2786 } 2787 } 2788 2789 /** Token generator and output processing callback (cmdline API). */ 2790 static void 2791 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2) 2792 { 2793 if (cl == NULL) 2794 cmd_flow_tok(arg0, arg2); 2795 else 2796 cmd_flow_parsed(arg0); 2797 } 2798 2799 /** Global parser instance (cmdline API). */ 2800 cmdline_parse_inst_t cmd_flow = { 2801 .f = cmd_flow_cb, 2802 .data = NULL, /**< Unused. */ 2803 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */ 2804 .tokens = { 2805 NULL, 2806 }, /**< Tokens are returned by cmd_flow_tok(). */ 2807 }; 2808