1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2016 6WIND S.A. 3 * Copyright 2016 Mellanox Technologies, Ltd 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_eth_ctrl.h> 18 #include <rte_ethdev.h> 19 #include <rte_byteorder.h> 20 #include <cmdline_parse.h> 21 #include <cmdline_parse_etheraddr.h> 22 #include <rte_flow.h> 23 24 #include "testpmd.h" 25 26 /** Parser token indices. */ 27 enum index { 28 /* Special tokens. */ 29 ZERO = 0, 30 END, 31 32 /* Common tokens. */ 33 INTEGER, 34 UNSIGNED, 35 PREFIX, 36 BOOLEAN, 37 STRING, 38 MAC_ADDR, 39 IPV4_ADDR, 40 IPV6_ADDR, 41 RULE_ID, 42 PORT_ID, 43 GROUP_ID, 44 PRIORITY_LEVEL, 45 46 /* Top-level command. */ 47 FLOW, 48 49 /* Sub-level commands. */ 50 VALIDATE, 51 CREATE, 52 DESTROY, 53 FLUSH, 54 QUERY, 55 LIST, 56 ISOLATE, 57 58 /* Destroy arguments. */ 59 DESTROY_RULE, 60 61 /* Query arguments. */ 62 QUERY_ACTION, 63 64 /* List arguments. */ 65 LIST_GROUP, 66 67 /* Validate/create arguments. */ 68 GROUP, 69 PRIORITY, 70 INGRESS, 71 EGRESS, 72 TRANSFER, 73 74 /* Validate/create pattern. */ 75 PATTERN, 76 ITEM_PARAM_IS, 77 ITEM_PARAM_SPEC, 78 ITEM_PARAM_LAST, 79 ITEM_PARAM_MASK, 80 ITEM_PARAM_PREFIX, 81 ITEM_NEXT, 82 ITEM_END, 83 ITEM_VOID, 84 ITEM_INVERT, 85 ITEM_ANY, 86 ITEM_ANY_NUM, 87 ITEM_PF, 88 ITEM_VF, 89 ITEM_VF_ID, 90 ITEM_PHY_PORT, 91 ITEM_PHY_PORT_INDEX, 92 ITEM_PORT_ID, 93 ITEM_PORT_ID_ID, 94 ITEM_RAW, 95 ITEM_RAW_RELATIVE, 96 ITEM_RAW_SEARCH, 97 ITEM_RAW_OFFSET, 98 ITEM_RAW_LIMIT, 99 ITEM_RAW_PATTERN, 100 ITEM_ETH, 101 ITEM_ETH_DST, 102 ITEM_ETH_SRC, 103 ITEM_ETH_TYPE, 104 ITEM_VLAN, 105 ITEM_VLAN_TCI, 106 ITEM_VLAN_PCP, 107 ITEM_VLAN_DEI, 108 ITEM_VLAN_VID, 109 ITEM_VLAN_INNER_TYPE, 110 ITEM_IPV4, 111 ITEM_IPV4_TOS, 112 ITEM_IPV4_TTL, 113 ITEM_IPV4_PROTO, 114 ITEM_IPV4_SRC, 115 ITEM_IPV4_DST, 116 ITEM_IPV6, 117 ITEM_IPV6_TC, 118 ITEM_IPV6_FLOW, 119 ITEM_IPV6_PROTO, 120 ITEM_IPV6_HOP, 121 ITEM_IPV6_SRC, 122 ITEM_IPV6_DST, 123 ITEM_ICMP, 124 ITEM_ICMP_TYPE, 125 ITEM_ICMP_CODE, 126 ITEM_UDP, 127 ITEM_UDP_SRC, 128 ITEM_UDP_DST, 129 ITEM_TCP, 130 ITEM_TCP_SRC, 131 ITEM_TCP_DST, 132 ITEM_TCP_FLAGS, 133 ITEM_SCTP, 134 ITEM_SCTP_SRC, 135 ITEM_SCTP_DST, 136 ITEM_SCTP_TAG, 137 ITEM_SCTP_CKSUM, 138 ITEM_VXLAN, 139 ITEM_VXLAN_VNI, 140 ITEM_E_TAG, 141 ITEM_E_TAG_GRP_ECID_B, 142 ITEM_NVGRE, 143 ITEM_NVGRE_TNI, 144 ITEM_MPLS, 145 ITEM_MPLS_LABEL, 146 ITEM_GRE, 147 ITEM_GRE_PROTO, 148 ITEM_FUZZY, 149 ITEM_FUZZY_THRESH, 150 ITEM_GTP, 151 ITEM_GTP_TEID, 152 ITEM_GTPC, 153 ITEM_GTPU, 154 ITEM_GENEVE, 155 ITEM_GENEVE_VNI, 156 ITEM_GENEVE_PROTO, 157 ITEM_VXLAN_GPE, 158 ITEM_VXLAN_GPE_VNI, 159 ITEM_ARP_ETH_IPV4, 160 ITEM_ARP_ETH_IPV4_SHA, 161 ITEM_ARP_ETH_IPV4_SPA, 162 ITEM_ARP_ETH_IPV4_THA, 163 ITEM_ARP_ETH_IPV4_TPA, 164 ITEM_IPV6_EXT, 165 ITEM_IPV6_EXT_NEXT_HDR, 166 ITEM_ICMP6, 167 ITEM_ICMP6_TYPE, 168 ITEM_ICMP6_CODE, 169 ITEM_ICMP6_ND_NS, 170 ITEM_ICMP6_ND_NS_TARGET_ADDR, 171 ITEM_ICMP6_ND_NA, 172 ITEM_ICMP6_ND_NA_TARGET_ADDR, 173 ITEM_ICMP6_ND_OPT, 174 ITEM_ICMP6_ND_OPT_TYPE, 175 ITEM_ICMP6_ND_OPT_SLA_ETH, 176 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA, 177 ITEM_ICMP6_ND_OPT_TLA_ETH, 178 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA, 179 180 /* Validate/create actions. */ 181 ACTIONS, 182 ACTION_NEXT, 183 ACTION_END, 184 ACTION_VOID, 185 ACTION_PASSTHRU, 186 ACTION_JUMP, 187 ACTION_JUMP_GROUP, 188 ACTION_MARK, 189 ACTION_MARK_ID, 190 ACTION_FLAG, 191 ACTION_QUEUE, 192 ACTION_QUEUE_INDEX, 193 ACTION_DROP, 194 ACTION_COUNT, 195 ACTION_RSS, 196 ACTION_RSS_FUNC, 197 ACTION_RSS_LEVEL, 198 ACTION_RSS_FUNC_DEFAULT, 199 ACTION_RSS_FUNC_TOEPLITZ, 200 ACTION_RSS_FUNC_SIMPLE_XOR, 201 ACTION_RSS_TYPES, 202 ACTION_RSS_TYPE, 203 ACTION_RSS_KEY, 204 ACTION_RSS_KEY_LEN, 205 ACTION_RSS_QUEUES, 206 ACTION_RSS_QUEUE, 207 ACTION_PF, 208 ACTION_VF, 209 ACTION_VF_ORIGINAL, 210 ACTION_VF_ID, 211 ACTION_PHY_PORT, 212 ACTION_PHY_PORT_ORIGINAL, 213 ACTION_PHY_PORT_INDEX, 214 ACTION_PORT_ID, 215 ACTION_PORT_ID_ORIGINAL, 216 ACTION_PORT_ID_ID, 217 ACTION_METER, 218 ACTION_METER_ID, 219 ACTION_OF_SET_MPLS_TTL, 220 ACTION_OF_SET_MPLS_TTL_MPLS_TTL, 221 ACTION_OF_DEC_MPLS_TTL, 222 ACTION_OF_SET_NW_TTL, 223 ACTION_OF_SET_NW_TTL_NW_TTL, 224 ACTION_OF_DEC_NW_TTL, 225 ACTION_OF_COPY_TTL_OUT, 226 ACTION_OF_COPY_TTL_IN, 227 ACTION_OF_POP_VLAN, 228 ACTION_OF_PUSH_VLAN, 229 ACTION_OF_PUSH_VLAN_ETHERTYPE, 230 ACTION_OF_SET_VLAN_VID, 231 ACTION_OF_SET_VLAN_VID_VLAN_VID, 232 ACTION_OF_SET_VLAN_PCP, 233 ACTION_OF_SET_VLAN_PCP_VLAN_PCP, 234 ACTION_OF_POP_MPLS, 235 ACTION_OF_POP_MPLS_ETHERTYPE, 236 ACTION_OF_PUSH_MPLS, 237 ACTION_OF_PUSH_MPLS_ETHERTYPE, 238 }; 239 240 /** Maximum size for pattern in struct rte_flow_item_raw. */ 241 #define ITEM_RAW_PATTERN_SIZE 40 242 243 /** Storage size for struct rte_flow_item_raw including pattern. */ 244 #define ITEM_RAW_SIZE \ 245 (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE) 246 247 /** Maximum number of queue indices in struct rte_flow_action_rss. */ 248 #define ACTION_RSS_QUEUE_NUM 32 249 250 /** Storage for struct rte_flow_action_rss including external data. */ 251 struct action_rss_data { 252 struct rte_flow_action_rss conf; 253 uint8_t key[RSS_HASH_KEY_LENGTH]; 254 uint16_t queue[ACTION_RSS_QUEUE_NUM]; 255 }; 256 257 /** Maximum number of subsequent tokens and arguments on the stack. */ 258 #define CTX_STACK_SIZE 16 259 260 /** Parser context. */ 261 struct context { 262 /** Stack of subsequent token lists to process. */ 263 const enum index *next[CTX_STACK_SIZE]; 264 /** Arguments for stacked tokens. */ 265 const void *args[CTX_STACK_SIZE]; 266 enum index curr; /**< Current token index. */ 267 enum index prev; /**< Index of the last token seen. */ 268 int next_num; /**< Number of entries in next[]. */ 269 int args_num; /**< Number of entries in args[]. */ 270 uint32_t eol:1; /**< EOL has been detected. */ 271 uint32_t last:1; /**< No more arguments. */ 272 portid_t port; /**< Current port ID (for completions). */ 273 uint32_t objdata; /**< Object-specific data. */ 274 void *object; /**< Address of current object for relative offsets. */ 275 void *objmask; /**< Object a full mask must be written to. */ 276 }; 277 278 /** Token argument. */ 279 struct arg { 280 uint32_t hton:1; /**< Use network byte ordering. */ 281 uint32_t sign:1; /**< Value is signed. */ 282 uint32_t bounded:1; /**< Value is bounded. */ 283 uintmax_t min; /**< Minimum value if bounded. */ 284 uintmax_t max; /**< Maximum value if bounded. */ 285 uint32_t offset; /**< Relative offset from ctx->object. */ 286 uint32_t size; /**< Field size. */ 287 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */ 288 }; 289 290 /** Parser token definition. */ 291 struct token { 292 /** Type displayed during completion (defaults to "TOKEN"). */ 293 const char *type; 294 /** Help displayed during completion (defaults to token name). */ 295 const char *help; 296 /** Private data used by parser functions. */ 297 const void *priv; 298 /** 299 * Lists of subsequent tokens to push on the stack. Each call to the 300 * parser consumes the last entry of that stack. 301 */ 302 const enum index *const *next; 303 /** Arguments stack for subsequent tokens that need them. */ 304 const struct arg *const *args; 305 /** 306 * Token-processing callback, returns -1 in case of error, the 307 * length of the matched string otherwise. If NULL, attempts to 308 * match the token name. 309 * 310 * If buf is not NULL, the result should be stored in it according 311 * to context. An error is returned if not large enough. 312 */ 313 int (*call)(struct context *ctx, const struct token *token, 314 const char *str, unsigned int len, 315 void *buf, unsigned int size); 316 /** 317 * Callback that provides possible values for this token, used for 318 * completion. Returns -1 in case of error, the number of possible 319 * values otherwise. If NULL, the token name is used. 320 * 321 * If buf is not NULL, entry index ent is written to buf and the 322 * full length of the entry is returned (same behavior as 323 * snprintf()). 324 */ 325 int (*comp)(struct context *ctx, const struct token *token, 326 unsigned int ent, char *buf, unsigned int size); 327 /** Mandatory token name, no default value. */ 328 const char *name; 329 }; 330 331 /** Static initializer for the next field. */ 332 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, } 333 334 /** Static initializer for a NEXT() entry. */ 335 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, } 336 337 /** Static initializer for the args field. */ 338 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, } 339 340 /** Static initializer for ARGS() to target a field. */ 341 #define ARGS_ENTRY(s, f) \ 342 (&(const struct arg){ \ 343 .offset = offsetof(s, f), \ 344 .size = sizeof(((s *)0)->f), \ 345 }) 346 347 /** Static initializer for ARGS() to target a bit-field. */ 348 #define ARGS_ENTRY_BF(s, f, b) \ 349 (&(const struct arg){ \ 350 .size = sizeof(s), \ 351 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ 352 }) 353 354 /** Static initializer for ARGS() to target an arbitrary bit-mask. */ 355 #define ARGS_ENTRY_MASK(s, f, m) \ 356 (&(const struct arg){ \ 357 .offset = offsetof(s, f), \ 358 .size = sizeof(((s *)0)->f), \ 359 .mask = (const void *)(m), \ 360 }) 361 362 /** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */ 363 #define ARGS_ENTRY_MASK_HTON(s, f, m) \ 364 (&(const struct arg){ \ 365 .hton = 1, \ 366 .offset = offsetof(s, f), \ 367 .size = sizeof(((s *)0)->f), \ 368 .mask = (const void *)(m), \ 369 }) 370 371 /** Static initializer for ARGS() to target a pointer. */ 372 #define ARGS_ENTRY_PTR(s, f) \ 373 (&(const struct arg){ \ 374 .size = sizeof(*((s *)0)->f), \ 375 }) 376 377 /** Static initializer for ARGS() with arbitrary offset and size. */ 378 #define ARGS_ENTRY_ARB(o, s) \ 379 (&(const struct arg){ \ 380 .offset = (o), \ 381 .size = (s), \ 382 }) 383 384 /** Same as ARGS_ENTRY_ARB() with bounded values. */ 385 #define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \ 386 (&(const struct arg){ \ 387 .bounded = 1, \ 388 .min = (i), \ 389 .max = (a), \ 390 .offset = (o), \ 391 .size = (s), \ 392 }) 393 394 /** Same as ARGS_ENTRY() using network byte ordering. */ 395 #define ARGS_ENTRY_HTON(s, f) \ 396 (&(const struct arg){ \ 397 .hton = 1, \ 398 .offset = offsetof(s, f), \ 399 .size = sizeof(((s *)0)->f), \ 400 }) 401 402 /** Parser output buffer layout expected by cmd_flow_parsed(). */ 403 struct buffer { 404 enum index command; /**< Flow command. */ 405 portid_t port; /**< Affected port ID. */ 406 union { 407 struct { 408 struct rte_flow_attr attr; 409 struct rte_flow_item *pattern; 410 struct rte_flow_action *actions; 411 uint32_t pattern_n; 412 uint32_t actions_n; 413 uint8_t *data; 414 } vc; /**< Validate/create arguments. */ 415 struct { 416 uint32_t *rule; 417 uint32_t rule_n; 418 } destroy; /**< Destroy arguments. */ 419 struct { 420 uint32_t rule; 421 enum rte_flow_action_type action; 422 } query; /**< Query arguments. */ 423 struct { 424 uint32_t *group; 425 uint32_t group_n; 426 } list; /**< List arguments. */ 427 struct { 428 int set; 429 } isolate; /**< Isolated mode arguments. */ 430 } args; /**< Command arguments. */ 431 }; 432 433 /** Private data for pattern items. */ 434 struct parse_item_priv { 435 enum rte_flow_item_type type; /**< Item type. */ 436 uint32_t size; /**< Size of item specification structure. */ 437 }; 438 439 #define PRIV_ITEM(t, s) \ 440 (&(const struct parse_item_priv){ \ 441 .type = RTE_FLOW_ITEM_TYPE_ ## t, \ 442 .size = s, \ 443 }) 444 445 /** Private data for actions. */ 446 struct parse_action_priv { 447 enum rte_flow_action_type type; /**< Action type. */ 448 uint32_t size; /**< Size of action configuration structure. */ 449 }; 450 451 #define PRIV_ACTION(t, s) \ 452 (&(const struct parse_action_priv){ \ 453 .type = RTE_FLOW_ACTION_TYPE_ ## t, \ 454 .size = s, \ 455 }) 456 457 static const enum index next_vc_attr[] = { 458 GROUP, 459 PRIORITY, 460 INGRESS, 461 EGRESS, 462 TRANSFER, 463 PATTERN, 464 ZERO, 465 }; 466 467 static const enum index next_destroy_attr[] = { 468 DESTROY_RULE, 469 END, 470 ZERO, 471 }; 472 473 static const enum index next_list_attr[] = { 474 LIST_GROUP, 475 END, 476 ZERO, 477 }; 478 479 static const enum index item_param[] = { 480 ITEM_PARAM_IS, 481 ITEM_PARAM_SPEC, 482 ITEM_PARAM_LAST, 483 ITEM_PARAM_MASK, 484 ITEM_PARAM_PREFIX, 485 ZERO, 486 }; 487 488 static const enum index next_item[] = { 489 ITEM_END, 490 ITEM_VOID, 491 ITEM_INVERT, 492 ITEM_ANY, 493 ITEM_PF, 494 ITEM_VF, 495 ITEM_PHY_PORT, 496 ITEM_PORT_ID, 497 ITEM_RAW, 498 ITEM_ETH, 499 ITEM_VLAN, 500 ITEM_IPV4, 501 ITEM_IPV6, 502 ITEM_ICMP, 503 ITEM_UDP, 504 ITEM_TCP, 505 ITEM_SCTP, 506 ITEM_VXLAN, 507 ITEM_E_TAG, 508 ITEM_NVGRE, 509 ITEM_MPLS, 510 ITEM_GRE, 511 ITEM_FUZZY, 512 ITEM_GTP, 513 ITEM_GTPC, 514 ITEM_GTPU, 515 ITEM_GENEVE, 516 ITEM_VXLAN_GPE, 517 ITEM_ARP_ETH_IPV4, 518 ITEM_IPV6_EXT, 519 ITEM_ICMP6, 520 ITEM_ICMP6_ND_NS, 521 ITEM_ICMP6_ND_NA, 522 ITEM_ICMP6_ND_OPT, 523 ITEM_ICMP6_ND_OPT_SLA_ETH, 524 ITEM_ICMP6_ND_OPT_TLA_ETH, 525 ZERO, 526 }; 527 528 static const enum index item_fuzzy[] = { 529 ITEM_FUZZY_THRESH, 530 ITEM_NEXT, 531 ZERO, 532 }; 533 534 static const enum index item_any[] = { 535 ITEM_ANY_NUM, 536 ITEM_NEXT, 537 ZERO, 538 }; 539 540 static const enum index item_vf[] = { 541 ITEM_VF_ID, 542 ITEM_NEXT, 543 ZERO, 544 }; 545 546 static const enum index item_phy_port[] = { 547 ITEM_PHY_PORT_INDEX, 548 ITEM_NEXT, 549 ZERO, 550 }; 551 552 static const enum index item_port_id[] = { 553 ITEM_PORT_ID_ID, 554 ITEM_NEXT, 555 ZERO, 556 }; 557 558 static const enum index item_raw[] = { 559 ITEM_RAW_RELATIVE, 560 ITEM_RAW_SEARCH, 561 ITEM_RAW_OFFSET, 562 ITEM_RAW_LIMIT, 563 ITEM_RAW_PATTERN, 564 ITEM_NEXT, 565 ZERO, 566 }; 567 568 static const enum index item_eth[] = { 569 ITEM_ETH_DST, 570 ITEM_ETH_SRC, 571 ITEM_ETH_TYPE, 572 ITEM_NEXT, 573 ZERO, 574 }; 575 576 static const enum index item_vlan[] = { 577 ITEM_VLAN_TCI, 578 ITEM_VLAN_PCP, 579 ITEM_VLAN_DEI, 580 ITEM_VLAN_VID, 581 ITEM_VLAN_INNER_TYPE, 582 ITEM_NEXT, 583 ZERO, 584 }; 585 586 static const enum index item_ipv4[] = { 587 ITEM_IPV4_TOS, 588 ITEM_IPV4_TTL, 589 ITEM_IPV4_PROTO, 590 ITEM_IPV4_SRC, 591 ITEM_IPV4_DST, 592 ITEM_NEXT, 593 ZERO, 594 }; 595 596 static const enum index item_ipv6[] = { 597 ITEM_IPV6_TC, 598 ITEM_IPV6_FLOW, 599 ITEM_IPV6_PROTO, 600 ITEM_IPV6_HOP, 601 ITEM_IPV6_SRC, 602 ITEM_IPV6_DST, 603 ITEM_NEXT, 604 ZERO, 605 }; 606 607 static const enum index item_icmp[] = { 608 ITEM_ICMP_TYPE, 609 ITEM_ICMP_CODE, 610 ITEM_NEXT, 611 ZERO, 612 }; 613 614 static const enum index item_udp[] = { 615 ITEM_UDP_SRC, 616 ITEM_UDP_DST, 617 ITEM_NEXT, 618 ZERO, 619 }; 620 621 static const enum index item_tcp[] = { 622 ITEM_TCP_SRC, 623 ITEM_TCP_DST, 624 ITEM_TCP_FLAGS, 625 ITEM_NEXT, 626 ZERO, 627 }; 628 629 static const enum index item_sctp[] = { 630 ITEM_SCTP_SRC, 631 ITEM_SCTP_DST, 632 ITEM_SCTP_TAG, 633 ITEM_SCTP_CKSUM, 634 ITEM_NEXT, 635 ZERO, 636 }; 637 638 static const enum index item_vxlan[] = { 639 ITEM_VXLAN_VNI, 640 ITEM_NEXT, 641 ZERO, 642 }; 643 644 static const enum index item_e_tag[] = { 645 ITEM_E_TAG_GRP_ECID_B, 646 ITEM_NEXT, 647 ZERO, 648 }; 649 650 static const enum index item_nvgre[] = { 651 ITEM_NVGRE_TNI, 652 ITEM_NEXT, 653 ZERO, 654 }; 655 656 static const enum index item_mpls[] = { 657 ITEM_MPLS_LABEL, 658 ITEM_NEXT, 659 ZERO, 660 }; 661 662 static const enum index item_gre[] = { 663 ITEM_GRE_PROTO, 664 ITEM_NEXT, 665 ZERO, 666 }; 667 668 static const enum index item_gtp[] = { 669 ITEM_GTP_TEID, 670 ITEM_NEXT, 671 ZERO, 672 }; 673 674 static const enum index item_geneve[] = { 675 ITEM_GENEVE_VNI, 676 ITEM_GENEVE_PROTO, 677 ITEM_NEXT, 678 ZERO, 679 }; 680 681 static const enum index item_vxlan_gpe[] = { 682 ITEM_VXLAN_GPE_VNI, 683 ITEM_NEXT, 684 ZERO, 685 }; 686 687 static const enum index item_arp_eth_ipv4[] = { 688 ITEM_ARP_ETH_IPV4_SHA, 689 ITEM_ARP_ETH_IPV4_SPA, 690 ITEM_ARP_ETH_IPV4_THA, 691 ITEM_ARP_ETH_IPV4_TPA, 692 ITEM_NEXT, 693 ZERO, 694 }; 695 696 static const enum index item_ipv6_ext[] = { 697 ITEM_IPV6_EXT_NEXT_HDR, 698 ITEM_NEXT, 699 ZERO, 700 }; 701 702 static const enum index item_icmp6[] = { 703 ITEM_ICMP6_TYPE, 704 ITEM_ICMP6_CODE, 705 ITEM_NEXT, 706 ZERO, 707 }; 708 709 static const enum index item_icmp6_nd_ns[] = { 710 ITEM_ICMP6_ND_NS_TARGET_ADDR, 711 ITEM_NEXT, 712 ZERO, 713 }; 714 715 static const enum index item_icmp6_nd_na[] = { 716 ITEM_ICMP6_ND_NA_TARGET_ADDR, 717 ITEM_NEXT, 718 ZERO, 719 }; 720 721 static const enum index item_icmp6_nd_opt[] = { 722 ITEM_ICMP6_ND_OPT_TYPE, 723 ITEM_NEXT, 724 ZERO, 725 }; 726 727 static const enum index item_icmp6_nd_opt_sla_eth[] = { 728 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA, 729 ITEM_NEXT, 730 ZERO, 731 }; 732 733 static const enum index item_icmp6_nd_opt_tla_eth[] = { 734 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA, 735 ITEM_NEXT, 736 ZERO, 737 }; 738 739 static const enum index next_action[] = { 740 ACTION_END, 741 ACTION_VOID, 742 ACTION_PASSTHRU, 743 ACTION_JUMP, 744 ACTION_MARK, 745 ACTION_FLAG, 746 ACTION_QUEUE, 747 ACTION_DROP, 748 ACTION_COUNT, 749 ACTION_RSS, 750 ACTION_PF, 751 ACTION_VF, 752 ACTION_PHY_PORT, 753 ACTION_PORT_ID, 754 ACTION_METER, 755 ACTION_OF_SET_MPLS_TTL, 756 ACTION_OF_DEC_MPLS_TTL, 757 ACTION_OF_SET_NW_TTL, 758 ACTION_OF_DEC_NW_TTL, 759 ACTION_OF_COPY_TTL_OUT, 760 ACTION_OF_COPY_TTL_IN, 761 ACTION_OF_POP_VLAN, 762 ACTION_OF_PUSH_VLAN, 763 ACTION_OF_SET_VLAN_VID, 764 ACTION_OF_SET_VLAN_PCP, 765 ACTION_OF_POP_MPLS, 766 ACTION_OF_PUSH_MPLS, 767 ZERO, 768 }; 769 770 static const enum index action_mark[] = { 771 ACTION_MARK_ID, 772 ACTION_NEXT, 773 ZERO, 774 }; 775 776 static const enum index action_queue[] = { 777 ACTION_QUEUE_INDEX, 778 ACTION_NEXT, 779 ZERO, 780 }; 781 782 static const enum index action_rss[] = { 783 ACTION_RSS_FUNC, 784 ACTION_RSS_LEVEL, 785 ACTION_RSS_TYPES, 786 ACTION_RSS_KEY, 787 ACTION_RSS_KEY_LEN, 788 ACTION_RSS_QUEUES, 789 ACTION_NEXT, 790 ZERO, 791 }; 792 793 static const enum index action_vf[] = { 794 ACTION_VF_ORIGINAL, 795 ACTION_VF_ID, 796 ACTION_NEXT, 797 ZERO, 798 }; 799 800 static const enum index action_phy_port[] = { 801 ACTION_PHY_PORT_ORIGINAL, 802 ACTION_PHY_PORT_INDEX, 803 ACTION_NEXT, 804 ZERO, 805 }; 806 807 static const enum index action_port_id[] = { 808 ACTION_PORT_ID_ORIGINAL, 809 ACTION_PORT_ID_ID, 810 ACTION_NEXT, 811 ZERO, 812 }; 813 814 static const enum index action_meter[] = { 815 ACTION_METER_ID, 816 ACTION_NEXT, 817 ZERO, 818 }; 819 820 static const enum index action_of_set_mpls_ttl[] = { 821 ACTION_OF_SET_MPLS_TTL_MPLS_TTL, 822 ACTION_NEXT, 823 ZERO, 824 }; 825 826 static const enum index action_of_set_nw_ttl[] = { 827 ACTION_OF_SET_NW_TTL_NW_TTL, 828 ACTION_NEXT, 829 ZERO, 830 }; 831 832 static const enum index action_of_push_vlan[] = { 833 ACTION_OF_PUSH_VLAN_ETHERTYPE, 834 ACTION_NEXT, 835 ZERO, 836 }; 837 838 static const enum index action_of_set_vlan_vid[] = { 839 ACTION_OF_SET_VLAN_VID_VLAN_VID, 840 ACTION_NEXT, 841 ZERO, 842 }; 843 844 static const enum index action_of_set_vlan_pcp[] = { 845 ACTION_OF_SET_VLAN_PCP_VLAN_PCP, 846 ACTION_NEXT, 847 ZERO, 848 }; 849 850 static const enum index action_of_pop_mpls[] = { 851 ACTION_OF_POP_MPLS_ETHERTYPE, 852 ACTION_NEXT, 853 ZERO, 854 }; 855 856 static const enum index action_of_push_mpls[] = { 857 ACTION_OF_PUSH_MPLS_ETHERTYPE, 858 ACTION_NEXT, 859 ZERO, 860 }; 861 862 static const enum index action_jump[] = { 863 ACTION_JUMP_GROUP, 864 ACTION_NEXT, 865 ZERO, 866 }; 867 868 static int parse_init(struct context *, const struct token *, 869 const char *, unsigned int, 870 void *, unsigned int); 871 static int parse_vc(struct context *, const struct token *, 872 const char *, unsigned int, 873 void *, unsigned int); 874 static int parse_vc_spec(struct context *, const struct token *, 875 const char *, unsigned int, void *, unsigned int); 876 static int parse_vc_conf(struct context *, const struct token *, 877 const char *, unsigned int, void *, unsigned int); 878 static int parse_vc_action_rss(struct context *, const struct token *, 879 const char *, unsigned int, void *, 880 unsigned int); 881 static int parse_vc_action_rss_func(struct context *, const struct token *, 882 const char *, unsigned int, void *, 883 unsigned int); 884 static int parse_vc_action_rss_type(struct context *, const struct token *, 885 const char *, unsigned int, void *, 886 unsigned int); 887 static int parse_vc_action_rss_queue(struct context *, const struct token *, 888 const char *, unsigned int, void *, 889 unsigned int); 890 static int parse_destroy(struct context *, const struct token *, 891 const char *, unsigned int, 892 void *, unsigned int); 893 static int parse_flush(struct context *, const struct token *, 894 const char *, unsigned int, 895 void *, unsigned int); 896 static int parse_query(struct context *, const struct token *, 897 const char *, unsigned int, 898 void *, unsigned int); 899 static int parse_action(struct context *, const struct token *, 900 const char *, unsigned int, 901 void *, unsigned int); 902 static int parse_list(struct context *, const struct token *, 903 const char *, unsigned int, 904 void *, unsigned int); 905 static int parse_isolate(struct context *, const struct token *, 906 const char *, unsigned int, 907 void *, unsigned int); 908 static int parse_int(struct context *, const struct token *, 909 const char *, unsigned int, 910 void *, unsigned int); 911 static int parse_prefix(struct context *, const struct token *, 912 const char *, unsigned int, 913 void *, unsigned int); 914 static int parse_boolean(struct context *, const struct token *, 915 const char *, unsigned int, 916 void *, unsigned int); 917 static int parse_string(struct context *, const struct token *, 918 const char *, unsigned int, 919 void *, unsigned int); 920 static int parse_mac_addr(struct context *, const struct token *, 921 const char *, unsigned int, 922 void *, unsigned int); 923 static int parse_ipv4_addr(struct context *, const struct token *, 924 const char *, unsigned int, 925 void *, unsigned int); 926 static int parse_ipv6_addr(struct context *, const struct token *, 927 const char *, unsigned int, 928 void *, unsigned int); 929 static int parse_port(struct context *, const struct token *, 930 const char *, unsigned int, 931 void *, unsigned int); 932 static int comp_none(struct context *, const struct token *, 933 unsigned int, char *, unsigned int); 934 static int comp_boolean(struct context *, const struct token *, 935 unsigned int, char *, unsigned int); 936 static int comp_action(struct context *, const struct token *, 937 unsigned int, char *, unsigned int); 938 static int comp_port(struct context *, const struct token *, 939 unsigned int, char *, unsigned int); 940 static int comp_rule_id(struct context *, const struct token *, 941 unsigned int, char *, unsigned int); 942 static int comp_vc_action_rss_type(struct context *, const struct token *, 943 unsigned int, char *, unsigned int); 944 static int comp_vc_action_rss_queue(struct context *, const struct token *, 945 unsigned int, char *, unsigned int); 946 947 /** Token definitions. */ 948 static const struct token token_list[] = { 949 /* Special tokens. */ 950 [ZERO] = { 951 .name = "ZERO", 952 .help = "null entry, abused as the entry point", 953 .next = NEXT(NEXT_ENTRY(FLOW)), 954 }, 955 [END] = { 956 .name = "", 957 .type = "RETURN", 958 .help = "command may end here", 959 }, 960 /* Common tokens. */ 961 [INTEGER] = { 962 .name = "{int}", 963 .type = "INTEGER", 964 .help = "integer value", 965 .call = parse_int, 966 .comp = comp_none, 967 }, 968 [UNSIGNED] = { 969 .name = "{unsigned}", 970 .type = "UNSIGNED", 971 .help = "unsigned integer value", 972 .call = parse_int, 973 .comp = comp_none, 974 }, 975 [PREFIX] = { 976 .name = "{prefix}", 977 .type = "PREFIX", 978 .help = "prefix length for bit-mask", 979 .call = parse_prefix, 980 .comp = comp_none, 981 }, 982 [BOOLEAN] = { 983 .name = "{boolean}", 984 .type = "BOOLEAN", 985 .help = "any boolean value", 986 .call = parse_boolean, 987 .comp = comp_boolean, 988 }, 989 [STRING] = { 990 .name = "{string}", 991 .type = "STRING", 992 .help = "fixed string", 993 .call = parse_string, 994 .comp = comp_none, 995 }, 996 [MAC_ADDR] = { 997 .name = "{MAC address}", 998 .type = "MAC-48", 999 .help = "standard MAC address notation", 1000 .call = parse_mac_addr, 1001 .comp = comp_none, 1002 }, 1003 [IPV4_ADDR] = { 1004 .name = "{IPv4 address}", 1005 .type = "IPV4 ADDRESS", 1006 .help = "standard IPv4 address notation", 1007 .call = parse_ipv4_addr, 1008 .comp = comp_none, 1009 }, 1010 [IPV6_ADDR] = { 1011 .name = "{IPv6 address}", 1012 .type = "IPV6 ADDRESS", 1013 .help = "standard IPv6 address notation", 1014 .call = parse_ipv6_addr, 1015 .comp = comp_none, 1016 }, 1017 [RULE_ID] = { 1018 .name = "{rule id}", 1019 .type = "RULE ID", 1020 .help = "rule identifier", 1021 .call = parse_int, 1022 .comp = comp_rule_id, 1023 }, 1024 [PORT_ID] = { 1025 .name = "{port_id}", 1026 .type = "PORT ID", 1027 .help = "port identifier", 1028 .call = parse_port, 1029 .comp = comp_port, 1030 }, 1031 [GROUP_ID] = { 1032 .name = "{group_id}", 1033 .type = "GROUP ID", 1034 .help = "group identifier", 1035 .call = parse_int, 1036 .comp = comp_none, 1037 }, 1038 [PRIORITY_LEVEL] = { 1039 .name = "{level}", 1040 .type = "PRIORITY", 1041 .help = "priority level", 1042 .call = parse_int, 1043 .comp = comp_none, 1044 }, 1045 /* Top-level command. */ 1046 [FLOW] = { 1047 .name = "flow", 1048 .type = "{command} {port_id} [{arg} [...]]", 1049 .help = "manage ingress/egress flow rules", 1050 .next = NEXT(NEXT_ENTRY 1051 (VALIDATE, 1052 CREATE, 1053 DESTROY, 1054 FLUSH, 1055 LIST, 1056 QUERY, 1057 ISOLATE)), 1058 .call = parse_init, 1059 }, 1060 /* Sub-level commands. */ 1061 [VALIDATE] = { 1062 .name = "validate", 1063 .help = "check whether a flow rule can be created", 1064 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)), 1065 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 1066 .call = parse_vc, 1067 }, 1068 [CREATE] = { 1069 .name = "create", 1070 .help = "create a flow rule", 1071 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)), 1072 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 1073 .call = parse_vc, 1074 }, 1075 [DESTROY] = { 1076 .name = "destroy", 1077 .help = "destroy specific flow rules", 1078 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)), 1079 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 1080 .call = parse_destroy, 1081 }, 1082 [FLUSH] = { 1083 .name = "flush", 1084 .help = "destroy all flow rules", 1085 .next = NEXT(NEXT_ENTRY(PORT_ID)), 1086 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 1087 .call = parse_flush, 1088 }, 1089 [QUERY] = { 1090 .name = "query", 1091 .help = "query an existing flow rule", 1092 .next = NEXT(NEXT_ENTRY(QUERY_ACTION), 1093 NEXT_ENTRY(RULE_ID), 1094 NEXT_ENTRY(PORT_ID)), 1095 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action), 1096 ARGS_ENTRY(struct buffer, args.query.rule), 1097 ARGS_ENTRY(struct buffer, port)), 1098 .call = parse_query, 1099 }, 1100 [LIST] = { 1101 .name = "list", 1102 .help = "list existing flow rules", 1103 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)), 1104 .args = ARGS(ARGS_ENTRY(struct buffer, port)), 1105 .call = parse_list, 1106 }, 1107 [ISOLATE] = { 1108 .name = "isolate", 1109 .help = "restrict ingress traffic to the defined flow rules", 1110 .next = NEXT(NEXT_ENTRY(BOOLEAN), 1111 NEXT_ENTRY(PORT_ID)), 1112 .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set), 1113 ARGS_ENTRY(struct buffer, port)), 1114 .call = parse_isolate, 1115 }, 1116 /* Destroy arguments. */ 1117 [DESTROY_RULE] = { 1118 .name = "rule", 1119 .help = "specify a rule identifier", 1120 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)), 1121 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)), 1122 .call = parse_destroy, 1123 }, 1124 /* Query arguments. */ 1125 [QUERY_ACTION] = { 1126 .name = "{action}", 1127 .type = "ACTION", 1128 .help = "action to query, must be part of the rule", 1129 .call = parse_action, 1130 .comp = comp_action, 1131 }, 1132 /* List arguments. */ 1133 [LIST_GROUP] = { 1134 .name = "group", 1135 .help = "specify a group", 1136 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)), 1137 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)), 1138 .call = parse_list, 1139 }, 1140 /* Validate/create attributes. */ 1141 [GROUP] = { 1142 .name = "group", 1143 .help = "specify a group", 1144 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)), 1145 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)), 1146 .call = parse_vc, 1147 }, 1148 [PRIORITY] = { 1149 .name = "priority", 1150 .help = "specify a priority level", 1151 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)), 1152 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)), 1153 .call = parse_vc, 1154 }, 1155 [INGRESS] = { 1156 .name = "ingress", 1157 .help = "affect rule to ingress", 1158 .next = NEXT(next_vc_attr), 1159 .call = parse_vc, 1160 }, 1161 [EGRESS] = { 1162 .name = "egress", 1163 .help = "affect rule to egress", 1164 .next = NEXT(next_vc_attr), 1165 .call = parse_vc, 1166 }, 1167 [TRANSFER] = { 1168 .name = "transfer", 1169 .help = "apply rule directly to endpoints found in pattern", 1170 .next = NEXT(next_vc_attr), 1171 .call = parse_vc, 1172 }, 1173 /* Validate/create pattern. */ 1174 [PATTERN] = { 1175 .name = "pattern", 1176 .help = "submit a list of pattern items", 1177 .next = NEXT(next_item), 1178 .call = parse_vc, 1179 }, 1180 [ITEM_PARAM_IS] = { 1181 .name = "is", 1182 .help = "match value perfectly (with full bit-mask)", 1183 .call = parse_vc_spec, 1184 }, 1185 [ITEM_PARAM_SPEC] = { 1186 .name = "spec", 1187 .help = "match value according to configured bit-mask", 1188 .call = parse_vc_spec, 1189 }, 1190 [ITEM_PARAM_LAST] = { 1191 .name = "last", 1192 .help = "specify upper bound to establish a range", 1193 .call = parse_vc_spec, 1194 }, 1195 [ITEM_PARAM_MASK] = { 1196 .name = "mask", 1197 .help = "specify bit-mask with relevant bits set to one", 1198 .call = parse_vc_spec, 1199 }, 1200 [ITEM_PARAM_PREFIX] = { 1201 .name = "prefix", 1202 .help = "generate bit-mask from a prefix length", 1203 .call = parse_vc_spec, 1204 }, 1205 [ITEM_NEXT] = { 1206 .name = "/", 1207 .help = "specify next pattern item", 1208 .next = NEXT(next_item), 1209 }, 1210 [ITEM_END] = { 1211 .name = "end", 1212 .help = "end list of pattern items", 1213 .priv = PRIV_ITEM(END, 0), 1214 .next = NEXT(NEXT_ENTRY(ACTIONS)), 1215 .call = parse_vc, 1216 }, 1217 [ITEM_VOID] = { 1218 .name = "void", 1219 .help = "no-op pattern item", 1220 .priv = PRIV_ITEM(VOID, 0), 1221 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), 1222 .call = parse_vc, 1223 }, 1224 [ITEM_INVERT] = { 1225 .name = "invert", 1226 .help = "perform actions when pattern does not match", 1227 .priv = PRIV_ITEM(INVERT, 0), 1228 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), 1229 .call = parse_vc, 1230 }, 1231 [ITEM_ANY] = { 1232 .name = "any", 1233 .help = "match any protocol for the current layer", 1234 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)), 1235 .next = NEXT(item_any), 1236 .call = parse_vc, 1237 }, 1238 [ITEM_ANY_NUM] = { 1239 .name = "num", 1240 .help = "number of layers covered", 1241 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), 1242 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), 1243 }, 1244 [ITEM_PF] = { 1245 .name = "pf", 1246 .help = "match traffic from/to the physical function", 1247 .priv = PRIV_ITEM(PF, 0), 1248 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), 1249 .call = parse_vc, 1250 }, 1251 [ITEM_VF] = { 1252 .name = "vf", 1253 .help = "match traffic from/to a virtual function ID", 1254 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)), 1255 .next = NEXT(item_vf), 1256 .call = parse_vc, 1257 }, 1258 [ITEM_VF_ID] = { 1259 .name = "id", 1260 .help = "VF ID", 1261 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param), 1262 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)), 1263 }, 1264 [ITEM_PHY_PORT] = { 1265 .name = "phy_port", 1266 .help = "match traffic from/to a specific physical port", 1267 .priv = PRIV_ITEM(PHY_PORT, 1268 sizeof(struct rte_flow_item_phy_port)), 1269 .next = NEXT(item_phy_port), 1270 .call = parse_vc, 1271 }, 1272 [ITEM_PHY_PORT_INDEX] = { 1273 .name = "index", 1274 .help = "physical port index", 1275 .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param), 1276 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)), 1277 }, 1278 [ITEM_PORT_ID] = { 1279 .name = "port_id", 1280 .help = "match traffic from/to a given DPDK port ID", 1281 .priv = PRIV_ITEM(PORT_ID, 1282 sizeof(struct rte_flow_item_port_id)), 1283 .next = NEXT(item_port_id), 1284 .call = parse_vc, 1285 }, 1286 [ITEM_PORT_ID_ID] = { 1287 .name = "id", 1288 .help = "DPDK port ID", 1289 .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param), 1290 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)), 1291 }, 1292 [ITEM_RAW] = { 1293 .name = "raw", 1294 .help = "match an arbitrary byte string", 1295 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE), 1296 .next = NEXT(item_raw), 1297 .call = parse_vc, 1298 }, 1299 [ITEM_RAW_RELATIVE] = { 1300 .name = "relative", 1301 .help = "look for pattern after the previous item", 1302 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), 1303 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, 1304 relative, 1)), 1305 }, 1306 [ITEM_RAW_SEARCH] = { 1307 .name = "search", 1308 .help = "search pattern from offset (see also limit)", 1309 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), 1310 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, 1311 search, 1)), 1312 }, 1313 [ITEM_RAW_OFFSET] = { 1314 .name = "offset", 1315 .help = "absolute or relative offset for pattern", 1316 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param), 1317 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)), 1318 }, 1319 [ITEM_RAW_LIMIT] = { 1320 .name = "limit", 1321 .help = "search area limit for start of pattern", 1322 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param), 1323 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)), 1324 }, 1325 [ITEM_RAW_PATTERN] = { 1326 .name = "pattern", 1327 .help = "byte string to look for", 1328 .next = NEXT(item_raw, 1329 NEXT_ENTRY(STRING), 1330 NEXT_ENTRY(ITEM_PARAM_IS, 1331 ITEM_PARAM_SPEC, 1332 ITEM_PARAM_MASK)), 1333 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, pattern), 1334 ARGS_ENTRY(struct rte_flow_item_raw, length), 1335 ARGS_ENTRY_ARB(sizeof(struct rte_flow_item_raw), 1336 ITEM_RAW_PATTERN_SIZE)), 1337 }, 1338 [ITEM_ETH] = { 1339 .name = "eth", 1340 .help = "match Ethernet header", 1341 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)), 1342 .next = NEXT(item_eth), 1343 .call = parse_vc, 1344 }, 1345 [ITEM_ETH_DST] = { 1346 .name = "dst", 1347 .help = "destination MAC", 1348 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param), 1349 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)), 1350 }, 1351 [ITEM_ETH_SRC] = { 1352 .name = "src", 1353 .help = "source MAC", 1354 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param), 1355 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)), 1356 }, 1357 [ITEM_ETH_TYPE] = { 1358 .name = "type", 1359 .help = "EtherType", 1360 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param), 1361 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)), 1362 }, 1363 [ITEM_VLAN] = { 1364 .name = "vlan", 1365 .help = "match 802.1Q/ad VLAN tag", 1366 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)), 1367 .next = NEXT(item_vlan), 1368 .call = parse_vc, 1369 }, 1370 [ITEM_VLAN_TCI] = { 1371 .name = "tci", 1372 .help = "tag control information", 1373 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1374 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), 1375 }, 1376 [ITEM_VLAN_PCP] = { 1377 .name = "pcp", 1378 .help = "priority code point", 1379 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1380 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, 1381 tci, "\xe0\x00")), 1382 }, 1383 [ITEM_VLAN_DEI] = { 1384 .name = "dei", 1385 .help = "drop eligible indicator", 1386 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1387 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, 1388 tci, "\x10\x00")), 1389 }, 1390 [ITEM_VLAN_VID] = { 1391 .name = "vid", 1392 .help = "VLAN identifier", 1393 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1394 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, 1395 tci, "\x0f\xff")), 1396 }, 1397 [ITEM_VLAN_INNER_TYPE] = { 1398 .name = "inner_type", 1399 .help = "inner EtherType", 1400 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), 1401 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, 1402 inner_type)), 1403 }, 1404 [ITEM_IPV4] = { 1405 .name = "ipv4", 1406 .help = "match IPv4 header", 1407 .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), 1408 .next = NEXT(item_ipv4), 1409 .call = parse_vc, 1410 }, 1411 [ITEM_IPV4_TOS] = { 1412 .name = "tos", 1413 .help = "type of service", 1414 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), 1415 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1416 hdr.type_of_service)), 1417 }, 1418 [ITEM_IPV4_TTL] = { 1419 .name = "ttl", 1420 .help = "time to live", 1421 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), 1422 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1423 hdr.time_to_live)), 1424 }, 1425 [ITEM_IPV4_PROTO] = { 1426 .name = "proto", 1427 .help = "next protocol ID", 1428 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param), 1429 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1430 hdr.next_proto_id)), 1431 }, 1432 [ITEM_IPV4_SRC] = { 1433 .name = "src", 1434 .help = "source address", 1435 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), 1436 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1437 hdr.src_addr)), 1438 }, 1439 [ITEM_IPV4_DST] = { 1440 .name = "dst", 1441 .help = "destination address", 1442 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), 1443 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, 1444 hdr.dst_addr)), 1445 }, 1446 [ITEM_IPV6] = { 1447 .name = "ipv6", 1448 .help = "match IPv6 header", 1449 .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), 1450 .next = NEXT(item_ipv6), 1451 .call = parse_vc, 1452 }, 1453 [ITEM_IPV6_TC] = { 1454 .name = "tc", 1455 .help = "traffic class", 1456 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1457 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6, 1458 hdr.vtc_flow, 1459 "\x0f\xf0\x00\x00")), 1460 }, 1461 [ITEM_IPV6_FLOW] = { 1462 .name = "flow", 1463 .help = "flow label", 1464 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1465 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6, 1466 hdr.vtc_flow, 1467 "\x00\x0f\xff\xff")), 1468 }, 1469 [ITEM_IPV6_PROTO] = { 1470 .name = "proto", 1471 .help = "protocol (next header)", 1472 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1473 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1474 hdr.proto)), 1475 }, 1476 [ITEM_IPV6_HOP] = { 1477 .name = "hop", 1478 .help = "hop limit", 1479 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param), 1480 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1481 hdr.hop_limits)), 1482 }, 1483 [ITEM_IPV6_SRC] = { 1484 .name = "src", 1485 .help = "source address", 1486 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), 1487 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1488 hdr.src_addr)), 1489 }, 1490 [ITEM_IPV6_DST] = { 1491 .name = "dst", 1492 .help = "destination address", 1493 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), 1494 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, 1495 hdr.dst_addr)), 1496 }, 1497 [ITEM_ICMP] = { 1498 .name = "icmp", 1499 .help = "match ICMP header", 1500 .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), 1501 .next = NEXT(item_icmp), 1502 .call = parse_vc, 1503 }, 1504 [ITEM_ICMP_TYPE] = { 1505 .name = "type", 1506 .help = "ICMP packet type", 1507 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), 1508 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, 1509 hdr.icmp_type)), 1510 }, 1511 [ITEM_ICMP_CODE] = { 1512 .name = "code", 1513 .help = "ICMP packet code", 1514 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), 1515 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, 1516 hdr.icmp_code)), 1517 }, 1518 [ITEM_UDP] = { 1519 .name = "udp", 1520 .help = "match UDP header", 1521 .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)), 1522 .next = NEXT(item_udp), 1523 .call = parse_vc, 1524 }, 1525 [ITEM_UDP_SRC] = { 1526 .name = "src", 1527 .help = "UDP source port", 1528 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), 1529 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, 1530 hdr.src_port)), 1531 }, 1532 [ITEM_UDP_DST] = { 1533 .name = "dst", 1534 .help = "UDP destination port", 1535 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), 1536 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, 1537 hdr.dst_port)), 1538 }, 1539 [ITEM_TCP] = { 1540 .name = "tcp", 1541 .help = "match TCP header", 1542 .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), 1543 .next = NEXT(item_tcp), 1544 .call = parse_vc, 1545 }, 1546 [ITEM_TCP_SRC] = { 1547 .name = "src", 1548 .help = "TCP source port", 1549 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), 1550 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, 1551 hdr.src_port)), 1552 }, 1553 [ITEM_TCP_DST] = { 1554 .name = "dst", 1555 .help = "TCP destination port", 1556 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), 1557 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, 1558 hdr.dst_port)), 1559 }, 1560 [ITEM_TCP_FLAGS] = { 1561 .name = "flags", 1562 .help = "TCP flags", 1563 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), 1564 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, 1565 hdr.tcp_flags)), 1566 }, 1567 [ITEM_SCTP] = { 1568 .name = "sctp", 1569 .help = "match SCTP header", 1570 .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), 1571 .next = NEXT(item_sctp), 1572 .call = parse_vc, 1573 }, 1574 [ITEM_SCTP_SRC] = { 1575 .name = "src", 1576 .help = "SCTP source port", 1577 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1578 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1579 hdr.src_port)), 1580 }, 1581 [ITEM_SCTP_DST] = { 1582 .name = "dst", 1583 .help = "SCTP destination port", 1584 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1585 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1586 hdr.dst_port)), 1587 }, 1588 [ITEM_SCTP_TAG] = { 1589 .name = "tag", 1590 .help = "validation tag", 1591 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1592 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1593 hdr.tag)), 1594 }, 1595 [ITEM_SCTP_CKSUM] = { 1596 .name = "cksum", 1597 .help = "checksum", 1598 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), 1599 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, 1600 hdr.cksum)), 1601 }, 1602 [ITEM_VXLAN] = { 1603 .name = "vxlan", 1604 .help = "match VXLAN header", 1605 .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), 1606 .next = NEXT(item_vxlan), 1607 .call = parse_vc, 1608 }, 1609 [ITEM_VXLAN_VNI] = { 1610 .name = "vni", 1611 .help = "VXLAN identifier", 1612 .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param), 1613 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)), 1614 }, 1615 [ITEM_E_TAG] = { 1616 .name = "e_tag", 1617 .help = "match E-Tag header", 1618 .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)), 1619 .next = NEXT(item_e_tag), 1620 .call = parse_vc, 1621 }, 1622 [ITEM_E_TAG_GRP_ECID_B] = { 1623 .name = "grp_ecid_b", 1624 .help = "GRP and E-CID base", 1625 .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param), 1626 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag, 1627 rsvd_grp_ecid_b, 1628 "\x3f\xff")), 1629 }, 1630 [ITEM_NVGRE] = { 1631 .name = "nvgre", 1632 .help = "match NVGRE header", 1633 .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)), 1634 .next = NEXT(item_nvgre), 1635 .call = parse_vc, 1636 }, 1637 [ITEM_NVGRE_TNI] = { 1638 .name = "tni", 1639 .help = "virtual subnet ID", 1640 .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param), 1641 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)), 1642 }, 1643 [ITEM_MPLS] = { 1644 .name = "mpls", 1645 .help = "match MPLS header", 1646 .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)), 1647 .next = NEXT(item_mpls), 1648 .call = parse_vc, 1649 }, 1650 [ITEM_MPLS_LABEL] = { 1651 .name = "label", 1652 .help = "MPLS label", 1653 .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param), 1654 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls, 1655 label_tc_s, 1656 "\xff\xff\xf0")), 1657 }, 1658 [ITEM_GRE] = { 1659 .name = "gre", 1660 .help = "match GRE header", 1661 .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)), 1662 .next = NEXT(item_gre), 1663 .call = parse_vc, 1664 }, 1665 [ITEM_GRE_PROTO] = { 1666 .name = "protocol", 1667 .help = "GRE protocol type", 1668 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param), 1669 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre, 1670 protocol)), 1671 }, 1672 [ITEM_FUZZY] = { 1673 .name = "fuzzy", 1674 .help = "fuzzy pattern match, expect faster than default", 1675 .priv = PRIV_ITEM(FUZZY, 1676 sizeof(struct rte_flow_item_fuzzy)), 1677 .next = NEXT(item_fuzzy), 1678 .call = parse_vc, 1679 }, 1680 [ITEM_FUZZY_THRESH] = { 1681 .name = "thresh", 1682 .help = "match accuracy threshold", 1683 .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param), 1684 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy, 1685 thresh)), 1686 }, 1687 [ITEM_GTP] = { 1688 .name = "gtp", 1689 .help = "match GTP header", 1690 .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)), 1691 .next = NEXT(item_gtp), 1692 .call = parse_vc, 1693 }, 1694 [ITEM_GTP_TEID] = { 1695 .name = "teid", 1696 .help = "tunnel endpoint identifier", 1697 .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param), 1698 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)), 1699 }, 1700 [ITEM_GTPC] = { 1701 .name = "gtpc", 1702 .help = "match GTP header", 1703 .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)), 1704 .next = NEXT(item_gtp), 1705 .call = parse_vc, 1706 }, 1707 [ITEM_GTPU] = { 1708 .name = "gtpu", 1709 .help = "match GTP header", 1710 .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)), 1711 .next = NEXT(item_gtp), 1712 .call = parse_vc, 1713 }, 1714 [ITEM_GENEVE] = { 1715 .name = "geneve", 1716 .help = "match GENEVE header", 1717 .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)), 1718 .next = NEXT(item_geneve), 1719 .call = parse_vc, 1720 }, 1721 [ITEM_GENEVE_VNI] = { 1722 .name = "vni", 1723 .help = "virtual network identifier", 1724 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param), 1725 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)), 1726 }, 1727 [ITEM_GENEVE_PROTO] = { 1728 .name = "protocol", 1729 .help = "GENEVE protocol type", 1730 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param), 1731 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, 1732 protocol)), 1733 }, 1734 [ITEM_VXLAN_GPE] = { 1735 .name = "vxlan-gpe", 1736 .help = "match VXLAN-GPE header", 1737 .priv = PRIV_ITEM(VXLAN_GPE, 1738 sizeof(struct rte_flow_item_vxlan_gpe)), 1739 .next = NEXT(item_vxlan_gpe), 1740 .call = parse_vc, 1741 }, 1742 [ITEM_VXLAN_GPE_VNI] = { 1743 .name = "vni", 1744 .help = "VXLAN-GPE identifier", 1745 .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param), 1746 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe, 1747 vni)), 1748 }, 1749 [ITEM_ARP_ETH_IPV4] = { 1750 .name = "arp_eth_ipv4", 1751 .help = "match ARP header for Ethernet/IPv4", 1752 .priv = PRIV_ITEM(ARP_ETH_IPV4, 1753 sizeof(struct rte_flow_item_arp_eth_ipv4)), 1754 .next = NEXT(item_arp_eth_ipv4), 1755 .call = parse_vc, 1756 }, 1757 [ITEM_ARP_ETH_IPV4_SHA] = { 1758 .name = "sha", 1759 .help = "sender hardware address", 1760 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR), 1761 item_param), 1762 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4, 1763 sha)), 1764 }, 1765 [ITEM_ARP_ETH_IPV4_SPA] = { 1766 .name = "spa", 1767 .help = "sender IPv4 address", 1768 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR), 1769 item_param), 1770 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4, 1771 spa)), 1772 }, 1773 [ITEM_ARP_ETH_IPV4_THA] = { 1774 .name = "tha", 1775 .help = "target hardware address", 1776 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR), 1777 item_param), 1778 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4, 1779 tha)), 1780 }, 1781 [ITEM_ARP_ETH_IPV4_TPA] = { 1782 .name = "tpa", 1783 .help = "target IPv4 address", 1784 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR), 1785 item_param), 1786 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4, 1787 tpa)), 1788 }, 1789 [ITEM_IPV6_EXT] = { 1790 .name = "ipv6_ext", 1791 .help = "match presence of any IPv6 extension header", 1792 .priv = PRIV_ITEM(IPV6_EXT, 1793 sizeof(struct rte_flow_item_ipv6_ext)), 1794 .next = NEXT(item_ipv6_ext), 1795 .call = parse_vc, 1796 }, 1797 [ITEM_IPV6_EXT_NEXT_HDR] = { 1798 .name = "next_hdr", 1799 .help = "next header", 1800 .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param), 1801 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext, 1802 next_hdr)), 1803 }, 1804 [ITEM_ICMP6] = { 1805 .name = "icmp6", 1806 .help = "match any ICMPv6 header", 1807 .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)), 1808 .next = NEXT(item_icmp6), 1809 .call = parse_vc, 1810 }, 1811 [ITEM_ICMP6_TYPE] = { 1812 .name = "type", 1813 .help = "ICMPv6 type", 1814 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param), 1815 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6, 1816 type)), 1817 }, 1818 [ITEM_ICMP6_CODE] = { 1819 .name = "code", 1820 .help = "ICMPv6 code", 1821 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param), 1822 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6, 1823 code)), 1824 }, 1825 [ITEM_ICMP6_ND_NS] = { 1826 .name = "icmp6_nd_ns", 1827 .help = "match ICMPv6 neighbor discovery solicitation", 1828 .priv = PRIV_ITEM(ICMP6_ND_NS, 1829 sizeof(struct rte_flow_item_icmp6_nd_ns)), 1830 .next = NEXT(item_icmp6_nd_ns), 1831 .call = parse_vc, 1832 }, 1833 [ITEM_ICMP6_ND_NS_TARGET_ADDR] = { 1834 .name = "target_addr", 1835 .help = "target address", 1836 .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR), 1837 item_param), 1838 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns, 1839 target_addr)), 1840 }, 1841 [ITEM_ICMP6_ND_NA] = { 1842 .name = "icmp6_nd_na", 1843 .help = "match ICMPv6 neighbor discovery advertisement", 1844 .priv = PRIV_ITEM(ICMP6_ND_NA, 1845 sizeof(struct rte_flow_item_icmp6_nd_na)), 1846 .next = NEXT(item_icmp6_nd_na), 1847 .call = parse_vc, 1848 }, 1849 [ITEM_ICMP6_ND_NA_TARGET_ADDR] = { 1850 .name = "target_addr", 1851 .help = "target address", 1852 .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR), 1853 item_param), 1854 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na, 1855 target_addr)), 1856 }, 1857 [ITEM_ICMP6_ND_OPT] = { 1858 .name = "icmp6_nd_opt", 1859 .help = "match presence of any ICMPv6 neighbor discovery" 1860 " option", 1861 .priv = PRIV_ITEM(ICMP6_ND_OPT, 1862 sizeof(struct rte_flow_item_icmp6_nd_opt)), 1863 .next = NEXT(item_icmp6_nd_opt), 1864 .call = parse_vc, 1865 }, 1866 [ITEM_ICMP6_ND_OPT_TYPE] = { 1867 .name = "type", 1868 .help = "ND option type", 1869 .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED), 1870 item_param), 1871 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt, 1872 type)), 1873 }, 1874 [ITEM_ICMP6_ND_OPT_SLA_ETH] = { 1875 .name = "icmp6_nd_opt_sla_eth", 1876 .help = "match ICMPv6 neighbor discovery source Ethernet" 1877 " link-layer address option", 1878 .priv = PRIV_ITEM 1879 (ICMP6_ND_OPT_SLA_ETH, 1880 sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)), 1881 .next = NEXT(item_icmp6_nd_opt_sla_eth), 1882 .call = parse_vc, 1883 }, 1884 [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = { 1885 .name = "sla", 1886 .help = "source Ethernet LLA", 1887 .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR), 1888 item_param), 1889 .args = ARGS(ARGS_ENTRY_HTON 1890 (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)), 1891 }, 1892 [ITEM_ICMP6_ND_OPT_TLA_ETH] = { 1893 .name = "icmp6_nd_opt_tla_eth", 1894 .help = "match ICMPv6 neighbor discovery target Ethernet" 1895 " link-layer address option", 1896 .priv = PRIV_ITEM 1897 (ICMP6_ND_OPT_TLA_ETH, 1898 sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)), 1899 .next = NEXT(item_icmp6_nd_opt_tla_eth), 1900 .call = parse_vc, 1901 }, 1902 [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = { 1903 .name = "tla", 1904 .help = "target Ethernet LLA", 1905 .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR), 1906 item_param), 1907 .args = ARGS(ARGS_ENTRY_HTON 1908 (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)), 1909 }, 1910 1911 /* Validate/create actions. */ 1912 [ACTIONS] = { 1913 .name = "actions", 1914 .help = "submit a list of associated actions", 1915 .next = NEXT(next_action), 1916 .call = parse_vc, 1917 }, 1918 [ACTION_NEXT] = { 1919 .name = "/", 1920 .help = "specify next action", 1921 .next = NEXT(next_action), 1922 }, 1923 [ACTION_END] = { 1924 .name = "end", 1925 .help = "end list of actions", 1926 .priv = PRIV_ACTION(END, 0), 1927 .call = parse_vc, 1928 }, 1929 [ACTION_VOID] = { 1930 .name = "void", 1931 .help = "no-op action", 1932 .priv = PRIV_ACTION(VOID, 0), 1933 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1934 .call = parse_vc, 1935 }, 1936 [ACTION_PASSTHRU] = { 1937 .name = "passthru", 1938 .help = "let subsequent rule process matched packets", 1939 .priv = PRIV_ACTION(PASSTHRU, 0), 1940 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1941 .call = parse_vc, 1942 }, 1943 [ACTION_JUMP] = { 1944 .name = "jump", 1945 .help = "redirect traffic to a given group", 1946 .priv = PRIV_ACTION(JUMP, sizeof(struct rte_flow_action_jump)), 1947 .next = NEXT(action_jump), 1948 .call = parse_vc, 1949 }, 1950 [ACTION_JUMP_GROUP] = { 1951 .name = "group", 1952 .help = "group to redirect traffic to", 1953 .next = NEXT(action_jump, NEXT_ENTRY(UNSIGNED)), 1954 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_jump, group)), 1955 .call = parse_vc_conf, 1956 }, 1957 [ACTION_MARK] = { 1958 .name = "mark", 1959 .help = "attach 32 bit value to packets", 1960 .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)), 1961 .next = NEXT(action_mark), 1962 .call = parse_vc, 1963 }, 1964 [ACTION_MARK_ID] = { 1965 .name = "id", 1966 .help = "32 bit value to return with packets", 1967 .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)), 1968 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)), 1969 .call = parse_vc_conf, 1970 }, 1971 [ACTION_FLAG] = { 1972 .name = "flag", 1973 .help = "flag packets", 1974 .priv = PRIV_ACTION(FLAG, 0), 1975 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1976 .call = parse_vc, 1977 }, 1978 [ACTION_QUEUE] = { 1979 .name = "queue", 1980 .help = "assign packets to a given queue index", 1981 .priv = PRIV_ACTION(QUEUE, 1982 sizeof(struct rte_flow_action_queue)), 1983 .next = NEXT(action_queue), 1984 .call = parse_vc, 1985 }, 1986 [ACTION_QUEUE_INDEX] = { 1987 .name = "index", 1988 .help = "queue index to use", 1989 .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)), 1990 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)), 1991 .call = parse_vc_conf, 1992 }, 1993 [ACTION_DROP] = { 1994 .name = "drop", 1995 .help = "drop packets (note: passthru has priority)", 1996 .priv = PRIV_ACTION(DROP, 0), 1997 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 1998 .call = parse_vc, 1999 }, 2000 [ACTION_COUNT] = { 2001 .name = "count", 2002 .help = "enable counters for this rule", 2003 .priv = PRIV_ACTION(COUNT, 0), 2004 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2005 .call = parse_vc, 2006 }, 2007 [ACTION_RSS] = { 2008 .name = "rss", 2009 .help = "spread packets among several queues", 2010 .priv = PRIV_ACTION(RSS, sizeof(struct action_rss_data)), 2011 .next = NEXT(action_rss), 2012 .call = parse_vc_action_rss, 2013 }, 2014 [ACTION_RSS_FUNC] = { 2015 .name = "func", 2016 .help = "RSS hash function to apply", 2017 .next = NEXT(action_rss, 2018 NEXT_ENTRY(ACTION_RSS_FUNC_DEFAULT, 2019 ACTION_RSS_FUNC_TOEPLITZ, 2020 ACTION_RSS_FUNC_SIMPLE_XOR)), 2021 }, 2022 [ACTION_RSS_FUNC_DEFAULT] = { 2023 .name = "default", 2024 .help = "default hash function", 2025 .call = parse_vc_action_rss_func, 2026 }, 2027 [ACTION_RSS_FUNC_TOEPLITZ] = { 2028 .name = "toeplitz", 2029 .help = "Toeplitz hash function", 2030 .call = parse_vc_action_rss_func, 2031 }, 2032 [ACTION_RSS_FUNC_SIMPLE_XOR] = { 2033 .name = "simple_xor", 2034 .help = "simple XOR hash function", 2035 .call = parse_vc_action_rss_func, 2036 }, 2037 [ACTION_RSS_LEVEL] = { 2038 .name = "level", 2039 .help = "encapsulation level for \"types\"", 2040 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)), 2041 .args = ARGS(ARGS_ENTRY_ARB 2042 (offsetof(struct action_rss_data, conf) + 2043 offsetof(struct rte_flow_action_rss, level), 2044 sizeof(((struct rte_flow_action_rss *)0)-> 2045 level))), 2046 }, 2047 [ACTION_RSS_TYPES] = { 2048 .name = "types", 2049 .help = "specific RSS hash types", 2050 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)), 2051 }, 2052 [ACTION_RSS_TYPE] = { 2053 .name = "{type}", 2054 .help = "RSS hash type", 2055 .call = parse_vc_action_rss_type, 2056 .comp = comp_vc_action_rss_type, 2057 }, 2058 [ACTION_RSS_KEY] = { 2059 .name = "key", 2060 .help = "RSS hash key", 2061 .next = NEXT(action_rss, NEXT_ENTRY(STRING)), 2062 .args = ARGS(ARGS_ENTRY_ARB(0, 0), 2063 ARGS_ENTRY_ARB 2064 (offsetof(struct action_rss_data, conf) + 2065 offsetof(struct rte_flow_action_rss, key_len), 2066 sizeof(((struct rte_flow_action_rss *)0)-> 2067 key_len)), 2068 ARGS_ENTRY(struct action_rss_data, key)), 2069 }, 2070 [ACTION_RSS_KEY_LEN] = { 2071 .name = "key_len", 2072 .help = "RSS hash key length in bytes", 2073 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)), 2074 .args = ARGS(ARGS_ENTRY_ARB_BOUNDED 2075 (offsetof(struct action_rss_data, conf) + 2076 offsetof(struct rte_flow_action_rss, key_len), 2077 sizeof(((struct rte_flow_action_rss *)0)-> 2078 key_len), 2079 0, 2080 RSS_HASH_KEY_LENGTH)), 2081 }, 2082 [ACTION_RSS_QUEUES] = { 2083 .name = "queues", 2084 .help = "queue indices to use", 2085 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)), 2086 .call = parse_vc_conf, 2087 }, 2088 [ACTION_RSS_QUEUE] = { 2089 .name = "{queue}", 2090 .help = "queue index", 2091 .call = parse_vc_action_rss_queue, 2092 .comp = comp_vc_action_rss_queue, 2093 }, 2094 [ACTION_PF] = { 2095 .name = "pf", 2096 .help = "direct traffic to physical function", 2097 .priv = PRIV_ACTION(PF, 0), 2098 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2099 .call = parse_vc, 2100 }, 2101 [ACTION_VF] = { 2102 .name = "vf", 2103 .help = "direct traffic to a virtual function ID", 2104 .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)), 2105 .next = NEXT(action_vf), 2106 .call = parse_vc, 2107 }, 2108 [ACTION_VF_ORIGINAL] = { 2109 .name = "original", 2110 .help = "use original VF ID if possible", 2111 .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)), 2112 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf, 2113 original, 1)), 2114 .call = parse_vc_conf, 2115 }, 2116 [ACTION_VF_ID] = { 2117 .name = "id", 2118 .help = "VF ID", 2119 .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)), 2120 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)), 2121 .call = parse_vc_conf, 2122 }, 2123 [ACTION_PHY_PORT] = { 2124 .name = "phy_port", 2125 .help = "direct packets to physical port index", 2126 .priv = PRIV_ACTION(PHY_PORT, 2127 sizeof(struct rte_flow_action_phy_port)), 2128 .next = NEXT(action_phy_port), 2129 .call = parse_vc, 2130 }, 2131 [ACTION_PHY_PORT_ORIGINAL] = { 2132 .name = "original", 2133 .help = "use original port index if possible", 2134 .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)), 2135 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port, 2136 original, 1)), 2137 .call = parse_vc_conf, 2138 }, 2139 [ACTION_PHY_PORT_INDEX] = { 2140 .name = "index", 2141 .help = "physical port index", 2142 .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)), 2143 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port, 2144 index)), 2145 .call = parse_vc_conf, 2146 }, 2147 [ACTION_PORT_ID] = { 2148 .name = "port_id", 2149 .help = "direct matching traffic to a given DPDK port ID", 2150 .priv = PRIV_ACTION(PORT_ID, 2151 sizeof(struct rte_flow_action_port_id)), 2152 .next = NEXT(action_port_id), 2153 .call = parse_vc, 2154 }, 2155 [ACTION_PORT_ID_ORIGINAL] = { 2156 .name = "original", 2157 .help = "use original DPDK port ID if possible", 2158 .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)), 2159 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id, 2160 original, 1)), 2161 .call = parse_vc_conf, 2162 }, 2163 [ACTION_PORT_ID_ID] = { 2164 .name = "id", 2165 .help = "DPDK port ID", 2166 .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)), 2167 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)), 2168 .call = parse_vc_conf, 2169 }, 2170 [ACTION_METER] = { 2171 .name = "meter", 2172 .help = "meter the directed packets at given id", 2173 .priv = PRIV_ACTION(METER, 2174 sizeof(struct rte_flow_action_meter)), 2175 .next = NEXT(action_meter), 2176 .call = parse_vc, 2177 }, 2178 [ACTION_METER_ID] = { 2179 .name = "mtr_id", 2180 .help = "meter id to use", 2181 .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)), 2182 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)), 2183 .call = parse_vc_conf, 2184 }, 2185 [ACTION_OF_SET_MPLS_TTL] = { 2186 .name = "of_set_mpls_ttl", 2187 .help = "OpenFlow's OFPAT_SET_MPLS_TTL", 2188 .priv = PRIV_ACTION 2189 (OF_SET_MPLS_TTL, 2190 sizeof(struct rte_flow_action_of_set_mpls_ttl)), 2191 .next = NEXT(action_of_set_mpls_ttl), 2192 .call = parse_vc, 2193 }, 2194 [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = { 2195 .name = "mpls_ttl", 2196 .help = "MPLS TTL", 2197 .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)), 2198 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl, 2199 mpls_ttl)), 2200 .call = parse_vc_conf, 2201 }, 2202 [ACTION_OF_DEC_MPLS_TTL] = { 2203 .name = "of_dec_mpls_ttl", 2204 .help = "OpenFlow's OFPAT_DEC_MPLS_TTL", 2205 .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0), 2206 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2207 .call = parse_vc, 2208 }, 2209 [ACTION_OF_SET_NW_TTL] = { 2210 .name = "of_set_nw_ttl", 2211 .help = "OpenFlow's OFPAT_SET_NW_TTL", 2212 .priv = PRIV_ACTION 2213 (OF_SET_NW_TTL, 2214 sizeof(struct rte_flow_action_of_set_nw_ttl)), 2215 .next = NEXT(action_of_set_nw_ttl), 2216 .call = parse_vc, 2217 }, 2218 [ACTION_OF_SET_NW_TTL_NW_TTL] = { 2219 .name = "nw_ttl", 2220 .help = "IP TTL", 2221 .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)), 2222 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl, 2223 nw_ttl)), 2224 .call = parse_vc_conf, 2225 }, 2226 [ACTION_OF_DEC_NW_TTL] = { 2227 .name = "of_dec_nw_ttl", 2228 .help = "OpenFlow's OFPAT_DEC_NW_TTL", 2229 .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0), 2230 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2231 .call = parse_vc, 2232 }, 2233 [ACTION_OF_COPY_TTL_OUT] = { 2234 .name = "of_copy_ttl_out", 2235 .help = "OpenFlow's OFPAT_COPY_TTL_OUT", 2236 .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0), 2237 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2238 .call = parse_vc, 2239 }, 2240 [ACTION_OF_COPY_TTL_IN] = { 2241 .name = "of_copy_ttl_in", 2242 .help = "OpenFlow's OFPAT_COPY_TTL_IN", 2243 .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0), 2244 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2245 .call = parse_vc, 2246 }, 2247 [ACTION_OF_POP_VLAN] = { 2248 .name = "of_pop_vlan", 2249 .help = "OpenFlow's OFPAT_POP_VLAN", 2250 .priv = PRIV_ACTION(OF_POP_VLAN, 0), 2251 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), 2252 .call = parse_vc, 2253 }, 2254 [ACTION_OF_PUSH_VLAN] = { 2255 .name = "of_push_vlan", 2256 .help = "OpenFlow's OFPAT_PUSH_VLAN", 2257 .priv = PRIV_ACTION 2258 (OF_PUSH_VLAN, 2259 sizeof(struct rte_flow_action_of_push_vlan)), 2260 .next = NEXT(action_of_push_vlan), 2261 .call = parse_vc, 2262 }, 2263 [ACTION_OF_PUSH_VLAN_ETHERTYPE] = { 2264 .name = "ethertype", 2265 .help = "EtherType", 2266 .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)), 2267 .args = ARGS(ARGS_ENTRY_HTON 2268 (struct rte_flow_action_of_push_vlan, 2269 ethertype)), 2270 .call = parse_vc_conf, 2271 }, 2272 [ACTION_OF_SET_VLAN_VID] = { 2273 .name = "of_set_vlan_vid", 2274 .help = "OpenFlow's OFPAT_SET_VLAN_VID", 2275 .priv = PRIV_ACTION 2276 (OF_SET_VLAN_VID, 2277 sizeof(struct rte_flow_action_of_set_vlan_vid)), 2278 .next = NEXT(action_of_set_vlan_vid), 2279 .call = parse_vc, 2280 }, 2281 [ACTION_OF_SET_VLAN_VID_VLAN_VID] = { 2282 .name = "vlan_vid", 2283 .help = "VLAN id", 2284 .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)), 2285 .args = ARGS(ARGS_ENTRY_HTON 2286 (struct rte_flow_action_of_set_vlan_vid, 2287 vlan_vid)), 2288 .call = parse_vc_conf, 2289 }, 2290 [ACTION_OF_SET_VLAN_PCP] = { 2291 .name = "of_set_vlan_pcp", 2292 .help = "OpenFlow's OFPAT_SET_VLAN_PCP", 2293 .priv = PRIV_ACTION 2294 (OF_SET_VLAN_PCP, 2295 sizeof(struct rte_flow_action_of_set_vlan_pcp)), 2296 .next = NEXT(action_of_set_vlan_pcp), 2297 .call = parse_vc, 2298 }, 2299 [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = { 2300 .name = "vlan_pcp", 2301 .help = "VLAN priority", 2302 .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)), 2303 .args = ARGS(ARGS_ENTRY_HTON 2304 (struct rte_flow_action_of_set_vlan_pcp, 2305 vlan_pcp)), 2306 .call = parse_vc_conf, 2307 }, 2308 [ACTION_OF_POP_MPLS] = { 2309 .name = "of_pop_mpls", 2310 .help = "OpenFlow's OFPAT_POP_MPLS", 2311 .priv = PRIV_ACTION(OF_POP_MPLS, 2312 sizeof(struct rte_flow_action_of_pop_mpls)), 2313 .next = NEXT(action_of_pop_mpls), 2314 .call = parse_vc, 2315 }, 2316 [ACTION_OF_POP_MPLS_ETHERTYPE] = { 2317 .name = "ethertype", 2318 .help = "EtherType", 2319 .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)), 2320 .args = ARGS(ARGS_ENTRY_HTON 2321 (struct rte_flow_action_of_pop_mpls, 2322 ethertype)), 2323 .call = parse_vc_conf, 2324 }, 2325 [ACTION_OF_PUSH_MPLS] = { 2326 .name = "of_push_mpls", 2327 .help = "OpenFlow's OFPAT_PUSH_MPLS", 2328 .priv = PRIV_ACTION 2329 (OF_PUSH_MPLS, 2330 sizeof(struct rte_flow_action_of_push_mpls)), 2331 .next = NEXT(action_of_push_mpls), 2332 .call = parse_vc, 2333 }, 2334 [ACTION_OF_PUSH_MPLS_ETHERTYPE] = { 2335 .name = "ethertype", 2336 .help = "EtherType", 2337 .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)), 2338 .args = ARGS(ARGS_ENTRY_HTON 2339 (struct rte_flow_action_of_push_mpls, 2340 ethertype)), 2341 .call = parse_vc_conf, 2342 }, 2343 }; 2344 2345 /** Remove and return last entry from argument stack. */ 2346 static const struct arg * 2347 pop_args(struct context *ctx) 2348 { 2349 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL; 2350 } 2351 2352 /** Add entry on top of the argument stack. */ 2353 static int 2354 push_args(struct context *ctx, const struct arg *arg) 2355 { 2356 if (ctx->args_num == CTX_STACK_SIZE) 2357 return -1; 2358 ctx->args[ctx->args_num++] = arg; 2359 return 0; 2360 } 2361 2362 /** Spread value into buffer according to bit-mask. */ 2363 static size_t 2364 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg) 2365 { 2366 uint32_t i = arg->size; 2367 uint32_t end = 0; 2368 int sub = 1; 2369 int add = 0; 2370 size_t len = 0; 2371 2372 if (!arg->mask) 2373 return 0; 2374 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 2375 if (!arg->hton) { 2376 i = 0; 2377 end = arg->size; 2378 sub = 0; 2379 add = 1; 2380 } 2381 #endif 2382 while (i != end) { 2383 unsigned int shift = 0; 2384 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub); 2385 2386 for (shift = 0; arg->mask[i] >> shift; ++shift) { 2387 if (!(arg->mask[i] & (1 << shift))) 2388 continue; 2389 ++len; 2390 if (!dst) 2391 continue; 2392 *buf &= ~(1 << shift); 2393 *buf |= (val & 1) << shift; 2394 val >>= 1; 2395 } 2396 i += add; 2397 } 2398 return len; 2399 } 2400 2401 /** Compare a string with a partial one of a given length. */ 2402 static int 2403 strcmp_partial(const char *full, const char *partial, size_t partial_len) 2404 { 2405 int r = strncmp(full, partial, partial_len); 2406 2407 if (r) 2408 return r; 2409 if (strlen(full) <= partial_len) 2410 return 0; 2411 return full[partial_len]; 2412 } 2413 2414 /** 2415 * Parse a prefix length and generate a bit-mask. 2416 * 2417 * Last argument (ctx->args) is retrieved to determine mask size, storage 2418 * location and whether the result must use network byte ordering. 2419 */ 2420 static int 2421 parse_prefix(struct context *ctx, const struct token *token, 2422 const char *str, unsigned int len, 2423 void *buf, unsigned int size) 2424 { 2425 const struct arg *arg = pop_args(ctx); 2426 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff"; 2427 char *end; 2428 uintmax_t u; 2429 unsigned int bytes; 2430 unsigned int extra; 2431 2432 (void)token; 2433 /* Argument is expected. */ 2434 if (!arg) 2435 return -1; 2436 errno = 0; 2437 u = strtoumax(str, &end, 0); 2438 if (errno || (size_t)(end - str) != len) 2439 goto error; 2440 if (arg->mask) { 2441 uintmax_t v = 0; 2442 2443 extra = arg_entry_bf_fill(NULL, 0, arg); 2444 if (u > extra) 2445 goto error; 2446 if (!ctx->object) 2447 return len; 2448 extra -= u; 2449 while (u--) 2450 (v <<= 1, v |= 1); 2451 v <<= extra; 2452 if (!arg_entry_bf_fill(ctx->object, v, arg) || 2453 !arg_entry_bf_fill(ctx->objmask, -1, arg)) 2454 goto error; 2455 return len; 2456 } 2457 bytes = u / 8; 2458 extra = u % 8; 2459 size = arg->size; 2460 if (bytes > size || bytes + !!extra > size) 2461 goto error; 2462 if (!ctx->object) 2463 return len; 2464 buf = (uint8_t *)ctx->object + arg->offset; 2465 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 2466 if (!arg->hton) { 2467 memset((uint8_t *)buf + size - bytes, 0xff, bytes); 2468 memset(buf, 0x00, size - bytes); 2469 if (extra) 2470 ((uint8_t *)buf)[size - bytes - 1] = conv[extra]; 2471 } else 2472 #endif 2473 { 2474 memset(buf, 0xff, bytes); 2475 memset((uint8_t *)buf + bytes, 0x00, size - bytes); 2476 if (extra) 2477 ((uint8_t *)buf)[bytes] = conv[extra]; 2478 } 2479 if (ctx->objmask) 2480 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 2481 return len; 2482 error: 2483 push_args(ctx, arg); 2484 return -1; 2485 } 2486 2487 /** Default parsing function for token name matching. */ 2488 static int 2489 parse_default(struct context *ctx, const struct token *token, 2490 const char *str, unsigned int len, 2491 void *buf, unsigned int size) 2492 { 2493 (void)ctx; 2494 (void)buf; 2495 (void)size; 2496 if (strcmp_partial(token->name, str, len)) 2497 return -1; 2498 return len; 2499 } 2500 2501 /** Parse flow command, initialize output buffer for subsequent tokens. */ 2502 static int 2503 parse_init(struct context *ctx, const struct token *token, 2504 const char *str, unsigned int len, 2505 void *buf, unsigned int size) 2506 { 2507 struct buffer *out = buf; 2508 2509 /* Token name must match. */ 2510 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2511 return -1; 2512 /* Nothing else to do if there is no buffer. */ 2513 if (!out) 2514 return len; 2515 /* Make sure buffer is large enough. */ 2516 if (size < sizeof(*out)) 2517 return -1; 2518 /* Initialize buffer. */ 2519 memset(out, 0x00, sizeof(*out)); 2520 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out)); 2521 ctx->objdata = 0; 2522 ctx->object = out; 2523 ctx->objmask = NULL; 2524 return len; 2525 } 2526 2527 /** Parse tokens for validate/create commands. */ 2528 static int 2529 parse_vc(struct context *ctx, const struct token *token, 2530 const char *str, unsigned int len, 2531 void *buf, unsigned int size) 2532 { 2533 struct buffer *out = buf; 2534 uint8_t *data; 2535 uint32_t data_size; 2536 2537 /* Token name must match. */ 2538 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2539 return -1; 2540 /* Nothing else to do if there is no buffer. */ 2541 if (!out) 2542 return len; 2543 if (!out->command) { 2544 if (ctx->curr != VALIDATE && ctx->curr != CREATE) 2545 return -1; 2546 if (sizeof(*out) > size) 2547 return -1; 2548 out->command = ctx->curr; 2549 ctx->objdata = 0; 2550 ctx->object = out; 2551 ctx->objmask = NULL; 2552 out->args.vc.data = (uint8_t *)out + size; 2553 return len; 2554 } 2555 ctx->objdata = 0; 2556 ctx->object = &out->args.vc.attr; 2557 ctx->objmask = NULL; 2558 switch (ctx->curr) { 2559 case GROUP: 2560 case PRIORITY: 2561 return len; 2562 case INGRESS: 2563 out->args.vc.attr.ingress = 1; 2564 return len; 2565 case EGRESS: 2566 out->args.vc.attr.egress = 1; 2567 return len; 2568 case TRANSFER: 2569 out->args.vc.attr.transfer = 1; 2570 return len; 2571 case PATTERN: 2572 out->args.vc.pattern = 2573 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), 2574 sizeof(double)); 2575 ctx->object = out->args.vc.pattern; 2576 ctx->objmask = NULL; 2577 return len; 2578 case ACTIONS: 2579 out->args.vc.actions = 2580 (void *)RTE_ALIGN_CEIL((uintptr_t) 2581 (out->args.vc.pattern + 2582 out->args.vc.pattern_n), 2583 sizeof(double)); 2584 ctx->object = out->args.vc.actions; 2585 ctx->objmask = NULL; 2586 return len; 2587 default: 2588 if (!token->priv) 2589 return -1; 2590 break; 2591 } 2592 if (!out->args.vc.actions) { 2593 const struct parse_item_priv *priv = token->priv; 2594 struct rte_flow_item *item = 2595 out->args.vc.pattern + out->args.vc.pattern_n; 2596 2597 data_size = priv->size * 3; /* spec, last, mask */ 2598 data = (void *)RTE_ALIGN_FLOOR((uintptr_t) 2599 (out->args.vc.data - data_size), 2600 sizeof(double)); 2601 if ((uint8_t *)item + sizeof(*item) > data) 2602 return -1; 2603 *item = (struct rte_flow_item){ 2604 .type = priv->type, 2605 }; 2606 ++out->args.vc.pattern_n; 2607 ctx->object = item; 2608 ctx->objmask = NULL; 2609 } else { 2610 const struct parse_action_priv *priv = token->priv; 2611 struct rte_flow_action *action = 2612 out->args.vc.actions + out->args.vc.actions_n; 2613 2614 data_size = priv->size; /* configuration */ 2615 data = (void *)RTE_ALIGN_FLOOR((uintptr_t) 2616 (out->args.vc.data - data_size), 2617 sizeof(double)); 2618 if ((uint8_t *)action + sizeof(*action) > data) 2619 return -1; 2620 *action = (struct rte_flow_action){ 2621 .type = priv->type, 2622 .conf = data_size ? data : NULL, 2623 }; 2624 ++out->args.vc.actions_n; 2625 ctx->object = action; 2626 ctx->objmask = NULL; 2627 } 2628 memset(data, 0, data_size); 2629 out->args.vc.data = data; 2630 ctx->objdata = data_size; 2631 return len; 2632 } 2633 2634 /** Parse pattern item parameter type. */ 2635 static int 2636 parse_vc_spec(struct context *ctx, const struct token *token, 2637 const char *str, unsigned int len, 2638 void *buf, unsigned int size) 2639 { 2640 struct buffer *out = buf; 2641 struct rte_flow_item *item; 2642 uint32_t data_size; 2643 int index; 2644 int objmask = 0; 2645 2646 (void)size; 2647 /* Token name must match. */ 2648 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2649 return -1; 2650 /* Parse parameter types. */ 2651 switch (ctx->curr) { 2652 static const enum index prefix[] = NEXT_ENTRY(PREFIX); 2653 2654 case ITEM_PARAM_IS: 2655 index = 0; 2656 objmask = 1; 2657 break; 2658 case ITEM_PARAM_SPEC: 2659 index = 0; 2660 break; 2661 case ITEM_PARAM_LAST: 2662 index = 1; 2663 break; 2664 case ITEM_PARAM_PREFIX: 2665 /* Modify next token to expect a prefix. */ 2666 if (ctx->next_num < 2) 2667 return -1; 2668 ctx->next[ctx->next_num - 2] = prefix; 2669 /* Fall through. */ 2670 case ITEM_PARAM_MASK: 2671 index = 2; 2672 break; 2673 default: 2674 return -1; 2675 } 2676 /* Nothing else to do if there is no buffer. */ 2677 if (!out) 2678 return len; 2679 if (!out->args.vc.pattern_n) 2680 return -1; 2681 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1]; 2682 data_size = ctx->objdata / 3; /* spec, last, mask */ 2683 /* Point to selected object. */ 2684 ctx->object = out->args.vc.data + (data_size * index); 2685 if (objmask) { 2686 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */ 2687 item->mask = ctx->objmask; 2688 } else 2689 ctx->objmask = NULL; 2690 /* Update relevant item pointer. */ 2691 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] = 2692 ctx->object; 2693 return len; 2694 } 2695 2696 /** Parse action configuration field. */ 2697 static int 2698 parse_vc_conf(struct context *ctx, const struct token *token, 2699 const char *str, unsigned int len, 2700 void *buf, unsigned int size) 2701 { 2702 struct buffer *out = buf; 2703 2704 (void)size; 2705 /* Token name must match. */ 2706 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2707 return -1; 2708 /* Nothing else to do if there is no buffer. */ 2709 if (!out) 2710 return len; 2711 /* Point to selected object. */ 2712 ctx->object = out->args.vc.data; 2713 ctx->objmask = NULL; 2714 return len; 2715 } 2716 2717 /** Parse RSS action. */ 2718 static int 2719 parse_vc_action_rss(struct context *ctx, const struct token *token, 2720 const char *str, unsigned int len, 2721 void *buf, unsigned int size) 2722 { 2723 struct buffer *out = buf; 2724 struct rte_flow_action *action; 2725 struct action_rss_data *action_rss_data; 2726 unsigned int i; 2727 int ret; 2728 2729 ret = parse_vc(ctx, token, str, len, buf, size); 2730 if (ret < 0) 2731 return ret; 2732 /* Nothing else to do if there is no buffer. */ 2733 if (!out) 2734 return ret; 2735 if (!out->args.vc.actions_n) 2736 return -1; 2737 action = &out->args.vc.actions[out->args.vc.actions_n - 1]; 2738 /* Point to selected object. */ 2739 ctx->object = out->args.vc.data; 2740 ctx->objmask = NULL; 2741 /* Set up default configuration. */ 2742 action_rss_data = ctx->object; 2743 *action_rss_data = (struct action_rss_data){ 2744 .conf = (struct rte_flow_action_rss){ 2745 .func = RTE_ETH_HASH_FUNCTION_DEFAULT, 2746 .level = 0, 2747 .types = rss_hf, 2748 .key_len = sizeof(action_rss_data->key), 2749 .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM), 2750 .key = action_rss_data->key, 2751 .queue = action_rss_data->queue, 2752 }, 2753 .key = "testpmd's default RSS hash key", 2754 .queue = { 0 }, 2755 }; 2756 for (i = 0; i < action_rss_data->conf.queue_num; ++i) 2757 action_rss_data->queue[i] = i; 2758 if (!port_id_is_invalid(ctx->port, DISABLED_WARN) && 2759 ctx->port != (portid_t)RTE_PORT_ALL) { 2760 struct rte_eth_dev_info info; 2761 2762 rte_eth_dev_info_get(ctx->port, &info); 2763 action_rss_data->conf.key_len = 2764 RTE_MIN(sizeof(action_rss_data->key), 2765 info.hash_key_size); 2766 } 2767 action->conf = &action_rss_data->conf; 2768 return ret; 2769 } 2770 2771 /** 2772 * Parse func field for RSS action. 2773 * 2774 * The RTE_ETH_HASH_FUNCTION_* value to assign is derived from the 2775 * ACTION_RSS_FUNC_* index that called this function. 2776 */ 2777 static int 2778 parse_vc_action_rss_func(struct context *ctx, const struct token *token, 2779 const char *str, unsigned int len, 2780 void *buf, unsigned int size) 2781 { 2782 struct action_rss_data *action_rss_data; 2783 enum rte_eth_hash_function func; 2784 2785 (void)buf; 2786 (void)size; 2787 /* Token name must match. */ 2788 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2789 return -1; 2790 switch (ctx->curr) { 2791 case ACTION_RSS_FUNC_DEFAULT: 2792 func = RTE_ETH_HASH_FUNCTION_DEFAULT; 2793 break; 2794 case ACTION_RSS_FUNC_TOEPLITZ: 2795 func = RTE_ETH_HASH_FUNCTION_TOEPLITZ; 2796 break; 2797 case ACTION_RSS_FUNC_SIMPLE_XOR: 2798 func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR; 2799 break; 2800 default: 2801 return -1; 2802 } 2803 if (!ctx->object) 2804 return len; 2805 action_rss_data = ctx->object; 2806 action_rss_data->conf.func = func; 2807 return len; 2808 } 2809 2810 /** 2811 * Parse type field for RSS action. 2812 * 2813 * Valid tokens are type field names and the "end" token. 2814 */ 2815 static int 2816 parse_vc_action_rss_type(struct context *ctx, const struct token *token, 2817 const char *str, unsigned int len, 2818 void *buf, unsigned int size) 2819 { 2820 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE); 2821 struct action_rss_data *action_rss_data; 2822 unsigned int i; 2823 2824 (void)token; 2825 (void)buf; 2826 (void)size; 2827 if (ctx->curr != ACTION_RSS_TYPE) 2828 return -1; 2829 if (!(ctx->objdata >> 16) && ctx->object) { 2830 action_rss_data = ctx->object; 2831 action_rss_data->conf.types = 0; 2832 } 2833 if (!strcmp_partial("end", str, len)) { 2834 ctx->objdata &= 0xffff; 2835 return len; 2836 } 2837 for (i = 0; rss_type_table[i].str; ++i) 2838 if (!strcmp_partial(rss_type_table[i].str, str, len)) 2839 break; 2840 if (!rss_type_table[i].str) 2841 return -1; 2842 ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff); 2843 /* Repeat token. */ 2844 if (ctx->next_num == RTE_DIM(ctx->next)) 2845 return -1; 2846 ctx->next[ctx->next_num++] = next; 2847 if (!ctx->object) 2848 return len; 2849 action_rss_data = ctx->object; 2850 action_rss_data->conf.types |= rss_type_table[i].rss_type; 2851 return len; 2852 } 2853 2854 /** 2855 * Parse queue field for RSS action. 2856 * 2857 * Valid tokens are queue indices and the "end" token. 2858 */ 2859 static int 2860 parse_vc_action_rss_queue(struct context *ctx, const struct token *token, 2861 const char *str, unsigned int len, 2862 void *buf, unsigned int size) 2863 { 2864 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE); 2865 struct action_rss_data *action_rss_data; 2866 int ret; 2867 int i; 2868 2869 (void)token; 2870 (void)buf; 2871 (void)size; 2872 if (ctx->curr != ACTION_RSS_QUEUE) 2873 return -1; 2874 i = ctx->objdata >> 16; 2875 if (!strcmp_partial("end", str, len)) { 2876 ctx->objdata &= 0xffff; 2877 return len; 2878 } 2879 if (i >= ACTION_RSS_QUEUE_NUM) 2880 return -1; 2881 if (push_args(ctx, 2882 ARGS_ENTRY_ARB(offsetof(struct action_rss_data, queue) + 2883 i * sizeof(action_rss_data->queue[i]), 2884 sizeof(action_rss_data->queue[i])))) 2885 return -1; 2886 ret = parse_int(ctx, token, str, len, NULL, 0); 2887 if (ret < 0) { 2888 pop_args(ctx); 2889 return -1; 2890 } 2891 ++i; 2892 ctx->objdata = i << 16 | (ctx->objdata & 0xffff); 2893 /* Repeat token. */ 2894 if (ctx->next_num == RTE_DIM(ctx->next)) 2895 return -1; 2896 ctx->next[ctx->next_num++] = next; 2897 if (!ctx->object) 2898 return len; 2899 action_rss_data = ctx->object; 2900 action_rss_data->conf.queue_num = i; 2901 action_rss_data->conf.queue = i ? action_rss_data->queue : NULL; 2902 return len; 2903 } 2904 2905 /** Parse tokens for destroy command. */ 2906 static int 2907 parse_destroy(struct context *ctx, const struct token *token, 2908 const char *str, unsigned int len, 2909 void *buf, unsigned int size) 2910 { 2911 struct buffer *out = buf; 2912 2913 /* Token name must match. */ 2914 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2915 return -1; 2916 /* Nothing else to do if there is no buffer. */ 2917 if (!out) 2918 return len; 2919 if (!out->command) { 2920 if (ctx->curr != DESTROY) 2921 return -1; 2922 if (sizeof(*out) > size) 2923 return -1; 2924 out->command = ctx->curr; 2925 ctx->objdata = 0; 2926 ctx->object = out; 2927 ctx->objmask = NULL; 2928 out->args.destroy.rule = 2929 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), 2930 sizeof(double)); 2931 return len; 2932 } 2933 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) + 2934 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size) 2935 return -1; 2936 ctx->objdata = 0; 2937 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++; 2938 ctx->objmask = NULL; 2939 return len; 2940 } 2941 2942 /** Parse tokens for flush command. */ 2943 static int 2944 parse_flush(struct context *ctx, const struct token *token, 2945 const char *str, unsigned int len, 2946 void *buf, unsigned int size) 2947 { 2948 struct buffer *out = buf; 2949 2950 /* Token name must match. */ 2951 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2952 return -1; 2953 /* Nothing else to do if there is no buffer. */ 2954 if (!out) 2955 return len; 2956 if (!out->command) { 2957 if (ctx->curr != FLUSH) 2958 return -1; 2959 if (sizeof(*out) > size) 2960 return -1; 2961 out->command = ctx->curr; 2962 ctx->objdata = 0; 2963 ctx->object = out; 2964 ctx->objmask = NULL; 2965 } 2966 return len; 2967 } 2968 2969 /** Parse tokens for query command. */ 2970 static int 2971 parse_query(struct context *ctx, const struct token *token, 2972 const char *str, unsigned int len, 2973 void *buf, unsigned int size) 2974 { 2975 struct buffer *out = buf; 2976 2977 /* Token name must match. */ 2978 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 2979 return -1; 2980 /* Nothing else to do if there is no buffer. */ 2981 if (!out) 2982 return len; 2983 if (!out->command) { 2984 if (ctx->curr != QUERY) 2985 return -1; 2986 if (sizeof(*out) > size) 2987 return -1; 2988 out->command = ctx->curr; 2989 ctx->objdata = 0; 2990 ctx->object = out; 2991 ctx->objmask = NULL; 2992 } 2993 return len; 2994 } 2995 2996 /** Parse action names. */ 2997 static int 2998 parse_action(struct context *ctx, const struct token *token, 2999 const char *str, unsigned int len, 3000 void *buf, unsigned int size) 3001 { 3002 struct buffer *out = buf; 3003 const struct arg *arg = pop_args(ctx); 3004 unsigned int i; 3005 3006 (void)size; 3007 /* Argument is expected. */ 3008 if (!arg) 3009 return -1; 3010 /* Parse action name. */ 3011 for (i = 0; next_action[i]; ++i) { 3012 const struct parse_action_priv *priv; 3013 3014 token = &token_list[next_action[i]]; 3015 if (strcmp_partial(token->name, str, len)) 3016 continue; 3017 priv = token->priv; 3018 if (!priv) 3019 goto error; 3020 if (out) 3021 memcpy((uint8_t *)ctx->object + arg->offset, 3022 &priv->type, 3023 arg->size); 3024 return len; 3025 } 3026 error: 3027 push_args(ctx, arg); 3028 return -1; 3029 } 3030 3031 /** Parse tokens for list command. */ 3032 static int 3033 parse_list(struct context *ctx, const struct token *token, 3034 const char *str, unsigned int len, 3035 void *buf, unsigned int size) 3036 { 3037 struct buffer *out = buf; 3038 3039 /* Token name must match. */ 3040 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 3041 return -1; 3042 /* Nothing else to do if there is no buffer. */ 3043 if (!out) 3044 return len; 3045 if (!out->command) { 3046 if (ctx->curr != LIST) 3047 return -1; 3048 if (sizeof(*out) > size) 3049 return -1; 3050 out->command = ctx->curr; 3051 ctx->objdata = 0; 3052 ctx->object = out; 3053 ctx->objmask = NULL; 3054 out->args.list.group = 3055 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1), 3056 sizeof(double)); 3057 return len; 3058 } 3059 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) + 3060 sizeof(*out->args.list.group)) > (uint8_t *)out + size) 3061 return -1; 3062 ctx->objdata = 0; 3063 ctx->object = out->args.list.group + out->args.list.group_n++; 3064 ctx->objmask = NULL; 3065 return len; 3066 } 3067 3068 /** Parse tokens for isolate command. */ 3069 static int 3070 parse_isolate(struct context *ctx, const struct token *token, 3071 const char *str, unsigned int len, 3072 void *buf, unsigned int size) 3073 { 3074 struct buffer *out = buf; 3075 3076 /* Token name must match. */ 3077 if (parse_default(ctx, token, str, len, NULL, 0) < 0) 3078 return -1; 3079 /* Nothing else to do if there is no buffer. */ 3080 if (!out) 3081 return len; 3082 if (!out->command) { 3083 if (ctx->curr != ISOLATE) 3084 return -1; 3085 if (sizeof(*out) > size) 3086 return -1; 3087 out->command = ctx->curr; 3088 ctx->objdata = 0; 3089 ctx->object = out; 3090 ctx->objmask = NULL; 3091 } 3092 return len; 3093 } 3094 3095 /** 3096 * Parse signed/unsigned integers 8 to 64-bit long. 3097 * 3098 * Last argument (ctx->args) is retrieved to determine integer type and 3099 * storage location. 3100 */ 3101 static int 3102 parse_int(struct context *ctx, const struct token *token, 3103 const char *str, unsigned int len, 3104 void *buf, unsigned int size) 3105 { 3106 const struct arg *arg = pop_args(ctx); 3107 uintmax_t u; 3108 char *end; 3109 3110 (void)token; 3111 /* Argument is expected. */ 3112 if (!arg) 3113 return -1; 3114 errno = 0; 3115 u = arg->sign ? 3116 (uintmax_t)strtoimax(str, &end, 0) : 3117 strtoumax(str, &end, 0); 3118 if (errno || (size_t)(end - str) != len) 3119 goto error; 3120 if (arg->bounded && 3121 ((arg->sign && ((intmax_t)u < (intmax_t)arg->min || 3122 (intmax_t)u > (intmax_t)arg->max)) || 3123 (!arg->sign && (u < arg->min || u > arg->max)))) 3124 goto error; 3125 if (!ctx->object) 3126 return len; 3127 if (arg->mask) { 3128 if (!arg_entry_bf_fill(ctx->object, u, arg) || 3129 !arg_entry_bf_fill(ctx->objmask, -1, arg)) 3130 goto error; 3131 return len; 3132 } 3133 buf = (uint8_t *)ctx->object + arg->offset; 3134 size = arg->size; 3135 objmask: 3136 switch (size) { 3137 case sizeof(uint8_t): 3138 *(uint8_t *)buf = u; 3139 break; 3140 case sizeof(uint16_t): 3141 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u; 3142 break; 3143 case sizeof(uint8_t [3]): 3144 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 3145 if (!arg->hton) { 3146 ((uint8_t *)buf)[0] = u; 3147 ((uint8_t *)buf)[1] = u >> 8; 3148 ((uint8_t *)buf)[2] = u >> 16; 3149 break; 3150 } 3151 #endif 3152 ((uint8_t *)buf)[0] = u >> 16; 3153 ((uint8_t *)buf)[1] = u >> 8; 3154 ((uint8_t *)buf)[2] = u; 3155 break; 3156 case sizeof(uint32_t): 3157 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u; 3158 break; 3159 case sizeof(uint64_t): 3160 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u; 3161 break; 3162 default: 3163 goto error; 3164 } 3165 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) { 3166 u = -1; 3167 buf = (uint8_t *)ctx->objmask + arg->offset; 3168 goto objmask; 3169 } 3170 return len; 3171 error: 3172 push_args(ctx, arg); 3173 return -1; 3174 } 3175 3176 /** 3177 * Parse a string. 3178 * 3179 * Three arguments (ctx->args) are retrieved from the stack to store data, 3180 * its actual length and address (in that order). 3181 */ 3182 static int 3183 parse_string(struct context *ctx, const struct token *token, 3184 const char *str, unsigned int len, 3185 void *buf, unsigned int size) 3186 { 3187 const struct arg *arg_data = pop_args(ctx); 3188 const struct arg *arg_len = pop_args(ctx); 3189 const struct arg *arg_addr = pop_args(ctx); 3190 char tmp[16]; /* Ought to be enough. */ 3191 int ret; 3192 3193 /* Arguments are expected. */ 3194 if (!arg_data) 3195 return -1; 3196 if (!arg_len) { 3197 push_args(ctx, arg_data); 3198 return -1; 3199 } 3200 if (!arg_addr) { 3201 push_args(ctx, arg_len); 3202 push_args(ctx, arg_data); 3203 return -1; 3204 } 3205 size = arg_data->size; 3206 /* Bit-mask fill is not supported. */ 3207 if (arg_data->mask || size < len) 3208 goto error; 3209 if (!ctx->object) 3210 return len; 3211 /* Let parse_int() fill length information first. */ 3212 ret = snprintf(tmp, sizeof(tmp), "%u", len); 3213 if (ret < 0) 3214 goto error; 3215 push_args(ctx, arg_len); 3216 ret = parse_int(ctx, token, tmp, ret, NULL, 0); 3217 if (ret < 0) { 3218 pop_args(ctx); 3219 goto error; 3220 } 3221 buf = (uint8_t *)ctx->object + arg_data->offset; 3222 /* Output buffer is not necessarily NUL-terminated. */ 3223 memcpy(buf, str, len); 3224 memset((uint8_t *)buf + len, 0x00, size - len); 3225 if (ctx->objmask) 3226 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len); 3227 /* Save address if requested. */ 3228 if (arg_addr->size) { 3229 memcpy((uint8_t *)ctx->object + arg_addr->offset, 3230 (void *[]){ 3231 (uint8_t *)ctx->object + arg_data->offset 3232 }, 3233 arg_addr->size); 3234 if (ctx->objmask) 3235 memcpy((uint8_t *)ctx->objmask + arg_addr->offset, 3236 (void *[]){ 3237 (uint8_t *)ctx->objmask + arg_data->offset 3238 }, 3239 arg_addr->size); 3240 } 3241 return len; 3242 error: 3243 push_args(ctx, arg_addr); 3244 push_args(ctx, arg_len); 3245 push_args(ctx, arg_data); 3246 return -1; 3247 } 3248 3249 /** 3250 * Parse a MAC address. 3251 * 3252 * Last argument (ctx->args) is retrieved to determine storage size and 3253 * location. 3254 */ 3255 static int 3256 parse_mac_addr(struct context *ctx, const struct token *token, 3257 const char *str, unsigned int len, 3258 void *buf, unsigned int size) 3259 { 3260 const struct arg *arg = pop_args(ctx); 3261 struct ether_addr tmp; 3262 int ret; 3263 3264 (void)token; 3265 /* Argument is expected. */ 3266 if (!arg) 3267 return -1; 3268 size = arg->size; 3269 /* Bit-mask fill is not supported. */ 3270 if (arg->mask || size != sizeof(tmp)) 3271 goto error; 3272 /* Only network endian is supported. */ 3273 if (!arg->hton) 3274 goto error; 3275 ret = cmdline_parse_etheraddr(NULL, str, &tmp, size); 3276 if (ret < 0 || (unsigned int)ret != len) 3277 goto error; 3278 if (!ctx->object) 3279 return len; 3280 buf = (uint8_t *)ctx->object + arg->offset; 3281 memcpy(buf, &tmp, size); 3282 if (ctx->objmask) 3283 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 3284 return len; 3285 error: 3286 push_args(ctx, arg); 3287 return -1; 3288 } 3289 3290 /** 3291 * Parse an IPv4 address. 3292 * 3293 * Last argument (ctx->args) is retrieved to determine storage size and 3294 * location. 3295 */ 3296 static int 3297 parse_ipv4_addr(struct context *ctx, const struct token *token, 3298 const char *str, unsigned int len, 3299 void *buf, unsigned int size) 3300 { 3301 const struct arg *arg = pop_args(ctx); 3302 char str2[len + 1]; 3303 struct in_addr tmp; 3304 int ret; 3305 3306 /* Argument is expected. */ 3307 if (!arg) 3308 return -1; 3309 size = arg->size; 3310 /* Bit-mask fill is not supported. */ 3311 if (arg->mask || size != sizeof(tmp)) 3312 goto error; 3313 /* Only network endian is supported. */ 3314 if (!arg->hton) 3315 goto error; 3316 memcpy(str2, str, len); 3317 str2[len] = '\0'; 3318 ret = inet_pton(AF_INET, str2, &tmp); 3319 if (ret != 1) { 3320 /* Attempt integer parsing. */ 3321 push_args(ctx, arg); 3322 return parse_int(ctx, token, str, len, buf, size); 3323 } 3324 if (!ctx->object) 3325 return len; 3326 buf = (uint8_t *)ctx->object + arg->offset; 3327 memcpy(buf, &tmp, size); 3328 if (ctx->objmask) 3329 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 3330 return len; 3331 error: 3332 push_args(ctx, arg); 3333 return -1; 3334 } 3335 3336 /** 3337 * Parse an IPv6 address. 3338 * 3339 * Last argument (ctx->args) is retrieved to determine storage size and 3340 * location. 3341 */ 3342 static int 3343 parse_ipv6_addr(struct context *ctx, const struct token *token, 3344 const char *str, unsigned int len, 3345 void *buf, unsigned int size) 3346 { 3347 const struct arg *arg = pop_args(ctx); 3348 char str2[len + 1]; 3349 struct in6_addr tmp; 3350 int ret; 3351 3352 (void)token; 3353 /* Argument is expected. */ 3354 if (!arg) 3355 return -1; 3356 size = arg->size; 3357 /* Bit-mask fill is not supported. */ 3358 if (arg->mask || size != sizeof(tmp)) 3359 goto error; 3360 /* Only network endian is supported. */ 3361 if (!arg->hton) 3362 goto error; 3363 memcpy(str2, str, len); 3364 str2[len] = '\0'; 3365 ret = inet_pton(AF_INET6, str2, &tmp); 3366 if (ret != 1) 3367 goto error; 3368 if (!ctx->object) 3369 return len; 3370 buf = (uint8_t *)ctx->object + arg->offset; 3371 memcpy(buf, &tmp, size); 3372 if (ctx->objmask) 3373 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size); 3374 return len; 3375 error: 3376 push_args(ctx, arg); 3377 return -1; 3378 } 3379 3380 /** Boolean values (even indices stand for false). */ 3381 static const char *const boolean_name[] = { 3382 "0", "1", 3383 "false", "true", 3384 "no", "yes", 3385 "N", "Y", 3386 "off", "on", 3387 NULL, 3388 }; 3389 3390 /** 3391 * Parse a boolean value. 3392 * 3393 * Last argument (ctx->args) is retrieved to determine storage size and 3394 * location. 3395 */ 3396 static int 3397 parse_boolean(struct context *ctx, const struct token *token, 3398 const char *str, unsigned int len, 3399 void *buf, unsigned int size) 3400 { 3401 const struct arg *arg = pop_args(ctx); 3402 unsigned int i; 3403 int ret; 3404 3405 /* Argument is expected. */ 3406 if (!arg) 3407 return -1; 3408 for (i = 0; boolean_name[i]; ++i) 3409 if (!strcmp_partial(boolean_name[i], str, len)) 3410 break; 3411 /* Process token as integer. */ 3412 if (boolean_name[i]) 3413 str = i & 1 ? "1" : "0"; 3414 push_args(ctx, arg); 3415 ret = parse_int(ctx, token, str, strlen(str), buf, size); 3416 return ret > 0 ? (int)len : ret; 3417 } 3418 3419 /** Parse port and update context. */ 3420 static int 3421 parse_port(struct context *ctx, const struct token *token, 3422 const char *str, unsigned int len, 3423 void *buf, unsigned int size) 3424 { 3425 struct buffer *out = &(struct buffer){ .port = 0 }; 3426 int ret; 3427 3428 if (buf) 3429 out = buf; 3430 else { 3431 ctx->objdata = 0; 3432 ctx->object = out; 3433 ctx->objmask = NULL; 3434 size = sizeof(*out); 3435 } 3436 ret = parse_int(ctx, token, str, len, out, size); 3437 if (ret >= 0) 3438 ctx->port = out->port; 3439 if (!buf) 3440 ctx->object = NULL; 3441 return ret; 3442 } 3443 3444 /** No completion. */ 3445 static int 3446 comp_none(struct context *ctx, const struct token *token, 3447 unsigned int ent, char *buf, unsigned int size) 3448 { 3449 (void)ctx; 3450 (void)token; 3451 (void)ent; 3452 (void)buf; 3453 (void)size; 3454 return 0; 3455 } 3456 3457 /** Complete boolean values. */ 3458 static int 3459 comp_boolean(struct context *ctx, const struct token *token, 3460 unsigned int ent, char *buf, unsigned int size) 3461 { 3462 unsigned int i; 3463 3464 (void)ctx; 3465 (void)token; 3466 for (i = 0; boolean_name[i]; ++i) 3467 if (buf && i == ent) 3468 return snprintf(buf, size, "%s", boolean_name[i]); 3469 if (buf) 3470 return -1; 3471 return i; 3472 } 3473 3474 /** Complete action names. */ 3475 static int 3476 comp_action(struct context *ctx, const struct token *token, 3477 unsigned int ent, char *buf, unsigned int size) 3478 { 3479 unsigned int i; 3480 3481 (void)ctx; 3482 (void)token; 3483 for (i = 0; next_action[i]; ++i) 3484 if (buf && i == ent) 3485 return snprintf(buf, size, "%s", 3486 token_list[next_action[i]].name); 3487 if (buf) 3488 return -1; 3489 return i; 3490 } 3491 3492 /** Complete available ports. */ 3493 static int 3494 comp_port(struct context *ctx, const struct token *token, 3495 unsigned int ent, char *buf, unsigned int size) 3496 { 3497 unsigned int i = 0; 3498 portid_t p; 3499 3500 (void)ctx; 3501 (void)token; 3502 RTE_ETH_FOREACH_DEV(p) { 3503 if (buf && i == ent) 3504 return snprintf(buf, size, "%u", p); 3505 ++i; 3506 } 3507 if (buf) 3508 return -1; 3509 return i; 3510 } 3511 3512 /** Complete available rule IDs. */ 3513 static int 3514 comp_rule_id(struct context *ctx, const struct token *token, 3515 unsigned int ent, char *buf, unsigned int size) 3516 { 3517 unsigned int i = 0; 3518 struct rte_port *port; 3519 struct port_flow *pf; 3520 3521 (void)token; 3522 if (port_id_is_invalid(ctx->port, DISABLED_WARN) || 3523 ctx->port == (portid_t)RTE_PORT_ALL) 3524 return -1; 3525 port = &ports[ctx->port]; 3526 for (pf = port->flow_list; pf != NULL; pf = pf->next) { 3527 if (buf && i == ent) 3528 return snprintf(buf, size, "%u", pf->id); 3529 ++i; 3530 } 3531 if (buf) 3532 return -1; 3533 return i; 3534 } 3535 3536 /** Complete type field for RSS action. */ 3537 static int 3538 comp_vc_action_rss_type(struct context *ctx, const struct token *token, 3539 unsigned int ent, char *buf, unsigned int size) 3540 { 3541 unsigned int i; 3542 3543 (void)ctx; 3544 (void)token; 3545 for (i = 0; rss_type_table[i].str; ++i) 3546 ; 3547 if (!buf) 3548 return i + 1; 3549 if (ent < i) 3550 return snprintf(buf, size, "%s", rss_type_table[ent].str); 3551 if (ent == i) 3552 return snprintf(buf, size, "end"); 3553 return -1; 3554 } 3555 3556 /** Complete queue field for RSS action. */ 3557 static int 3558 comp_vc_action_rss_queue(struct context *ctx, const struct token *token, 3559 unsigned int ent, char *buf, unsigned int size) 3560 { 3561 (void)ctx; 3562 (void)token; 3563 if (!buf) 3564 return nb_rxq + 1; 3565 if (ent < nb_rxq) 3566 return snprintf(buf, size, "%u", ent); 3567 if (ent == nb_rxq) 3568 return snprintf(buf, size, "end"); 3569 return -1; 3570 } 3571 3572 /** Internal context. */ 3573 static struct context cmd_flow_context; 3574 3575 /** Global parser instance (cmdline API). */ 3576 cmdline_parse_inst_t cmd_flow; 3577 3578 /** Initialize context. */ 3579 static void 3580 cmd_flow_context_init(struct context *ctx) 3581 { 3582 /* A full memset() is not necessary. */ 3583 ctx->curr = ZERO; 3584 ctx->prev = ZERO; 3585 ctx->next_num = 0; 3586 ctx->args_num = 0; 3587 ctx->eol = 0; 3588 ctx->last = 0; 3589 ctx->port = 0; 3590 ctx->objdata = 0; 3591 ctx->object = NULL; 3592 ctx->objmask = NULL; 3593 } 3594 3595 /** Parse a token (cmdline API). */ 3596 static int 3597 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result, 3598 unsigned int size) 3599 { 3600 struct context *ctx = &cmd_flow_context; 3601 const struct token *token; 3602 const enum index *list; 3603 int len; 3604 int i; 3605 3606 (void)hdr; 3607 token = &token_list[ctx->curr]; 3608 /* Check argument length. */ 3609 ctx->eol = 0; 3610 ctx->last = 1; 3611 for (len = 0; src[len]; ++len) 3612 if (src[len] == '#' || isspace(src[len])) 3613 break; 3614 if (!len) 3615 return -1; 3616 /* Last argument and EOL detection. */ 3617 for (i = len; src[i]; ++i) 3618 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n') 3619 break; 3620 else if (!isspace(src[i])) { 3621 ctx->last = 0; 3622 break; 3623 } 3624 for (; src[i]; ++i) 3625 if (src[i] == '\r' || src[i] == '\n') { 3626 ctx->eol = 1; 3627 break; 3628 } 3629 /* Initialize context if necessary. */ 3630 if (!ctx->next_num) { 3631 if (!token->next) 3632 return 0; 3633 ctx->next[ctx->next_num++] = token->next[0]; 3634 } 3635 /* Process argument through candidates. */ 3636 ctx->prev = ctx->curr; 3637 list = ctx->next[ctx->next_num - 1]; 3638 for (i = 0; list[i]; ++i) { 3639 const struct token *next = &token_list[list[i]]; 3640 int tmp; 3641 3642 ctx->curr = list[i]; 3643 if (next->call) 3644 tmp = next->call(ctx, next, src, len, result, size); 3645 else 3646 tmp = parse_default(ctx, next, src, len, result, size); 3647 if (tmp == -1 || tmp != len) 3648 continue; 3649 token = next; 3650 break; 3651 } 3652 if (!list[i]) 3653 return -1; 3654 --ctx->next_num; 3655 /* Push subsequent tokens if any. */ 3656 if (token->next) 3657 for (i = 0; token->next[i]; ++i) { 3658 if (ctx->next_num == RTE_DIM(ctx->next)) 3659 return -1; 3660 ctx->next[ctx->next_num++] = token->next[i]; 3661 } 3662 /* Push arguments if any. */ 3663 if (token->args) 3664 for (i = 0; token->args[i]; ++i) { 3665 if (ctx->args_num == RTE_DIM(ctx->args)) 3666 return -1; 3667 ctx->args[ctx->args_num++] = token->args[i]; 3668 } 3669 return len; 3670 } 3671 3672 /** Return number of completion entries (cmdline API). */ 3673 static int 3674 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr) 3675 { 3676 struct context *ctx = &cmd_flow_context; 3677 const struct token *token = &token_list[ctx->curr]; 3678 const enum index *list; 3679 int i; 3680 3681 (void)hdr; 3682 /* Count number of tokens in current list. */ 3683 if (ctx->next_num) 3684 list = ctx->next[ctx->next_num - 1]; 3685 else 3686 list = token->next[0]; 3687 for (i = 0; list[i]; ++i) 3688 ; 3689 if (!i) 3690 return 0; 3691 /* 3692 * If there is a single token, use its completion callback, otherwise 3693 * return the number of entries. 3694 */ 3695 token = &token_list[list[0]]; 3696 if (i == 1 && token->comp) { 3697 /* Save index for cmd_flow_get_help(). */ 3698 ctx->prev = list[0]; 3699 return token->comp(ctx, token, 0, NULL, 0); 3700 } 3701 return i; 3702 } 3703 3704 /** Return a completion entry (cmdline API). */ 3705 static int 3706 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index, 3707 char *dst, unsigned int size) 3708 { 3709 struct context *ctx = &cmd_flow_context; 3710 const struct token *token = &token_list[ctx->curr]; 3711 const enum index *list; 3712 int i; 3713 3714 (void)hdr; 3715 /* Count number of tokens in current list. */ 3716 if (ctx->next_num) 3717 list = ctx->next[ctx->next_num - 1]; 3718 else 3719 list = token->next[0]; 3720 for (i = 0; list[i]; ++i) 3721 ; 3722 if (!i) 3723 return -1; 3724 /* If there is a single token, use its completion callback. */ 3725 token = &token_list[list[0]]; 3726 if (i == 1 && token->comp) { 3727 /* Save index for cmd_flow_get_help(). */ 3728 ctx->prev = list[0]; 3729 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0; 3730 } 3731 /* Otherwise make sure the index is valid and use defaults. */ 3732 if (index >= i) 3733 return -1; 3734 token = &token_list[list[index]]; 3735 snprintf(dst, size, "%s", token->name); 3736 /* Save index for cmd_flow_get_help(). */ 3737 ctx->prev = list[index]; 3738 return 0; 3739 } 3740 3741 /** Populate help strings for current token (cmdline API). */ 3742 static int 3743 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size) 3744 { 3745 struct context *ctx = &cmd_flow_context; 3746 const struct token *token = &token_list[ctx->prev]; 3747 3748 (void)hdr; 3749 if (!size) 3750 return -1; 3751 /* Set token type and update global help with details. */ 3752 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN")); 3753 if (token->help) 3754 cmd_flow.help_str = token->help; 3755 else 3756 cmd_flow.help_str = token->name; 3757 return 0; 3758 } 3759 3760 /** Token definition template (cmdline API). */ 3761 static struct cmdline_token_hdr cmd_flow_token_hdr = { 3762 .ops = &(struct cmdline_token_ops){ 3763 .parse = cmd_flow_parse, 3764 .complete_get_nb = cmd_flow_complete_get_nb, 3765 .complete_get_elt = cmd_flow_complete_get_elt, 3766 .get_help = cmd_flow_get_help, 3767 }, 3768 .offset = 0, 3769 }; 3770 3771 /** Populate the next dynamic token. */ 3772 static void 3773 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr, 3774 cmdline_parse_token_hdr_t **hdr_inst) 3775 { 3776 struct context *ctx = &cmd_flow_context; 3777 3778 /* Always reinitialize context before requesting the first token. */ 3779 if (!(hdr_inst - cmd_flow.tokens)) 3780 cmd_flow_context_init(ctx); 3781 /* Return NULL when no more tokens are expected. */ 3782 if (!ctx->next_num && ctx->curr) { 3783 *hdr = NULL; 3784 return; 3785 } 3786 /* Determine if command should end here. */ 3787 if (ctx->eol && ctx->last && ctx->next_num) { 3788 const enum index *list = ctx->next[ctx->next_num - 1]; 3789 int i; 3790 3791 for (i = 0; list[i]; ++i) { 3792 if (list[i] != END) 3793 continue; 3794 *hdr = NULL; 3795 return; 3796 } 3797 } 3798 *hdr = &cmd_flow_token_hdr; 3799 } 3800 3801 /** Dispatch parsed buffer to function calls. */ 3802 static void 3803 cmd_flow_parsed(const struct buffer *in) 3804 { 3805 switch (in->command) { 3806 case VALIDATE: 3807 port_flow_validate(in->port, &in->args.vc.attr, 3808 in->args.vc.pattern, in->args.vc.actions); 3809 break; 3810 case CREATE: 3811 port_flow_create(in->port, &in->args.vc.attr, 3812 in->args.vc.pattern, in->args.vc.actions); 3813 break; 3814 case DESTROY: 3815 port_flow_destroy(in->port, in->args.destroy.rule_n, 3816 in->args.destroy.rule); 3817 break; 3818 case FLUSH: 3819 port_flow_flush(in->port); 3820 break; 3821 case QUERY: 3822 port_flow_query(in->port, in->args.query.rule, 3823 in->args.query.action); 3824 break; 3825 case LIST: 3826 port_flow_list(in->port, in->args.list.group_n, 3827 in->args.list.group); 3828 break; 3829 case ISOLATE: 3830 port_flow_isolate(in->port, in->args.isolate.set); 3831 break; 3832 default: 3833 break; 3834 } 3835 } 3836 3837 /** Token generator and output processing callback (cmdline API). */ 3838 static void 3839 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2) 3840 { 3841 if (cl == NULL) 3842 cmd_flow_tok(arg0, arg2); 3843 else 3844 cmd_flow_parsed(arg0); 3845 } 3846 3847 /** Global parser instance (cmdline API). */ 3848 cmdline_parse_inst_t cmd_flow = { 3849 .f = cmd_flow_cb, 3850 .data = NULL, /**< Unused. */ 3851 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */ 3852 .tokens = { 3853 NULL, 3854 }, /**< Tokens are returned by cmd_flow_tok(). */ 3855 }; 3856