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>
50 /** Parser token indices. */
65 /* Top-level command. */
68 /* Sub-level commands. */
76 /* Destroy arguments. */
79 /* Query arguments. */
85 /* Validate/create arguments. */
91 /* Validate/create pattern. */
105 /* Validate/create actions. */
113 /** Maximum number of subsequent tokens and arguments on the stack. */
114 #define CTX_STACK_SIZE 16
116 /** Parser context. */
118 /** Stack of subsequent token lists to process. */
119 const enum index *next[CTX_STACK_SIZE];
120 /** Arguments for stacked tokens. */
121 const void *args[CTX_STACK_SIZE];
122 enum index curr; /**< Current token index. */
123 enum index prev; /**< Index of the last token seen. */
124 int next_num; /**< Number of entries in next[]. */
125 int args_num; /**< Number of entries in args[]. */
126 uint32_t reparse:1; /**< Start over from the beginning. */
127 uint32_t eol:1; /**< EOL has been detected. */
128 uint32_t last:1; /**< No more arguments. */
129 uint16_t port; /**< Current port ID (for completions). */
130 uint32_t objdata; /**< Object-specific data. */
131 void *object; /**< Address of current object for relative offsets. */
132 void *objmask; /**< Object a full mask must be written to. */
135 /** Token argument. */
137 uint32_t hton:1; /**< Use network byte ordering. */
138 uint32_t sign:1; /**< Value is signed. */
139 uint32_t offset; /**< Relative offset from ctx->object. */
140 uint32_t size; /**< Field size. */
141 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
144 /** Parser token definition. */
146 /** Type displayed during completion (defaults to "TOKEN"). */
148 /** Help displayed during completion (defaults to token name). */
150 /** Private data used by parser functions. */
153 * Lists of subsequent tokens to push on the stack. Each call to the
154 * parser consumes the last entry of that stack.
156 const enum index *const *next;
157 /** Arguments stack for subsequent tokens that need them. */
158 const struct arg *const *args;
160 * Token-processing callback, returns -1 in case of error, the
161 * length of the matched string otherwise. If NULL, attempts to
162 * match the token name.
164 * If buf is not NULL, the result should be stored in it according
165 * to context. An error is returned if not large enough.
167 int (*call)(struct context *ctx, const struct token *token,
168 const char *str, unsigned int len,
169 void *buf, unsigned int size);
171 * Callback that provides possible values for this token, used for
172 * completion. Returns -1 in case of error, the number of possible
173 * values otherwise. If NULL, the token name is used.
175 * If buf is not NULL, entry index ent is written to buf and the
176 * full length of the entry is returned (same behavior as
179 int (*comp)(struct context *ctx, const struct token *token,
180 unsigned int ent, char *buf, unsigned int size);
181 /** Mandatory token name, no default value. */
185 /** Static initializer for the next field. */
186 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
188 /** Static initializer for a NEXT() entry. */
189 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
191 /** Static initializer for the args field. */
192 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
194 /** Static initializer for ARGS() to target a field. */
195 #define ARGS_ENTRY(s, f) \
196 (&(const struct arg){ \
197 .offset = offsetof(s, f), \
198 .size = sizeof(((s *)0)->f), \
201 /** Static initializer for ARGS() to target a bit-field. */
202 #define ARGS_ENTRY_BF(s, f, b) \
203 (&(const struct arg){ \
205 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
208 /** Static initializer for ARGS() to target a pointer. */
209 #define ARGS_ENTRY_PTR(s, f) \
210 (&(const struct arg){ \
211 .size = sizeof(*((s *)0)->f), \
214 /** Parser output buffer layout expected by cmd_flow_parsed(). */
216 enum index command; /**< Flow command. */
217 uint16_t port; /**< Affected port ID. */
220 struct rte_flow_attr attr;
221 struct rte_flow_item *pattern;
222 struct rte_flow_action *actions;
226 } vc; /**< Validate/create arguments. */
230 } destroy; /**< Destroy arguments. */
233 enum rte_flow_action_type action;
234 } query; /**< Query arguments. */
238 } list; /**< List arguments. */
239 } args; /**< Command arguments. */
242 /** Private data for pattern items. */
243 struct parse_item_priv {
244 enum rte_flow_item_type type; /**< Item type. */
245 uint32_t size; /**< Size of item specification structure. */
248 #define PRIV_ITEM(t, s) \
249 (&(const struct parse_item_priv){ \
250 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
254 /** Private data for actions. */
255 struct parse_action_priv {
256 enum rte_flow_action_type type; /**< Action type. */
257 uint32_t size; /**< Size of action configuration structure. */
260 #define PRIV_ACTION(t, s) \
261 (&(const struct parse_action_priv){ \
262 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
266 static const enum index next_vc_attr[] = {
275 static const enum index next_destroy_attr[] = {
281 static const enum index next_list_attr[] = {
287 static const enum index item_param[] = {
296 static const enum index next_item[] = {
304 static const enum index item_any[] = {
310 static const enum index next_action[] = {
317 static int parse_init(struct context *, const struct token *,
318 const char *, unsigned int,
319 void *, unsigned int);
320 static int parse_vc(struct context *, const struct token *,
321 const char *, unsigned int,
322 void *, unsigned int);
323 static int parse_vc_spec(struct context *, const struct token *,
324 const char *, unsigned int, void *, unsigned int);
325 static int parse_destroy(struct context *, const struct token *,
326 const char *, unsigned int,
327 void *, unsigned int);
328 static int parse_flush(struct context *, const struct token *,
329 const char *, unsigned int,
330 void *, unsigned int);
331 static int parse_query(struct context *, const struct token *,
332 const char *, unsigned int,
333 void *, unsigned int);
334 static int parse_action(struct context *, const struct token *,
335 const char *, unsigned int,
336 void *, unsigned int);
337 static int parse_list(struct context *, const struct token *,
338 const char *, unsigned int,
339 void *, unsigned int);
340 static int parse_int(struct context *, const struct token *,
341 const char *, unsigned int,
342 void *, unsigned int);
343 static int parse_prefix(struct context *, const struct token *,
344 const char *, unsigned int,
345 void *, unsigned int);
346 static int parse_port(struct context *, const struct token *,
347 const char *, unsigned int,
348 void *, unsigned int);
349 static int comp_none(struct context *, const struct token *,
350 unsigned int, char *, unsigned int);
351 static int comp_action(struct context *, const struct token *,
352 unsigned int, char *, unsigned int);
353 static int comp_port(struct context *, const struct token *,
354 unsigned int, char *, unsigned int);
355 static int comp_rule_id(struct context *, const struct token *,
356 unsigned int, char *, unsigned int);
358 /** Token definitions. */
359 static const struct token token_list[] = {
360 /* Special tokens. */
363 .help = "null entry, abused as the entry point",
364 .next = NEXT(NEXT_ENTRY(FLOW)),
369 .help = "command may end here",
375 .help = "integer value",
380 .name = "{unsigned}",
382 .help = "unsigned integer value",
389 .help = "prefix length for bit-mask",
390 .call = parse_prefix,
396 .help = "rule identifier",
398 .comp = comp_rule_id,
403 .help = "port identifier",
408 .name = "{group_id}",
410 .help = "group identifier",
417 .help = "priority level",
421 /* Top-level command. */
424 .type = "{command} {port_id} [{arg} [...]]",
425 .help = "manage ingress/egress flow rules",
426 .next = NEXT(NEXT_ENTRY
435 /* Sub-level commands. */
438 .help = "check whether a flow rule can be created",
439 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
440 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
445 .help = "create a flow rule",
446 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
447 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
452 .help = "destroy specific flow rules",
453 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
454 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
455 .call = parse_destroy,
459 .help = "destroy all flow rules",
460 .next = NEXT(NEXT_ENTRY(PORT_ID)),
461 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
466 .help = "query an existing flow rule",
467 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
469 NEXT_ENTRY(PORT_ID)),
470 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
471 ARGS_ENTRY(struct buffer, args.query.rule),
472 ARGS_ENTRY(struct buffer, port)),
477 .help = "list existing flow rules",
478 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
479 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
482 /* Destroy arguments. */
485 .help = "specify a rule identifier",
486 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
487 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
488 .call = parse_destroy,
490 /* Query arguments. */
494 .help = "action to query, must be part of the rule",
495 .call = parse_action,
498 /* List arguments. */
501 .help = "specify a group",
502 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
503 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
506 /* Validate/create attributes. */
509 .help = "specify a group",
510 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
511 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
516 .help = "specify a priority level",
517 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
518 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
523 .help = "affect rule to ingress",
524 .next = NEXT(next_vc_attr),
529 .help = "affect rule to egress",
530 .next = NEXT(next_vc_attr),
533 /* Validate/create pattern. */
536 .help = "submit a list of pattern items",
537 .next = NEXT(next_item),
542 .help = "match value perfectly (with full bit-mask)",
543 .call = parse_vc_spec,
545 [ITEM_PARAM_SPEC] = {
547 .help = "match value according to configured bit-mask",
548 .call = parse_vc_spec,
550 [ITEM_PARAM_LAST] = {
552 .help = "specify upper bound to establish a range",
553 .call = parse_vc_spec,
555 [ITEM_PARAM_MASK] = {
557 .help = "specify bit-mask with relevant bits set to one",
558 .call = parse_vc_spec,
560 [ITEM_PARAM_PREFIX] = {
562 .help = "generate bit-mask from a prefix length",
563 .call = parse_vc_spec,
567 .help = "specify next pattern item",
568 .next = NEXT(next_item),
572 .help = "end list of pattern items",
573 .priv = PRIV_ITEM(END, 0),
574 .next = NEXT(NEXT_ENTRY(ACTIONS)),
579 .help = "no-op pattern item",
580 .priv = PRIV_ITEM(VOID, 0),
581 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
586 .help = "perform actions when pattern does not match",
587 .priv = PRIV_ITEM(INVERT, 0),
588 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
593 .help = "match any protocol for the current layer",
594 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
595 .next = NEXT(item_any),
600 .help = "number of layers covered",
601 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
602 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
604 /* Validate/create actions. */
607 .help = "submit a list of associated actions",
608 .next = NEXT(next_action),
613 .help = "specify next action",
614 .next = NEXT(next_action),
618 .help = "end list of actions",
619 .priv = PRIV_ACTION(END, 0),
624 .help = "no-op action",
625 .priv = PRIV_ACTION(VOID, 0),
626 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
629 [ACTION_PASSTHRU] = {
631 .help = "let subsequent rule process matched packets",
632 .priv = PRIV_ACTION(PASSTHRU, 0),
633 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
638 /** Remove and return last entry from argument stack. */
639 static const struct arg *
640 pop_args(struct context *ctx)
642 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
645 /** Add entry on top of the argument stack. */
647 push_args(struct context *ctx, const struct arg *arg)
649 if (ctx->args_num == CTX_STACK_SIZE)
651 ctx->args[ctx->args_num++] = arg;
655 /** Spread value into buffer according to bit-mask. */
657 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
659 uint32_t i = arg->size;
667 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
676 unsigned int shift = 0;
677 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
679 for (shift = 0; arg->mask[i] >> shift; ++shift) {
680 if (!(arg->mask[i] & (1 << shift)))
685 *buf &= ~(1 << shift);
686 *buf |= (val & 1) << shift;
695 * Parse a prefix length and generate a bit-mask.
697 * Last argument (ctx->args) is retrieved to determine mask size, storage
698 * location and whether the result must use network byte ordering.
701 parse_prefix(struct context *ctx, const struct token *token,
702 const char *str, unsigned int len,
703 void *buf, unsigned int size)
705 const struct arg *arg = pop_args(ctx);
706 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
713 /* Argument is expected. */
717 u = strtoumax(str, &end, 0);
718 if (errno || (size_t)(end - str) != len)
723 extra = arg_entry_bf_fill(NULL, 0, arg);
732 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
733 !arg_entry_bf_fill(ctx->objmask, -1, arg))
740 if (bytes > size || bytes + !!extra > size)
744 buf = (uint8_t *)ctx->object + arg->offset;
745 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
747 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
748 memset(buf, 0x00, size - bytes);
750 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
754 memset(buf, 0xff, bytes);
755 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
757 ((uint8_t *)buf)[bytes] = conv[extra];
760 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
767 /** Default parsing function for token name matching. */
769 parse_default(struct context *ctx, const struct token *token,
770 const char *str, unsigned int len,
771 void *buf, unsigned int size)
776 if (strncmp(str, token->name, len))
781 /** Parse flow command, initialize output buffer for subsequent tokens. */
783 parse_init(struct context *ctx, const struct token *token,
784 const char *str, unsigned int len,
785 void *buf, unsigned int size)
787 struct buffer *out = buf;
789 /* Token name must match. */
790 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
792 /* Nothing else to do if there is no buffer. */
795 /* Make sure buffer is large enough. */
796 if (size < sizeof(*out))
798 /* Initialize buffer. */
799 memset(out, 0x00, sizeof(*out));
800 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
807 /** Parse tokens for validate/create commands. */
809 parse_vc(struct context *ctx, const struct token *token,
810 const char *str, unsigned int len,
811 void *buf, unsigned int size)
813 struct buffer *out = buf;
817 /* Token name must match. */
818 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
820 /* Nothing else to do if there is no buffer. */
824 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
826 if (sizeof(*out) > size)
828 out->command = ctx->curr;
832 out->args.vc.data = (uint8_t *)out + size;
836 ctx->object = &out->args.vc.attr;
843 out->args.vc.attr.ingress = 1;
846 out->args.vc.attr.egress = 1;
849 out->args.vc.pattern =
850 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
852 ctx->object = out->args.vc.pattern;
856 out->args.vc.actions =
857 (void *)RTE_ALIGN_CEIL((uintptr_t)
858 (out->args.vc.pattern +
859 out->args.vc.pattern_n),
861 ctx->object = out->args.vc.actions;
869 if (!out->args.vc.actions) {
870 const struct parse_item_priv *priv = token->priv;
871 struct rte_flow_item *item =
872 out->args.vc.pattern + out->args.vc.pattern_n;
874 data_size = priv->size * 3; /* spec, last, mask */
875 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
876 (out->args.vc.data - data_size),
878 if ((uint8_t *)item + sizeof(*item) > data)
880 *item = (struct rte_flow_item){
883 ++out->args.vc.pattern_n;
887 const struct parse_action_priv *priv = token->priv;
888 struct rte_flow_action *action =
889 out->args.vc.actions + out->args.vc.actions_n;
891 data_size = priv->size; /* configuration */
892 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
893 (out->args.vc.data - data_size),
895 if ((uint8_t *)action + sizeof(*action) > data)
897 *action = (struct rte_flow_action){
900 ++out->args.vc.actions_n;
901 ctx->object = action;
904 memset(data, 0, data_size);
905 out->args.vc.data = data;
906 ctx->objdata = data_size;
910 /** Parse pattern item parameter type. */
912 parse_vc_spec(struct context *ctx, const struct token *token,
913 const char *str, unsigned int len,
914 void *buf, unsigned int size)
916 struct buffer *out = buf;
917 struct rte_flow_item *item;
923 /* Token name must match. */
924 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
926 /* Parse parameter types. */
932 case ITEM_PARAM_SPEC:
935 case ITEM_PARAM_LAST:
938 case ITEM_PARAM_PREFIX:
939 /* Modify next token to expect a prefix. */
940 if (ctx->next_num < 2)
942 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
944 case ITEM_PARAM_MASK:
950 /* Nothing else to do if there is no buffer. */
953 if (!out->args.vc.pattern_n)
955 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
956 data_size = ctx->objdata / 3; /* spec, last, mask */
957 /* Point to selected object. */
958 ctx->object = out->args.vc.data + (data_size * index);
960 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
961 item->mask = ctx->objmask;
964 /* Update relevant item pointer. */
965 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
970 /** Parse tokens for destroy command. */
972 parse_destroy(struct context *ctx, const struct token *token,
973 const char *str, unsigned int len,
974 void *buf, unsigned int size)
976 struct buffer *out = buf;
978 /* Token name must match. */
979 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
981 /* Nothing else to do if there is no buffer. */
985 if (ctx->curr != DESTROY)
987 if (sizeof(*out) > size)
989 out->command = ctx->curr;
993 out->args.destroy.rule =
994 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
998 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
999 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
1002 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
1003 ctx->objmask = NULL;
1007 /** Parse tokens for flush command. */
1009 parse_flush(struct context *ctx, const struct token *token,
1010 const char *str, unsigned int len,
1011 void *buf, unsigned int size)
1013 struct buffer *out = buf;
1015 /* Token name must match. */
1016 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1018 /* Nothing else to do if there is no buffer. */
1021 if (!out->command) {
1022 if (ctx->curr != FLUSH)
1024 if (sizeof(*out) > size)
1026 out->command = ctx->curr;
1029 ctx->objmask = NULL;
1034 /** Parse tokens for query command. */
1036 parse_query(struct context *ctx, const struct token *token,
1037 const char *str, unsigned int len,
1038 void *buf, unsigned int size)
1040 struct buffer *out = buf;
1042 /* Token name must match. */
1043 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1045 /* Nothing else to do if there is no buffer. */
1048 if (!out->command) {
1049 if (ctx->curr != QUERY)
1051 if (sizeof(*out) > size)
1053 out->command = ctx->curr;
1056 ctx->objmask = NULL;
1061 /** Parse action names. */
1063 parse_action(struct context *ctx, const struct token *token,
1064 const char *str, unsigned int len,
1065 void *buf, unsigned int size)
1067 struct buffer *out = buf;
1068 const struct arg *arg = pop_args(ctx);
1072 /* Argument is expected. */
1075 /* Parse action name. */
1076 for (i = 0; next_action[i]; ++i) {
1077 const struct parse_action_priv *priv;
1079 token = &token_list[next_action[i]];
1080 if (strncmp(token->name, str, len))
1086 memcpy((uint8_t *)ctx->object + arg->offset,
1092 push_args(ctx, arg);
1096 /** Parse tokens for list command. */
1098 parse_list(struct context *ctx, const struct token *token,
1099 const char *str, unsigned int len,
1100 void *buf, unsigned int size)
1102 struct buffer *out = buf;
1104 /* Token name must match. */
1105 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1107 /* Nothing else to do if there is no buffer. */
1110 if (!out->command) {
1111 if (ctx->curr != LIST)
1113 if (sizeof(*out) > size)
1115 out->command = ctx->curr;
1118 ctx->objmask = NULL;
1119 out->args.list.group =
1120 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1124 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
1125 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
1128 ctx->object = out->args.list.group + out->args.list.group_n++;
1129 ctx->objmask = NULL;
1134 * Parse signed/unsigned integers 8 to 64-bit long.
1136 * Last argument (ctx->args) is retrieved to determine integer type and
1140 parse_int(struct context *ctx, const struct token *token,
1141 const char *str, unsigned int len,
1142 void *buf, unsigned int size)
1144 const struct arg *arg = pop_args(ctx);
1149 /* Argument is expected. */
1154 (uintmax_t)strtoimax(str, &end, 0) :
1155 strtoumax(str, &end, 0);
1156 if (errno || (size_t)(end - str) != len)
1161 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
1162 !arg_entry_bf_fill(ctx->objmask, -1, arg))
1166 buf = (uint8_t *)ctx->object + arg->offset;
1170 case sizeof(uint8_t):
1171 *(uint8_t *)buf = u;
1173 case sizeof(uint16_t):
1174 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1176 case sizeof(uint32_t):
1177 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1179 case sizeof(uint64_t):
1180 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1185 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1187 buf = (uint8_t *)ctx->objmask + arg->offset;
1192 push_args(ctx, arg);
1196 /** Parse port and update context. */
1198 parse_port(struct context *ctx, const struct token *token,
1199 const char *str, unsigned int len,
1200 void *buf, unsigned int size)
1202 struct buffer *out = &(struct buffer){ .port = 0 };
1210 ctx->objmask = NULL;
1211 size = sizeof(*out);
1213 ret = parse_int(ctx, token, str, len, out, size);
1215 ctx->port = out->port;
1221 /** No completion. */
1223 comp_none(struct context *ctx, const struct token *token,
1224 unsigned int ent, char *buf, unsigned int size)
1234 /** Complete action names. */
1236 comp_action(struct context *ctx, const struct token *token,
1237 unsigned int ent, char *buf, unsigned int size)
1243 for (i = 0; next_action[i]; ++i)
1244 if (buf && i == ent)
1245 return snprintf(buf, size, "%s",
1246 token_list[next_action[i]].name);
1252 /** Complete available ports. */
1254 comp_port(struct context *ctx, const struct token *token,
1255 unsigned int ent, char *buf, unsigned int size)
1262 FOREACH_PORT(p, ports) {
1263 if (buf && i == ent)
1264 return snprintf(buf, size, "%u", p);
1272 /** Complete available rule IDs. */
1274 comp_rule_id(struct context *ctx, const struct token *token,
1275 unsigned int ent, char *buf, unsigned int size)
1278 struct rte_port *port;
1279 struct port_flow *pf;
1282 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1283 ctx->port == (uint16_t)RTE_PORT_ALL)
1285 port = &ports[ctx->port];
1286 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1287 if (buf && i == ent)
1288 return snprintf(buf, size, "%u", pf->id);
1296 /** Internal context. */
1297 static struct context cmd_flow_context;
1299 /** Global parser instance (cmdline API). */
1300 cmdline_parse_inst_t cmd_flow;
1302 /** Initialize context. */
1304 cmd_flow_context_init(struct context *ctx)
1306 /* A full memset() is not necessary. */
1317 ctx->objmask = NULL;
1320 /** Parse a token (cmdline API). */
1322 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1325 struct context *ctx = &cmd_flow_context;
1326 const struct token *token;
1327 const enum index *list;
1332 /* Restart as requested. */
1334 cmd_flow_context_init(ctx);
1335 token = &token_list[ctx->curr];
1336 /* Check argument length. */
1339 for (len = 0; src[len]; ++len)
1340 if (src[len] == '#' || isspace(src[len]))
1344 /* Last argument and EOL detection. */
1345 for (i = len; src[i]; ++i)
1346 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1348 else if (!isspace(src[i])) {
1353 if (src[i] == '\r' || src[i] == '\n') {
1357 /* Initialize context if necessary. */
1358 if (!ctx->next_num) {
1361 ctx->next[ctx->next_num++] = token->next[0];
1363 /* Process argument through candidates. */
1364 ctx->prev = ctx->curr;
1365 list = ctx->next[ctx->next_num - 1];
1366 for (i = 0; list[i]; ++i) {
1367 const struct token *next = &token_list[list[i]];
1370 ctx->curr = list[i];
1372 tmp = next->call(ctx, next, src, len, result, size);
1374 tmp = parse_default(ctx, next, src, len, result, size);
1375 if (tmp == -1 || tmp != len)
1383 /* Push subsequent tokens if any. */
1385 for (i = 0; token->next[i]; ++i) {
1386 if (ctx->next_num == RTE_DIM(ctx->next))
1388 ctx->next[ctx->next_num++] = token->next[i];
1390 /* Push arguments if any. */
1392 for (i = 0; token->args[i]; ++i) {
1393 if (ctx->args_num == RTE_DIM(ctx->args))
1395 ctx->args[ctx->args_num++] = token->args[i];
1400 /** Return number of completion entries (cmdline API). */
1402 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1404 struct context *ctx = &cmd_flow_context;
1405 const struct token *token = &token_list[ctx->curr];
1406 const enum index *list;
1410 /* Tell cmd_flow_parse() that context must be reinitialized. */
1412 /* Count number of tokens in current list. */
1414 list = ctx->next[ctx->next_num - 1];
1416 list = token->next[0];
1417 for (i = 0; list[i]; ++i)
1422 * If there is a single token, use its completion callback, otherwise
1423 * return the number of entries.
1425 token = &token_list[list[0]];
1426 if (i == 1 && token->comp) {
1427 /* Save index for cmd_flow_get_help(). */
1428 ctx->prev = list[0];
1429 return token->comp(ctx, token, 0, NULL, 0);
1434 /** Return a completion entry (cmdline API). */
1436 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1437 char *dst, unsigned int size)
1439 struct context *ctx = &cmd_flow_context;
1440 const struct token *token = &token_list[ctx->curr];
1441 const enum index *list;
1445 /* Tell cmd_flow_parse() that context must be reinitialized. */
1447 /* Count number of tokens in current list. */
1449 list = ctx->next[ctx->next_num - 1];
1451 list = token->next[0];
1452 for (i = 0; list[i]; ++i)
1456 /* If there is a single token, use its completion callback. */
1457 token = &token_list[list[0]];
1458 if (i == 1 && token->comp) {
1459 /* Save index for cmd_flow_get_help(). */
1460 ctx->prev = list[0];
1461 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1463 /* Otherwise make sure the index is valid and use defaults. */
1466 token = &token_list[list[index]];
1467 snprintf(dst, size, "%s", token->name);
1468 /* Save index for cmd_flow_get_help(). */
1469 ctx->prev = list[index];
1473 /** Populate help strings for current token (cmdline API). */
1475 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1477 struct context *ctx = &cmd_flow_context;
1478 const struct token *token = &token_list[ctx->prev];
1481 /* Tell cmd_flow_parse() that context must be reinitialized. */
1485 /* Set token type and update global help with details. */
1486 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1488 cmd_flow.help_str = token->help;
1490 cmd_flow.help_str = token->name;
1494 /** Token definition template (cmdline API). */
1495 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1496 .ops = &(struct cmdline_token_ops){
1497 .parse = cmd_flow_parse,
1498 .complete_get_nb = cmd_flow_complete_get_nb,
1499 .complete_get_elt = cmd_flow_complete_get_elt,
1500 .get_help = cmd_flow_get_help,
1505 /** Populate the next dynamic token. */
1507 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1508 cmdline_parse_token_hdr_t *(*hdrs)[])
1510 struct context *ctx = &cmd_flow_context;
1512 /* Always reinitialize context before requesting the first token. */
1514 cmd_flow_context_init(ctx);
1515 /* Return NULL when no more tokens are expected. */
1516 if (!ctx->next_num && ctx->curr) {
1520 /* Determine if command should end here. */
1521 if (ctx->eol && ctx->last && ctx->next_num) {
1522 const enum index *list = ctx->next[ctx->next_num - 1];
1525 for (i = 0; list[i]; ++i) {
1532 *hdr = &cmd_flow_token_hdr;
1535 /** Dispatch parsed buffer to function calls. */
1537 cmd_flow_parsed(const struct buffer *in)
1539 switch (in->command) {
1541 port_flow_validate(in->port, &in->args.vc.attr,
1542 in->args.vc.pattern, in->args.vc.actions);
1545 port_flow_create(in->port, &in->args.vc.attr,
1546 in->args.vc.pattern, in->args.vc.actions);
1549 port_flow_destroy(in->port, in->args.destroy.rule_n,
1550 in->args.destroy.rule);
1553 port_flow_flush(in->port);
1556 port_flow_query(in->port, in->args.query.rule,
1557 in->args.query.action);
1560 port_flow_list(in->port, in->args.list.group_n,
1561 in->args.list.group);
1568 /** Token generator and output processing callback (cmdline API). */
1570 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1573 cmd_flow_tok(arg0, arg2);
1575 cmd_flow_parsed(arg0);
1578 /** Global parser instance (cmdline API). */
1579 cmdline_parse_inst_t cmd_flow = {
1581 .data = NULL, /**< Unused. */
1582 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1585 }, /**< Tokens are returned by cmd_flow_tok(). */