4 * Copyright 2016 6WIND S.A.
5 * Copyright 2016 Mellanox.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of 6WIND S.A. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include <rte_common.h>
43 #include <rte_ethdev.h>
44 #include <rte_byteorder.h>
45 #include <cmdline_parse.h>
46 #include <cmdline_parse_etheraddr.h>
51 /** Parser token indices. */
69 /* Top-level command. */
72 /* Sub-level commands. */
80 /* Destroy arguments. */
83 /* Query arguments. */
89 /* Validate/create arguments. */
95 /* Validate/create pattern. */
127 /* Validate/create actions. */
135 /** Size of pattern[] field in struct rte_flow_item_raw. */
136 #define ITEM_RAW_PATTERN_SIZE 36
138 /** Storage size for struct rte_flow_item_raw including pattern. */
139 #define ITEM_RAW_SIZE \
140 (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
142 /** Maximum number of subsequent tokens and arguments on the stack. */
143 #define CTX_STACK_SIZE 16
145 /** Parser context. */
147 /** Stack of subsequent token lists to process. */
148 const enum index *next[CTX_STACK_SIZE];
149 /** Arguments for stacked tokens. */
150 const void *args[CTX_STACK_SIZE];
151 enum index curr; /**< Current token index. */
152 enum index prev; /**< Index of the last token seen. */
153 int next_num; /**< Number of entries in next[]. */
154 int args_num; /**< Number of entries in args[]. */
155 uint32_t reparse:1; /**< Start over from the beginning. */
156 uint32_t eol:1; /**< EOL has been detected. */
157 uint32_t last:1; /**< No more arguments. */
158 uint16_t port; /**< Current port ID (for completions). */
159 uint32_t objdata; /**< Object-specific data. */
160 void *object; /**< Address of current object for relative offsets. */
161 void *objmask; /**< Object a full mask must be written to. */
164 /** Token argument. */
166 uint32_t hton:1; /**< Use network byte ordering. */
167 uint32_t sign:1; /**< Value is signed. */
168 uint32_t offset; /**< Relative offset from ctx->object. */
169 uint32_t size; /**< Field size. */
170 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
173 /** Parser token definition. */
175 /** Type displayed during completion (defaults to "TOKEN"). */
177 /** Help displayed during completion (defaults to token name). */
179 /** Private data used by parser functions. */
182 * Lists of subsequent tokens to push on the stack. Each call to the
183 * parser consumes the last entry of that stack.
185 const enum index *const *next;
186 /** Arguments stack for subsequent tokens that need them. */
187 const struct arg *const *args;
189 * Token-processing callback, returns -1 in case of error, the
190 * length of the matched string otherwise. If NULL, attempts to
191 * match the token name.
193 * If buf is not NULL, the result should be stored in it according
194 * to context. An error is returned if not large enough.
196 int (*call)(struct context *ctx, const struct token *token,
197 const char *str, unsigned int len,
198 void *buf, unsigned int size);
200 * Callback that provides possible values for this token, used for
201 * completion. Returns -1 in case of error, the number of possible
202 * values otherwise. If NULL, the token name is used.
204 * If buf is not NULL, entry index ent is written to buf and the
205 * full length of the entry is returned (same behavior as
208 int (*comp)(struct context *ctx, const struct token *token,
209 unsigned int ent, char *buf, unsigned int size);
210 /** Mandatory token name, no default value. */
214 /** Static initializer for the next field. */
215 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
217 /** Static initializer for a NEXT() entry. */
218 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
220 /** Static initializer for the args field. */
221 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
223 /** Static initializer for ARGS() to target a field. */
224 #define ARGS_ENTRY(s, f) \
225 (&(const struct arg){ \
226 .offset = offsetof(s, f), \
227 .size = sizeof(((s *)0)->f), \
230 /** Static initializer for ARGS() to target a bit-field. */
231 #define ARGS_ENTRY_BF(s, f, b) \
232 (&(const struct arg){ \
234 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
237 /** Static initializer for ARGS() to target a pointer. */
238 #define ARGS_ENTRY_PTR(s, f) \
239 (&(const struct arg){ \
240 .size = sizeof(*((s *)0)->f), \
243 /** Static initializer for ARGS() with arbitrary size. */
244 #define ARGS_ENTRY_USZ(s, f, sz) \
245 (&(const struct arg){ \
246 .offset = offsetof(s, f), \
250 /** Same as ARGS_ENTRY() using network byte ordering. */
251 #define ARGS_ENTRY_HTON(s, f) \
252 (&(const struct arg){ \
254 .offset = offsetof(s, f), \
255 .size = sizeof(((s *)0)->f), \
258 /** Parser output buffer layout expected by cmd_flow_parsed(). */
260 enum index command; /**< Flow command. */
261 uint16_t port; /**< Affected port ID. */
264 struct rte_flow_attr attr;
265 struct rte_flow_item *pattern;
266 struct rte_flow_action *actions;
270 } vc; /**< Validate/create arguments. */
274 } destroy; /**< Destroy arguments. */
277 enum rte_flow_action_type action;
278 } query; /**< Query arguments. */
282 } list; /**< List arguments. */
283 } args; /**< Command arguments. */
286 /** Private data for pattern items. */
287 struct parse_item_priv {
288 enum rte_flow_item_type type; /**< Item type. */
289 uint32_t size; /**< Size of item specification structure. */
292 #define PRIV_ITEM(t, s) \
293 (&(const struct parse_item_priv){ \
294 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
298 /** Private data for actions. */
299 struct parse_action_priv {
300 enum rte_flow_action_type type; /**< Action type. */
301 uint32_t size; /**< Size of action configuration structure. */
304 #define PRIV_ACTION(t, s) \
305 (&(const struct parse_action_priv){ \
306 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
310 static const enum index next_vc_attr[] = {
319 static const enum index next_destroy_attr[] = {
325 static const enum index next_list_attr[] = {
331 static const enum index item_param[] = {
340 static const enum index next_item[] = {
354 static const enum index item_any[] = {
360 static const enum index item_vf[] = {
366 static const enum index item_port[] = {
372 static const enum index item_raw[] = {
382 static const enum index item_eth[] = {
390 static const enum index item_vlan[] = {
397 static const enum index next_action[] = {
404 static int parse_init(struct context *, const struct token *,
405 const char *, unsigned int,
406 void *, unsigned int);
407 static int parse_vc(struct context *, const struct token *,
408 const char *, unsigned int,
409 void *, unsigned int);
410 static int parse_vc_spec(struct context *, const struct token *,
411 const char *, unsigned int, void *, unsigned int);
412 static int parse_destroy(struct context *, const struct token *,
413 const char *, unsigned int,
414 void *, unsigned int);
415 static int parse_flush(struct context *, const struct token *,
416 const char *, unsigned int,
417 void *, unsigned int);
418 static int parse_query(struct context *, const struct token *,
419 const char *, unsigned int,
420 void *, unsigned int);
421 static int parse_action(struct context *, const struct token *,
422 const char *, unsigned int,
423 void *, unsigned int);
424 static int parse_list(struct context *, const struct token *,
425 const char *, unsigned int,
426 void *, unsigned int);
427 static int parse_int(struct context *, const struct token *,
428 const char *, unsigned int,
429 void *, unsigned int);
430 static int parse_prefix(struct context *, const struct token *,
431 const char *, unsigned int,
432 void *, unsigned int);
433 static int parse_boolean(struct context *, const struct token *,
434 const char *, unsigned int,
435 void *, unsigned int);
436 static int parse_string(struct context *, const struct token *,
437 const char *, unsigned int,
438 void *, unsigned int);
439 static int parse_mac_addr(struct context *, const struct token *,
440 const char *, unsigned int,
441 void *, unsigned int);
442 static int parse_port(struct context *, const struct token *,
443 const char *, unsigned int,
444 void *, unsigned int);
445 static int comp_none(struct context *, const struct token *,
446 unsigned int, char *, unsigned int);
447 static int comp_boolean(struct context *, const struct token *,
448 unsigned int, char *, unsigned int);
449 static int comp_action(struct context *, const struct token *,
450 unsigned int, char *, unsigned int);
451 static int comp_port(struct context *, const struct token *,
452 unsigned int, char *, unsigned int);
453 static int comp_rule_id(struct context *, const struct token *,
454 unsigned int, char *, unsigned int);
456 /** Token definitions. */
457 static const struct token token_list[] = {
458 /* Special tokens. */
461 .help = "null entry, abused as the entry point",
462 .next = NEXT(NEXT_ENTRY(FLOW)),
467 .help = "command may end here",
473 .help = "integer value",
478 .name = "{unsigned}",
480 .help = "unsigned integer value",
487 .help = "prefix length for bit-mask",
488 .call = parse_prefix,
494 .help = "any boolean value",
495 .call = parse_boolean,
496 .comp = comp_boolean,
501 .help = "fixed string",
502 .call = parse_string,
506 .name = "{MAC address}",
508 .help = "standard MAC address notation",
509 .call = parse_mac_addr,
515 .help = "rule identifier",
517 .comp = comp_rule_id,
522 .help = "port identifier",
527 .name = "{group_id}",
529 .help = "group identifier",
536 .help = "priority level",
540 /* Top-level command. */
543 .type = "{command} {port_id} [{arg} [...]]",
544 .help = "manage ingress/egress flow rules",
545 .next = NEXT(NEXT_ENTRY
554 /* Sub-level commands. */
557 .help = "check whether a flow rule can be created",
558 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
559 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
564 .help = "create a flow rule",
565 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
566 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
571 .help = "destroy specific flow rules",
572 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
573 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
574 .call = parse_destroy,
578 .help = "destroy all flow rules",
579 .next = NEXT(NEXT_ENTRY(PORT_ID)),
580 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
585 .help = "query an existing flow rule",
586 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
588 NEXT_ENTRY(PORT_ID)),
589 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
590 ARGS_ENTRY(struct buffer, args.query.rule),
591 ARGS_ENTRY(struct buffer, port)),
596 .help = "list existing flow rules",
597 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
598 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
601 /* Destroy arguments. */
604 .help = "specify a rule identifier",
605 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
606 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
607 .call = parse_destroy,
609 /* Query arguments. */
613 .help = "action to query, must be part of the rule",
614 .call = parse_action,
617 /* List arguments. */
620 .help = "specify a group",
621 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
622 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
625 /* Validate/create attributes. */
628 .help = "specify a group",
629 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
630 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
635 .help = "specify a priority level",
636 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
637 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
642 .help = "affect rule to ingress",
643 .next = NEXT(next_vc_attr),
648 .help = "affect rule to egress",
649 .next = NEXT(next_vc_attr),
652 /* Validate/create pattern. */
655 .help = "submit a list of pattern items",
656 .next = NEXT(next_item),
661 .help = "match value perfectly (with full bit-mask)",
662 .call = parse_vc_spec,
664 [ITEM_PARAM_SPEC] = {
666 .help = "match value according to configured bit-mask",
667 .call = parse_vc_spec,
669 [ITEM_PARAM_LAST] = {
671 .help = "specify upper bound to establish a range",
672 .call = parse_vc_spec,
674 [ITEM_PARAM_MASK] = {
676 .help = "specify bit-mask with relevant bits set to one",
677 .call = parse_vc_spec,
679 [ITEM_PARAM_PREFIX] = {
681 .help = "generate bit-mask from a prefix length",
682 .call = parse_vc_spec,
686 .help = "specify next pattern item",
687 .next = NEXT(next_item),
691 .help = "end list of pattern items",
692 .priv = PRIV_ITEM(END, 0),
693 .next = NEXT(NEXT_ENTRY(ACTIONS)),
698 .help = "no-op pattern item",
699 .priv = PRIV_ITEM(VOID, 0),
700 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
705 .help = "perform actions when pattern does not match",
706 .priv = PRIV_ITEM(INVERT, 0),
707 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
712 .help = "match any protocol for the current layer",
713 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
714 .next = NEXT(item_any),
719 .help = "number of layers covered",
720 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
721 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
725 .help = "match packets addressed to the physical function",
726 .priv = PRIV_ITEM(PF, 0),
727 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
732 .help = "match packets addressed to a virtual function ID",
733 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
734 .next = NEXT(item_vf),
739 .help = "destination VF ID",
740 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
741 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
745 .help = "device-specific physical port index to use",
746 .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)),
747 .next = NEXT(item_port),
750 [ITEM_PORT_INDEX] = {
752 .help = "physical port index",
753 .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param),
754 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)),
758 .help = "match an arbitrary byte string",
759 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
760 .next = NEXT(item_raw),
763 [ITEM_RAW_RELATIVE] = {
765 .help = "look for pattern after the previous item",
766 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
767 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
770 [ITEM_RAW_SEARCH] = {
772 .help = "search pattern from offset (see also limit)",
773 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
774 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
777 [ITEM_RAW_OFFSET] = {
779 .help = "absolute or relative offset for pattern",
780 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
781 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
785 .help = "search area limit for start of pattern",
786 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
787 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
789 [ITEM_RAW_PATTERN] = {
791 .help = "byte string to look for",
792 .next = NEXT(item_raw,
794 NEXT_ENTRY(ITEM_PARAM_IS,
797 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length),
798 ARGS_ENTRY_USZ(struct rte_flow_item_raw,
800 ITEM_RAW_PATTERN_SIZE)),
804 .help = "match Ethernet header",
805 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
806 .next = NEXT(item_eth),
811 .help = "destination MAC",
812 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
813 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, dst)),
817 .help = "source MAC",
818 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
819 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, src)),
824 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
825 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
829 .help = "match 802.1Q/ad VLAN tag",
830 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
831 .next = NEXT(item_vlan),
836 .help = "tag protocol identifier",
837 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
838 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)),
842 .help = "tag control information",
843 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
844 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
846 /* Validate/create actions. */
849 .help = "submit a list of associated actions",
850 .next = NEXT(next_action),
855 .help = "specify next action",
856 .next = NEXT(next_action),
860 .help = "end list of actions",
861 .priv = PRIV_ACTION(END, 0),
866 .help = "no-op action",
867 .priv = PRIV_ACTION(VOID, 0),
868 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
871 [ACTION_PASSTHRU] = {
873 .help = "let subsequent rule process matched packets",
874 .priv = PRIV_ACTION(PASSTHRU, 0),
875 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
880 /** Remove and return last entry from argument stack. */
881 static const struct arg *
882 pop_args(struct context *ctx)
884 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
887 /** Add entry on top of the argument stack. */
889 push_args(struct context *ctx, const struct arg *arg)
891 if (ctx->args_num == CTX_STACK_SIZE)
893 ctx->args[ctx->args_num++] = arg;
897 /** Spread value into buffer according to bit-mask. */
899 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
901 uint32_t i = arg->size;
909 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
918 unsigned int shift = 0;
919 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
921 for (shift = 0; arg->mask[i] >> shift; ++shift) {
922 if (!(arg->mask[i] & (1 << shift)))
927 *buf &= ~(1 << shift);
928 *buf |= (val & 1) << shift;
937 * Parse a prefix length and generate a bit-mask.
939 * Last argument (ctx->args) is retrieved to determine mask size, storage
940 * location and whether the result must use network byte ordering.
943 parse_prefix(struct context *ctx, const struct token *token,
944 const char *str, unsigned int len,
945 void *buf, unsigned int size)
947 const struct arg *arg = pop_args(ctx);
948 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
955 /* Argument is expected. */
959 u = strtoumax(str, &end, 0);
960 if (errno || (size_t)(end - str) != len)
965 extra = arg_entry_bf_fill(NULL, 0, arg);
974 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
975 !arg_entry_bf_fill(ctx->objmask, -1, arg))
982 if (bytes > size || bytes + !!extra > size)
986 buf = (uint8_t *)ctx->object + arg->offset;
987 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
989 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
990 memset(buf, 0x00, size - bytes);
992 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
996 memset(buf, 0xff, bytes);
997 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
999 ((uint8_t *)buf)[bytes] = conv[extra];
1002 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
1005 push_args(ctx, arg);
1009 /** Default parsing function for token name matching. */
1011 parse_default(struct context *ctx, const struct token *token,
1012 const char *str, unsigned int len,
1013 void *buf, unsigned int size)
1018 if (strncmp(str, token->name, len))
1023 /** Parse flow command, initialize output buffer for subsequent tokens. */
1025 parse_init(struct context *ctx, const struct token *token,
1026 const char *str, unsigned int len,
1027 void *buf, unsigned int size)
1029 struct buffer *out = buf;
1031 /* Token name must match. */
1032 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1034 /* Nothing else to do if there is no buffer. */
1037 /* Make sure buffer is large enough. */
1038 if (size < sizeof(*out))
1040 /* Initialize buffer. */
1041 memset(out, 0x00, sizeof(*out));
1042 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
1045 ctx->objmask = NULL;
1049 /** Parse tokens for validate/create commands. */
1051 parse_vc(struct context *ctx, const struct token *token,
1052 const char *str, unsigned int len,
1053 void *buf, unsigned int size)
1055 struct buffer *out = buf;
1059 /* Token name must match. */
1060 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1062 /* Nothing else to do if there is no buffer. */
1065 if (!out->command) {
1066 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
1068 if (sizeof(*out) > size)
1070 out->command = ctx->curr;
1073 ctx->objmask = NULL;
1074 out->args.vc.data = (uint8_t *)out + size;
1078 ctx->object = &out->args.vc.attr;
1079 ctx->objmask = NULL;
1080 switch (ctx->curr) {
1085 out->args.vc.attr.ingress = 1;
1088 out->args.vc.attr.egress = 1;
1091 out->args.vc.pattern =
1092 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1094 ctx->object = out->args.vc.pattern;
1095 ctx->objmask = NULL;
1098 out->args.vc.actions =
1099 (void *)RTE_ALIGN_CEIL((uintptr_t)
1100 (out->args.vc.pattern +
1101 out->args.vc.pattern_n),
1103 ctx->object = out->args.vc.actions;
1104 ctx->objmask = NULL;
1111 if (!out->args.vc.actions) {
1112 const struct parse_item_priv *priv = token->priv;
1113 struct rte_flow_item *item =
1114 out->args.vc.pattern + out->args.vc.pattern_n;
1116 data_size = priv->size * 3; /* spec, last, mask */
1117 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
1118 (out->args.vc.data - data_size),
1120 if ((uint8_t *)item + sizeof(*item) > data)
1122 *item = (struct rte_flow_item){
1125 ++out->args.vc.pattern_n;
1127 ctx->objmask = NULL;
1129 const struct parse_action_priv *priv = token->priv;
1130 struct rte_flow_action *action =
1131 out->args.vc.actions + out->args.vc.actions_n;
1133 data_size = priv->size; /* configuration */
1134 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
1135 (out->args.vc.data - data_size),
1137 if ((uint8_t *)action + sizeof(*action) > data)
1139 *action = (struct rte_flow_action){
1142 ++out->args.vc.actions_n;
1143 ctx->object = action;
1144 ctx->objmask = NULL;
1146 memset(data, 0, data_size);
1147 out->args.vc.data = data;
1148 ctx->objdata = data_size;
1152 /** Parse pattern item parameter type. */
1154 parse_vc_spec(struct context *ctx, const struct token *token,
1155 const char *str, unsigned int len,
1156 void *buf, unsigned int size)
1158 struct buffer *out = buf;
1159 struct rte_flow_item *item;
1165 /* Token name must match. */
1166 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1168 /* Parse parameter types. */
1169 switch (ctx->curr) {
1174 case ITEM_PARAM_SPEC:
1177 case ITEM_PARAM_LAST:
1180 case ITEM_PARAM_PREFIX:
1181 /* Modify next token to expect a prefix. */
1182 if (ctx->next_num < 2)
1184 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
1186 case ITEM_PARAM_MASK:
1192 /* Nothing else to do if there is no buffer. */
1195 if (!out->args.vc.pattern_n)
1197 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
1198 data_size = ctx->objdata / 3; /* spec, last, mask */
1199 /* Point to selected object. */
1200 ctx->object = out->args.vc.data + (data_size * index);
1202 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
1203 item->mask = ctx->objmask;
1205 ctx->objmask = NULL;
1206 /* Update relevant item pointer. */
1207 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
1212 /** Parse tokens for destroy command. */
1214 parse_destroy(struct context *ctx, const struct token *token,
1215 const char *str, unsigned int len,
1216 void *buf, unsigned int size)
1218 struct buffer *out = buf;
1220 /* Token name must match. */
1221 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1223 /* Nothing else to do if there is no buffer. */
1226 if (!out->command) {
1227 if (ctx->curr != DESTROY)
1229 if (sizeof(*out) > size)
1231 out->command = ctx->curr;
1234 ctx->objmask = NULL;
1235 out->args.destroy.rule =
1236 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1240 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
1241 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
1244 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
1245 ctx->objmask = NULL;
1249 /** Parse tokens for flush command. */
1251 parse_flush(struct context *ctx, const struct token *token,
1252 const char *str, unsigned int len,
1253 void *buf, unsigned int size)
1255 struct buffer *out = buf;
1257 /* Token name must match. */
1258 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1260 /* Nothing else to do if there is no buffer. */
1263 if (!out->command) {
1264 if (ctx->curr != FLUSH)
1266 if (sizeof(*out) > size)
1268 out->command = ctx->curr;
1271 ctx->objmask = NULL;
1276 /** Parse tokens for query command. */
1278 parse_query(struct context *ctx, const struct token *token,
1279 const char *str, unsigned int len,
1280 void *buf, unsigned int size)
1282 struct buffer *out = buf;
1284 /* Token name must match. */
1285 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1287 /* Nothing else to do if there is no buffer. */
1290 if (!out->command) {
1291 if (ctx->curr != QUERY)
1293 if (sizeof(*out) > size)
1295 out->command = ctx->curr;
1298 ctx->objmask = NULL;
1303 /** Parse action names. */
1305 parse_action(struct context *ctx, const struct token *token,
1306 const char *str, unsigned int len,
1307 void *buf, unsigned int size)
1309 struct buffer *out = buf;
1310 const struct arg *arg = pop_args(ctx);
1314 /* Argument is expected. */
1317 /* Parse action name. */
1318 for (i = 0; next_action[i]; ++i) {
1319 const struct parse_action_priv *priv;
1321 token = &token_list[next_action[i]];
1322 if (strncmp(token->name, str, len))
1328 memcpy((uint8_t *)ctx->object + arg->offset,
1334 push_args(ctx, arg);
1338 /** Parse tokens for list command. */
1340 parse_list(struct context *ctx, const struct token *token,
1341 const char *str, unsigned int len,
1342 void *buf, unsigned int size)
1344 struct buffer *out = buf;
1346 /* Token name must match. */
1347 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1349 /* Nothing else to do if there is no buffer. */
1352 if (!out->command) {
1353 if (ctx->curr != LIST)
1355 if (sizeof(*out) > size)
1357 out->command = ctx->curr;
1360 ctx->objmask = NULL;
1361 out->args.list.group =
1362 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1366 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
1367 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
1370 ctx->object = out->args.list.group + out->args.list.group_n++;
1371 ctx->objmask = NULL;
1376 * Parse signed/unsigned integers 8 to 64-bit long.
1378 * Last argument (ctx->args) is retrieved to determine integer type and
1382 parse_int(struct context *ctx, const struct token *token,
1383 const char *str, unsigned int len,
1384 void *buf, unsigned int size)
1386 const struct arg *arg = pop_args(ctx);
1391 /* Argument is expected. */
1396 (uintmax_t)strtoimax(str, &end, 0) :
1397 strtoumax(str, &end, 0);
1398 if (errno || (size_t)(end - str) != len)
1403 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
1404 !arg_entry_bf_fill(ctx->objmask, -1, arg))
1408 buf = (uint8_t *)ctx->object + arg->offset;
1412 case sizeof(uint8_t):
1413 *(uint8_t *)buf = u;
1415 case sizeof(uint16_t):
1416 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1418 case sizeof(uint32_t):
1419 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1421 case sizeof(uint64_t):
1422 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1427 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1429 buf = (uint8_t *)ctx->objmask + arg->offset;
1434 push_args(ctx, arg);
1441 * Two arguments (ctx->args) are retrieved from the stack to store data and
1442 * its length (in that order).
1445 parse_string(struct context *ctx, const struct token *token,
1446 const char *str, unsigned int len,
1447 void *buf, unsigned int size)
1449 const struct arg *arg_data = pop_args(ctx);
1450 const struct arg *arg_len = pop_args(ctx);
1451 char tmp[16]; /* Ought to be enough. */
1454 /* Arguments are expected. */
1458 push_args(ctx, arg_data);
1461 size = arg_data->size;
1462 /* Bit-mask fill is not supported. */
1463 if (arg_data->mask || size < len)
1467 /* Let parse_int() fill length information first. */
1468 ret = snprintf(tmp, sizeof(tmp), "%u", len);
1471 push_args(ctx, arg_len);
1472 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
1477 buf = (uint8_t *)ctx->object + arg_data->offset;
1478 /* Output buffer is not necessarily NUL-terminated. */
1479 memcpy(buf, str, len);
1480 memset((uint8_t *)buf + len, 0x55, size - len);
1482 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
1485 push_args(ctx, arg_len);
1486 push_args(ctx, arg_data);
1491 * Parse a MAC address.
1493 * Last argument (ctx->args) is retrieved to determine storage size and
1497 parse_mac_addr(struct context *ctx, const struct token *token,
1498 const char *str, unsigned int len,
1499 void *buf, unsigned int size)
1501 const struct arg *arg = pop_args(ctx);
1502 struct ether_addr tmp;
1506 /* Argument is expected. */
1510 /* Bit-mask fill is not supported. */
1511 if (arg->mask || size != sizeof(tmp))
1513 ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
1514 if (ret < 0 || (unsigned int)ret != len)
1518 buf = (uint8_t *)ctx->object + arg->offset;
1519 memcpy(buf, &tmp, size);
1521 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
1524 push_args(ctx, arg);
1528 /** Boolean values (even indices stand for false). */
1529 static const char *const boolean_name[] = {
1538 * Parse a boolean value.
1540 * Last argument (ctx->args) is retrieved to determine storage size and
1544 parse_boolean(struct context *ctx, const struct token *token,
1545 const char *str, unsigned int len,
1546 void *buf, unsigned int size)
1548 const struct arg *arg = pop_args(ctx);
1552 /* Argument is expected. */
1555 for (i = 0; boolean_name[i]; ++i)
1556 if (!strncmp(str, boolean_name[i], len))
1558 /* Process token as integer. */
1559 if (boolean_name[i])
1560 str = i & 1 ? "1" : "0";
1561 push_args(ctx, arg);
1562 ret = parse_int(ctx, token, str, strlen(str), buf, size);
1563 return ret > 0 ? (int)len : ret;
1566 /** Parse port and update context. */
1568 parse_port(struct context *ctx, const struct token *token,
1569 const char *str, unsigned int len,
1570 void *buf, unsigned int size)
1572 struct buffer *out = &(struct buffer){ .port = 0 };
1580 ctx->objmask = NULL;
1581 size = sizeof(*out);
1583 ret = parse_int(ctx, token, str, len, out, size);
1585 ctx->port = out->port;
1591 /** No completion. */
1593 comp_none(struct context *ctx, const struct token *token,
1594 unsigned int ent, char *buf, unsigned int size)
1604 /** Complete boolean values. */
1606 comp_boolean(struct context *ctx, const struct token *token,
1607 unsigned int ent, char *buf, unsigned int size)
1613 for (i = 0; boolean_name[i]; ++i)
1614 if (buf && i == ent)
1615 return snprintf(buf, size, "%s", boolean_name[i]);
1621 /** Complete action names. */
1623 comp_action(struct context *ctx, const struct token *token,
1624 unsigned int ent, char *buf, unsigned int size)
1630 for (i = 0; next_action[i]; ++i)
1631 if (buf && i == ent)
1632 return snprintf(buf, size, "%s",
1633 token_list[next_action[i]].name);
1639 /** Complete available ports. */
1641 comp_port(struct context *ctx, const struct token *token,
1642 unsigned int ent, char *buf, unsigned int size)
1649 FOREACH_PORT(p, ports) {
1650 if (buf && i == ent)
1651 return snprintf(buf, size, "%u", p);
1659 /** Complete available rule IDs. */
1661 comp_rule_id(struct context *ctx, const struct token *token,
1662 unsigned int ent, char *buf, unsigned int size)
1665 struct rte_port *port;
1666 struct port_flow *pf;
1669 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1670 ctx->port == (uint16_t)RTE_PORT_ALL)
1672 port = &ports[ctx->port];
1673 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1674 if (buf && i == ent)
1675 return snprintf(buf, size, "%u", pf->id);
1683 /** Internal context. */
1684 static struct context cmd_flow_context;
1686 /** Global parser instance (cmdline API). */
1687 cmdline_parse_inst_t cmd_flow;
1689 /** Initialize context. */
1691 cmd_flow_context_init(struct context *ctx)
1693 /* A full memset() is not necessary. */
1704 ctx->objmask = NULL;
1707 /** Parse a token (cmdline API). */
1709 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1712 struct context *ctx = &cmd_flow_context;
1713 const struct token *token;
1714 const enum index *list;
1719 /* Restart as requested. */
1721 cmd_flow_context_init(ctx);
1722 token = &token_list[ctx->curr];
1723 /* Check argument length. */
1726 for (len = 0; src[len]; ++len)
1727 if (src[len] == '#' || isspace(src[len]))
1731 /* Last argument and EOL detection. */
1732 for (i = len; src[i]; ++i)
1733 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1735 else if (!isspace(src[i])) {
1740 if (src[i] == '\r' || src[i] == '\n') {
1744 /* Initialize context if necessary. */
1745 if (!ctx->next_num) {
1748 ctx->next[ctx->next_num++] = token->next[0];
1750 /* Process argument through candidates. */
1751 ctx->prev = ctx->curr;
1752 list = ctx->next[ctx->next_num - 1];
1753 for (i = 0; list[i]; ++i) {
1754 const struct token *next = &token_list[list[i]];
1757 ctx->curr = list[i];
1759 tmp = next->call(ctx, next, src, len, result, size);
1761 tmp = parse_default(ctx, next, src, len, result, size);
1762 if (tmp == -1 || tmp != len)
1770 /* Push subsequent tokens if any. */
1772 for (i = 0; token->next[i]; ++i) {
1773 if (ctx->next_num == RTE_DIM(ctx->next))
1775 ctx->next[ctx->next_num++] = token->next[i];
1777 /* Push arguments if any. */
1779 for (i = 0; token->args[i]; ++i) {
1780 if (ctx->args_num == RTE_DIM(ctx->args))
1782 ctx->args[ctx->args_num++] = token->args[i];
1787 /** Return number of completion entries (cmdline API). */
1789 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1791 struct context *ctx = &cmd_flow_context;
1792 const struct token *token = &token_list[ctx->curr];
1793 const enum index *list;
1797 /* Tell cmd_flow_parse() that context must be reinitialized. */
1799 /* Count number of tokens in current list. */
1801 list = ctx->next[ctx->next_num - 1];
1803 list = token->next[0];
1804 for (i = 0; list[i]; ++i)
1809 * If there is a single token, use its completion callback, otherwise
1810 * return the number of entries.
1812 token = &token_list[list[0]];
1813 if (i == 1 && token->comp) {
1814 /* Save index for cmd_flow_get_help(). */
1815 ctx->prev = list[0];
1816 return token->comp(ctx, token, 0, NULL, 0);
1821 /** Return a completion entry (cmdline API). */
1823 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1824 char *dst, unsigned int size)
1826 struct context *ctx = &cmd_flow_context;
1827 const struct token *token = &token_list[ctx->curr];
1828 const enum index *list;
1832 /* Tell cmd_flow_parse() that context must be reinitialized. */
1834 /* Count number of tokens in current list. */
1836 list = ctx->next[ctx->next_num - 1];
1838 list = token->next[0];
1839 for (i = 0; list[i]; ++i)
1843 /* If there is a single token, use its completion callback. */
1844 token = &token_list[list[0]];
1845 if (i == 1 && token->comp) {
1846 /* Save index for cmd_flow_get_help(). */
1847 ctx->prev = list[0];
1848 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1850 /* Otherwise make sure the index is valid and use defaults. */
1853 token = &token_list[list[index]];
1854 snprintf(dst, size, "%s", token->name);
1855 /* Save index for cmd_flow_get_help(). */
1856 ctx->prev = list[index];
1860 /** Populate help strings for current token (cmdline API). */
1862 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1864 struct context *ctx = &cmd_flow_context;
1865 const struct token *token = &token_list[ctx->prev];
1868 /* Tell cmd_flow_parse() that context must be reinitialized. */
1872 /* Set token type and update global help with details. */
1873 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1875 cmd_flow.help_str = token->help;
1877 cmd_flow.help_str = token->name;
1881 /** Token definition template (cmdline API). */
1882 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1883 .ops = &(struct cmdline_token_ops){
1884 .parse = cmd_flow_parse,
1885 .complete_get_nb = cmd_flow_complete_get_nb,
1886 .complete_get_elt = cmd_flow_complete_get_elt,
1887 .get_help = cmd_flow_get_help,
1892 /** Populate the next dynamic token. */
1894 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1895 cmdline_parse_token_hdr_t *(*hdrs)[])
1897 struct context *ctx = &cmd_flow_context;
1899 /* Always reinitialize context before requesting the first token. */
1901 cmd_flow_context_init(ctx);
1902 /* Return NULL when no more tokens are expected. */
1903 if (!ctx->next_num && ctx->curr) {
1907 /* Determine if command should end here. */
1908 if (ctx->eol && ctx->last && ctx->next_num) {
1909 const enum index *list = ctx->next[ctx->next_num - 1];
1912 for (i = 0; list[i]; ++i) {
1919 *hdr = &cmd_flow_token_hdr;
1922 /** Dispatch parsed buffer to function calls. */
1924 cmd_flow_parsed(const struct buffer *in)
1926 switch (in->command) {
1928 port_flow_validate(in->port, &in->args.vc.attr,
1929 in->args.vc.pattern, in->args.vc.actions);
1932 port_flow_create(in->port, &in->args.vc.attr,
1933 in->args.vc.pattern, in->args.vc.actions);
1936 port_flow_destroy(in->port, in->args.destroy.rule_n,
1937 in->args.destroy.rule);
1940 port_flow_flush(in->port);
1943 port_flow_query(in->port, in->args.query.rule,
1944 in->args.query.action);
1947 port_flow_list(in->port, in->args.list.group_n,
1948 in->args.list.group);
1955 /** Token generator and output processing callback (cmdline API). */
1957 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1960 cmd_flow_tok(arg0, arg2);
1962 cmd_flow_parsed(arg0);
1965 /** Global parser instance (cmdline API). */
1966 cmdline_parse_inst_t cmd_flow = {
1968 .data = NULL, /**< Unused. */
1969 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1972 }, /**< Tokens are returned by cmd_flow_tok(). */