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