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