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