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. */
67 /* Top-level command. */
70 /* Sub-level commands. */
78 /* Destroy arguments. */
81 /* Query arguments. */
87 /* Validate/create arguments. */
93 /* Validate/create pattern. */
118 /* Validate/create actions. */
126 /** Size of pattern[] field in struct rte_flow_item_raw. */
127 #define ITEM_RAW_PATTERN_SIZE 36
129 /** Storage size for struct rte_flow_item_raw including pattern. */
130 #define ITEM_RAW_SIZE \
131 (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
133 /** Maximum number of subsequent tokens and arguments on the stack. */
134 #define CTX_STACK_SIZE 16
136 /** Parser context. */
138 /** Stack of subsequent token lists to process. */
139 const enum index *next[CTX_STACK_SIZE];
140 /** Arguments for stacked tokens. */
141 const void *args[CTX_STACK_SIZE];
142 enum index curr; /**< Current token index. */
143 enum index prev; /**< Index of the last token seen. */
144 int next_num; /**< Number of entries in next[]. */
145 int args_num; /**< Number of entries in args[]. */
146 uint32_t reparse:1; /**< Start over from the beginning. */
147 uint32_t eol:1; /**< EOL has been detected. */
148 uint32_t last:1; /**< No more arguments. */
149 uint16_t port; /**< Current port ID (for completions). */
150 uint32_t objdata; /**< Object-specific data. */
151 void *object; /**< Address of current object for relative offsets. */
152 void *objmask; /**< Object a full mask must be written to. */
155 /** Token argument. */
157 uint32_t hton:1; /**< Use network byte ordering. */
158 uint32_t sign:1; /**< Value is signed. */
159 uint32_t offset; /**< Relative offset from ctx->object. */
160 uint32_t size; /**< Field size. */
161 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
164 /** Parser token definition. */
166 /** Type displayed during completion (defaults to "TOKEN"). */
168 /** Help displayed during completion (defaults to token name). */
170 /** Private data used by parser functions. */
173 * Lists of subsequent tokens to push on the stack. Each call to the
174 * parser consumes the last entry of that stack.
176 const enum index *const *next;
177 /** Arguments stack for subsequent tokens that need them. */
178 const struct arg *const *args;
180 * Token-processing callback, returns -1 in case of error, the
181 * length of the matched string otherwise. If NULL, attempts to
182 * match the token name.
184 * If buf is not NULL, the result should be stored in it according
185 * to context. An error is returned if not large enough.
187 int (*call)(struct context *ctx, const struct token *token,
188 const char *str, unsigned int len,
189 void *buf, unsigned int size);
191 * Callback that provides possible values for this token, used for
192 * completion. Returns -1 in case of error, the number of possible
193 * values otherwise. If NULL, the token name is used.
195 * If buf is not NULL, entry index ent is written to buf and the
196 * full length of the entry is returned (same behavior as
199 int (*comp)(struct context *ctx, const struct token *token,
200 unsigned int ent, char *buf, unsigned int size);
201 /** Mandatory token name, no default value. */
205 /** Static initializer for the next field. */
206 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
208 /** Static initializer for a NEXT() entry. */
209 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
211 /** Static initializer for the args field. */
212 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
214 /** Static initializer for ARGS() to target a field. */
215 #define ARGS_ENTRY(s, f) \
216 (&(const struct arg){ \
217 .offset = offsetof(s, f), \
218 .size = sizeof(((s *)0)->f), \
221 /** Static initializer for ARGS() to target a bit-field. */
222 #define ARGS_ENTRY_BF(s, f, b) \
223 (&(const struct arg){ \
225 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
228 /** Static initializer for ARGS() to target a pointer. */
229 #define ARGS_ENTRY_PTR(s, f) \
230 (&(const struct arg){ \
231 .size = sizeof(*((s *)0)->f), \
234 /** Static initializer for ARGS() with arbitrary size. */
235 #define ARGS_ENTRY_USZ(s, f, sz) \
236 (&(const struct arg){ \
237 .offset = offsetof(s, f), \
241 /** Parser output buffer layout expected by cmd_flow_parsed(). */
243 enum index command; /**< Flow command. */
244 uint16_t port; /**< Affected port ID. */
247 struct rte_flow_attr attr;
248 struct rte_flow_item *pattern;
249 struct rte_flow_action *actions;
253 } vc; /**< Validate/create arguments. */
257 } destroy; /**< Destroy arguments. */
260 enum rte_flow_action_type action;
261 } query; /**< Query arguments. */
265 } list; /**< List arguments. */
266 } args; /**< Command arguments. */
269 /** Private data for pattern items. */
270 struct parse_item_priv {
271 enum rte_flow_item_type type; /**< Item type. */
272 uint32_t size; /**< Size of item specification structure. */
275 #define PRIV_ITEM(t, s) \
276 (&(const struct parse_item_priv){ \
277 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
281 /** Private data for actions. */
282 struct parse_action_priv {
283 enum rte_flow_action_type type; /**< Action type. */
284 uint32_t size; /**< Size of action configuration structure. */
287 #define PRIV_ACTION(t, s) \
288 (&(const struct parse_action_priv){ \
289 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
293 static const enum index next_vc_attr[] = {
302 static const enum index next_destroy_attr[] = {
308 static const enum index next_list_attr[] = {
314 static const enum index item_param[] = {
323 static const enum index next_item[] = {
335 static const enum index item_any[] = {
341 static const enum index item_vf[] = {
347 static const enum index item_port[] = {
353 static const enum index item_raw[] = {
363 static const enum index next_action[] = {
370 static int parse_init(struct context *, const struct token *,
371 const char *, unsigned int,
372 void *, unsigned int);
373 static int parse_vc(struct context *, const struct token *,
374 const char *, unsigned int,
375 void *, unsigned int);
376 static int parse_vc_spec(struct context *, const struct token *,
377 const char *, unsigned int, void *, unsigned int);
378 static int parse_destroy(struct context *, const struct token *,
379 const char *, unsigned int,
380 void *, unsigned int);
381 static int parse_flush(struct context *, const struct token *,
382 const char *, unsigned int,
383 void *, unsigned int);
384 static int parse_query(struct context *, const struct token *,
385 const char *, unsigned int,
386 void *, unsigned int);
387 static int parse_action(struct context *, const struct token *,
388 const char *, unsigned int,
389 void *, unsigned int);
390 static int parse_list(struct context *, const struct token *,
391 const char *, unsigned int,
392 void *, unsigned int);
393 static int parse_int(struct context *, const struct token *,
394 const char *, unsigned int,
395 void *, unsigned int);
396 static int parse_prefix(struct context *, const struct token *,
397 const char *, unsigned int,
398 void *, unsigned int);
399 static int parse_boolean(struct context *, const struct token *,
400 const char *, unsigned int,
401 void *, unsigned int);
402 static int parse_string(struct context *, const struct token *,
403 const char *, unsigned int,
404 void *, unsigned int);
405 static int parse_port(struct context *, const struct token *,
406 const char *, unsigned int,
407 void *, unsigned int);
408 static int comp_none(struct context *, const struct token *,
409 unsigned int, char *, unsigned int);
410 static int comp_boolean(struct context *, const struct token *,
411 unsigned int, char *, unsigned int);
412 static int comp_action(struct context *, const struct token *,
413 unsigned int, char *, unsigned int);
414 static int comp_port(struct context *, const struct token *,
415 unsigned int, char *, unsigned int);
416 static int comp_rule_id(struct context *, const struct token *,
417 unsigned int, char *, unsigned int);
419 /** Token definitions. */
420 static const struct token token_list[] = {
421 /* Special tokens. */
424 .help = "null entry, abused as the entry point",
425 .next = NEXT(NEXT_ENTRY(FLOW)),
430 .help = "command may end here",
436 .help = "integer value",
441 .name = "{unsigned}",
443 .help = "unsigned integer value",
450 .help = "prefix length for bit-mask",
451 .call = parse_prefix,
457 .help = "any boolean value",
458 .call = parse_boolean,
459 .comp = comp_boolean,
464 .help = "fixed string",
465 .call = parse_string,
471 .help = "rule identifier",
473 .comp = comp_rule_id,
478 .help = "port identifier",
483 .name = "{group_id}",
485 .help = "group identifier",
492 .help = "priority level",
496 /* Top-level command. */
499 .type = "{command} {port_id} [{arg} [...]]",
500 .help = "manage ingress/egress flow rules",
501 .next = NEXT(NEXT_ENTRY
510 /* Sub-level commands. */
513 .help = "check whether a flow rule can be created",
514 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
515 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
520 .help = "create a flow rule",
521 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
522 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
527 .help = "destroy specific flow rules",
528 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
529 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
530 .call = parse_destroy,
534 .help = "destroy all flow rules",
535 .next = NEXT(NEXT_ENTRY(PORT_ID)),
536 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
541 .help = "query an existing flow rule",
542 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
544 NEXT_ENTRY(PORT_ID)),
545 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
546 ARGS_ENTRY(struct buffer, args.query.rule),
547 ARGS_ENTRY(struct buffer, port)),
552 .help = "list existing flow rules",
553 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
554 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
557 /* Destroy arguments. */
560 .help = "specify a rule identifier",
561 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
562 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
563 .call = parse_destroy,
565 /* Query arguments. */
569 .help = "action to query, must be part of the rule",
570 .call = parse_action,
573 /* List arguments. */
576 .help = "specify a group",
577 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
578 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
581 /* Validate/create attributes. */
584 .help = "specify a group",
585 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
586 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
591 .help = "specify a priority level",
592 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
593 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
598 .help = "affect rule to ingress",
599 .next = NEXT(next_vc_attr),
604 .help = "affect rule to egress",
605 .next = NEXT(next_vc_attr),
608 /* Validate/create pattern. */
611 .help = "submit a list of pattern items",
612 .next = NEXT(next_item),
617 .help = "match value perfectly (with full bit-mask)",
618 .call = parse_vc_spec,
620 [ITEM_PARAM_SPEC] = {
622 .help = "match value according to configured bit-mask",
623 .call = parse_vc_spec,
625 [ITEM_PARAM_LAST] = {
627 .help = "specify upper bound to establish a range",
628 .call = parse_vc_spec,
630 [ITEM_PARAM_MASK] = {
632 .help = "specify bit-mask with relevant bits set to one",
633 .call = parse_vc_spec,
635 [ITEM_PARAM_PREFIX] = {
637 .help = "generate bit-mask from a prefix length",
638 .call = parse_vc_spec,
642 .help = "specify next pattern item",
643 .next = NEXT(next_item),
647 .help = "end list of pattern items",
648 .priv = PRIV_ITEM(END, 0),
649 .next = NEXT(NEXT_ENTRY(ACTIONS)),
654 .help = "no-op pattern item",
655 .priv = PRIV_ITEM(VOID, 0),
656 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
661 .help = "perform actions when pattern does not match",
662 .priv = PRIV_ITEM(INVERT, 0),
663 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
668 .help = "match any protocol for the current layer",
669 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
670 .next = NEXT(item_any),
675 .help = "number of layers covered",
676 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
677 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
681 .help = "match packets addressed to the physical function",
682 .priv = PRIV_ITEM(PF, 0),
683 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
688 .help = "match packets addressed to a virtual function ID",
689 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
690 .next = NEXT(item_vf),
695 .help = "destination VF ID",
696 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
697 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
701 .help = "device-specific physical port index to use",
702 .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)),
703 .next = NEXT(item_port),
706 [ITEM_PORT_INDEX] = {
708 .help = "physical port index",
709 .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param),
710 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)),
714 .help = "match an arbitrary byte string",
715 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
716 .next = NEXT(item_raw),
719 [ITEM_RAW_RELATIVE] = {
721 .help = "look for pattern after the previous item",
722 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
723 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
726 [ITEM_RAW_SEARCH] = {
728 .help = "search pattern from offset (see also limit)",
729 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
730 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
733 [ITEM_RAW_OFFSET] = {
735 .help = "absolute or relative offset for pattern",
736 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
737 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
741 .help = "search area limit for start of pattern",
742 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
743 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
745 [ITEM_RAW_PATTERN] = {
747 .help = "byte string to look for",
748 .next = NEXT(item_raw,
750 NEXT_ENTRY(ITEM_PARAM_IS,
753 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length),
754 ARGS_ENTRY_USZ(struct rte_flow_item_raw,
756 ITEM_RAW_PATTERN_SIZE)),
758 /* Validate/create actions. */
761 .help = "submit a list of associated actions",
762 .next = NEXT(next_action),
767 .help = "specify next action",
768 .next = NEXT(next_action),
772 .help = "end list of actions",
773 .priv = PRIV_ACTION(END, 0),
778 .help = "no-op action",
779 .priv = PRIV_ACTION(VOID, 0),
780 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
783 [ACTION_PASSTHRU] = {
785 .help = "let subsequent rule process matched packets",
786 .priv = PRIV_ACTION(PASSTHRU, 0),
787 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
792 /** Remove and return last entry from argument stack. */
793 static const struct arg *
794 pop_args(struct context *ctx)
796 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
799 /** Add entry on top of the argument stack. */
801 push_args(struct context *ctx, const struct arg *arg)
803 if (ctx->args_num == CTX_STACK_SIZE)
805 ctx->args[ctx->args_num++] = arg;
809 /** Spread value into buffer according to bit-mask. */
811 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
813 uint32_t i = arg->size;
821 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
830 unsigned int shift = 0;
831 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
833 for (shift = 0; arg->mask[i] >> shift; ++shift) {
834 if (!(arg->mask[i] & (1 << shift)))
839 *buf &= ~(1 << shift);
840 *buf |= (val & 1) << shift;
849 * Parse a prefix length and generate a bit-mask.
851 * Last argument (ctx->args) is retrieved to determine mask size, storage
852 * location and whether the result must use network byte ordering.
855 parse_prefix(struct context *ctx, const struct token *token,
856 const char *str, unsigned int len,
857 void *buf, unsigned int size)
859 const struct arg *arg = pop_args(ctx);
860 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
867 /* Argument is expected. */
871 u = strtoumax(str, &end, 0);
872 if (errno || (size_t)(end - str) != len)
877 extra = arg_entry_bf_fill(NULL, 0, arg);
886 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
887 !arg_entry_bf_fill(ctx->objmask, -1, arg))
894 if (bytes > size || bytes + !!extra > size)
898 buf = (uint8_t *)ctx->object + arg->offset;
899 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
901 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
902 memset(buf, 0x00, size - bytes);
904 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
908 memset(buf, 0xff, bytes);
909 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
911 ((uint8_t *)buf)[bytes] = conv[extra];
914 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
921 /** Default parsing function for token name matching. */
923 parse_default(struct context *ctx, const struct token *token,
924 const char *str, unsigned int len,
925 void *buf, unsigned int size)
930 if (strncmp(str, token->name, len))
935 /** Parse flow command, initialize output buffer for subsequent tokens. */
937 parse_init(struct context *ctx, const struct token *token,
938 const char *str, unsigned int len,
939 void *buf, unsigned int size)
941 struct buffer *out = buf;
943 /* Token name must match. */
944 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
946 /* Nothing else to do if there is no buffer. */
949 /* Make sure buffer is large enough. */
950 if (size < sizeof(*out))
952 /* Initialize buffer. */
953 memset(out, 0x00, sizeof(*out));
954 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
961 /** Parse tokens for validate/create commands. */
963 parse_vc(struct context *ctx, const struct token *token,
964 const char *str, unsigned int len,
965 void *buf, unsigned int size)
967 struct buffer *out = buf;
971 /* Token name must match. */
972 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
974 /* Nothing else to do if there is no buffer. */
978 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
980 if (sizeof(*out) > size)
982 out->command = ctx->curr;
986 out->args.vc.data = (uint8_t *)out + size;
990 ctx->object = &out->args.vc.attr;
997 out->args.vc.attr.ingress = 1;
1000 out->args.vc.attr.egress = 1;
1003 out->args.vc.pattern =
1004 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1006 ctx->object = out->args.vc.pattern;
1007 ctx->objmask = NULL;
1010 out->args.vc.actions =
1011 (void *)RTE_ALIGN_CEIL((uintptr_t)
1012 (out->args.vc.pattern +
1013 out->args.vc.pattern_n),
1015 ctx->object = out->args.vc.actions;
1016 ctx->objmask = NULL;
1023 if (!out->args.vc.actions) {
1024 const struct parse_item_priv *priv = token->priv;
1025 struct rte_flow_item *item =
1026 out->args.vc.pattern + out->args.vc.pattern_n;
1028 data_size = priv->size * 3; /* spec, last, mask */
1029 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
1030 (out->args.vc.data - data_size),
1032 if ((uint8_t *)item + sizeof(*item) > data)
1034 *item = (struct rte_flow_item){
1037 ++out->args.vc.pattern_n;
1039 ctx->objmask = NULL;
1041 const struct parse_action_priv *priv = token->priv;
1042 struct rte_flow_action *action =
1043 out->args.vc.actions + out->args.vc.actions_n;
1045 data_size = priv->size; /* configuration */
1046 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
1047 (out->args.vc.data - data_size),
1049 if ((uint8_t *)action + sizeof(*action) > data)
1051 *action = (struct rte_flow_action){
1054 ++out->args.vc.actions_n;
1055 ctx->object = action;
1056 ctx->objmask = NULL;
1058 memset(data, 0, data_size);
1059 out->args.vc.data = data;
1060 ctx->objdata = data_size;
1064 /** Parse pattern item parameter type. */
1066 parse_vc_spec(struct context *ctx, const struct token *token,
1067 const char *str, unsigned int len,
1068 void *buf, unsigned int size)
1070 struct buffer *out = buf;
1071 struct rte_flow_item *item;
1077 /* Token name must match. */
1078 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1080 /* Parse parameter types. */
1081 switch (ctx->curr) {
1086 case ITEM_PARAM_SPEC:
1089 case ITEM_PARAM_LAST:
1092 case ITEM_PARAM_PREFIX:
1093 /* Modify next token to expect a prefix. */
1094 if (ctx->next_num < 2)
1096 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
1098 case ITEM_PARAM_MASK:
1104 /* Nothing else to do if there is no buffer. */
1107 if (!out->args.vc.pattern_n)
1109 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
1110 data_size = ctx->objdata / 3; /* spec, last, mask */
1111 /* Point to selected object. */
1112 ctx->object = out->args.vc.data + (data_size * index);
1114 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
1115 item->mask = ctx->objmask;
1117 ctx->objmask = NULL;
1118 /* Update relevant item pointer. */
1119 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
1124 /** Parse tokens for destroy command. */
1126 parse_destroy(struct context *ctx, const struct token *token,
1127 const char *str, unsigned int len,
1128 void *buf, unsigned int size)
1130 struct buffer *out = buf;
1132 /* Token name must match. */
1133 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1135 /* Nothing else to do if there is no buffer. */
1138 if (!out->command) {
1139 if (ctx->curr != DESTROY)
1141 if (sizeof(*out) > size)
1143 out->command = ctx->curr;
1146 ctx->objmask = NULL;
1147 out->args.destroy.rule =
1148 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1152 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
1153 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
1156 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
1157 ctx->objmask = NULL;
1161 /** Parse tokens for flush command. */
1163 parse_flush(struct context *ctx, const struct token *token,
1164 const char *str, unsigned int len,
1165 void *buf, unsigned int size)
1167 struct buffer *out = buf;
1169 /* Token name must match. */
1170 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1172 /* Nothing else to do if there is no buffer. */
1175 if (!out->command) {
1176 if (ctx->curr != FLUSH)
1178 if (sizeof(*out) > size)
1180 out->command = ctx->curr;
1183 ctx->objmask = NULL;
1188 /** Parse tokens for query command. */
1190 parse_query(struct context *ctx, const struct token *token,
1191 const char *str, unsigned int len,
1192 void *buf, unsigned int size)
1194 struct buffer *out = buf;
1196 /* Token name must match. */
1197 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1199 /* Nothing else to do if there is no buffer. */
1202 if (!out->command) {
1203 if (ctx->curr != QUERY)
1205 if (sizeof(*out) > size)
1207 out->command = ctx->curr;
1210 ctx->objmask = NULL;
1215 /** Parse action names. */
1217 parse_action(struct context *ctx, const struct token *token,
1218 const char *str, unsigned int len,
1219 void *buf, unsigned int size)
1221 struct buffer *out = buf;
1222 const struct arg *arg = pop_args(ctx);
1226 /* Argument is expected. */
1229 /* Parse action name. */
1230 for (i = 0; next_action[i]; ++i) {
1231 const struct parse_action_priv *priv;
1233 token = &token_list[next_action[i]];
1234 if (strncmp(token->name, str, len))
1240 memcpy((uint8_t *)ctx->object + arg->offset,
1246 push_args(ctx, arg);
1250 /** Parse tokens for list command. */
1252 parse_list(struct context *ctx, const struct token *token,
1253 const char *str, unsigned int len,
1254 void *buf, unsigned int size)
1256 struct buffer *out = buf;
1258 /* Token name must match. */
1259 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1261 /* Nothing else to do if there is no buffer. */
1264 if (!out->command) {
1265 if (ctx->curr != LIST)
1267 if (sizeof(*out) > size)
1269 out->command = ctx->curr;
1272 ctx->objmask = NULL;
1273 out->args.list.group =
1274 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1278 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
1279 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
1282 ctx->object = out->args.list.group + out->args.list.group_n++;
1283 ctx->objmask = NULL;
1288 * Parse signed/unsigned integers 8 to 64-bit long.
1290 * Last argument (ctx->args) is retrieved to determine integer type and
1294 parse_int(struct context *ctx, const struct token *token,
1295 const char *str, unsigned int len,
1296 void *buf, unsigned int size)
1298 const struct arg *arg = pop_args(ctx);
1303 /* Argument is expected. */
1308 (uintmax_t)strtoimax(str, &end, 0) :
1309 strtoumax(str, &end, 0);
1310 if (errno || (size_t)(end - str) != len)
1315 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
1316 !arg_entry_bf_fill(ctx->objmask, -1, arg))
1320 buf = (uint8_t *)ctx->object + arg->offset;
1324 case sizeof(uint8_t):
1325 *(uint8_t *)buf = u;
1327 case sizeof(uint16_t):
1328 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1330 case sizeof(uint32_t):
1331 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1333 case sizeof(uint64_t):
1334 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1339 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1341 buf = (uint8_t *)ctx->objmask + arg->offset;
1346 push_args(ctx, arg);
1353 * Two arguments (ctx->args) are retrieved from the stack to store data and
1354 * its length (in that order).
1357 parse_string(struct context *ctx, const struct token *token,
1358 const char *str, unsigned int len,
1359 void *buf, unsigned int size)
1361 const struct arg *arg_data = pop_args(ctx);
1362 const struct arg *arg_len = pop_args(ctx);
1363 char tmp[16]; /* Ought to be enough. */
1366 /* Arguments are expected. */
1370 push_args(ctx, arg_data);
1373 size = arg_data->size;
1374 /* Bit-mask fill is not supported. */
1375 if (arg_data->mask || size < len)
1379 /* Let parse_int() fill length information first. */
1380 ret = snprintf(tmp, sizeof(tmp), "%u", len);
1383 push_args(ctx, arg_len);
1384 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
1389 buf = (uint8_t *)ctx->object + arg_data->offset;
1390 /* Output buffer is not necessarily NUL-terminated. */
1391 memcpy(buf, str, len);
1392 memset((uint8_t *)buf + len, 0x55, size - len);
1394 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
1397 push_args(ctx, arg_len);
1398 push_args(ctx, arg_data);
1402 /** Boolean values (even indices stand for false). */
1403 static const char *const boolean_name[] = {
1412 * Parse a boolean value.
1414 * Last argument (ctx->args) is retrieved to determine storage size and
1418 parse_boolean(struct context *ctx, const struct token *token,
1419 const char *str, unsigned int len,
1420 void *buf, unsigned int size)
1422 const struct arg *arg = pop_args(ctx);
1426 /* Argument is expected. */
1429 for (i = 0; boolean_name[i]; ++i)
1430 if (!strncmp(str, boolean_name[i], len))
1432 /* Process token as integer. */
1433 if (boolean_name[i])
1434 str = i & 1 ? "1" : "0";
1435 push_args(ctx, arg);
1436 ret = parse_int(ctx, token, str, strlen(str), buf, size);
1437 return ret > 0 ? (int)len : ret;
1440 /** Parse port and update context. */
1442 parse_port(struct context *ctx, const struct token *token,
1443 const char *str, unsigned int len,
1444 void *buf, unsigned int size)
1446 struct buffer *out = &(struct buffer){ .port = 0 };
1454 ctx->objmask = NULL;
1455 size = sizeof(*out);
1457 ret = parse_int(ctx, token, str, len, out, size);
1459 ctx->port = out->port;
1465 /** No completion. */
1467 comp_none(struct context *ctx, const struct token *token,
1468 unsigned int ent, char *buf, unsigned int size)
1478 /** Complete boolean values. */
1480 comp_boolean(struct context *ctx, const struct token *token,
1481 unsigned int ent, char *buf, unsigned int size)
1487 for (i = 0; boolean_name[i]; ++i)
1488 if (buf && i == ent)
1489 return snprintf(buf, size, "%s", boolean_name[i]);
1495 /** Complete action names. */
1497 comp_action(struct context *ctx, const struct token *token,
1498 unsigned int ent, char *buf, unsigned int size)
1504 for (i = 0; next_action[i]; ++i)
1505 if (buf && i == ent)
1506 return snprintf(buf, size, "%s",
1507 token_list[next_action[i]].name);
1513 /** Complete available ports. */
1515 comp_port(struct context *ctx, const struct token *token,
1516 unsigned int ent, char *buf, unsigned int size)
1523 FOREACH_PORT(p, ports) {
1524 if (buf && i == ent)
1525 return snprintf(buf, size, "%u", p);
1533 /** Complete available rule IDs. */
1535 comp_rule_id(struct context *ctx, const struct token *token,
1536 unsigned int ent, char *buf, unsigned int size)
1539 struct rte_port *port;
1540 struct port_flow *pf;
1543 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1544 ctx->port == (uint16_t)RTE_PORT_ALL)
1546 port = &ports[ctx->port];
1547 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1548 if (buf && i == ent)
1549 return snprintf(buf, size, "%u", pf->id);
1557 /** Internal context. */
1558 static struct context cmd_flow_context;
1560 /** Global parser instance (cmdline API). */
1561 cmdline_parse_inst_t cmd_flow;
1563 /** Initialize context. */
1565 cmd_flow_context_init(struct context *ctx)
1567 /* A full memset() is not necessary. */
1578 ctx->objmask = NULL;
1581 /** Parse a token (cmdline API). */
1583 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1586 struct context *ctx = &cmd_flow_context;
1587 const struct token *token;
1588 const enum index *list;
1593 /* Restart as requested. */
1595 cmd_flow_context_init(ctx);
1596 token = &token_list[ctx->curr];
1597 /* Check argument length. */
1600 for (len = 0; src[len]; ++len)
1601 if (src[len] == '#' || isspace(src[len]))
1605 /* Last argument and EOL detection. */
1606 for (i = len; src[i]; ++i)
1607 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1609 else if (!isspace(src[i])) {
1614 if (src[i] == '\r' || src[i] == '\n') {
1618 /* Initialize context if necessary. */
1619 if (!ctx->next_num) {
1622 ctx->next[ctx->next_num++] = token->next[0];
1624 /* Process argument through candidates. */
1625 ctx->prev = ctx->curr;
1626 list = ctx->next[ctx->next_num - 1];
1627 for (i = 0; list[i]; ++i) {
1628 const struct token *next = &token_list[list[i]];
1631 ctx->curr = list[i];
1633 tmp = next->call(ctx, next, src, len, result, size);
1635 tmp = parse_default(ctx, next, src, len, result, size);
1636 if (tmp == -1 || tmp != len)
1644 /* Push subsequent tokens if any. */
1646 for (i = 0; token->next[i]; ++i) {
1647 if (ctx->next_num == RTE_DIM(ctx->next))
1649 ctx->next[ctx->next_num++] = token->next[i];
1651 /* Push arguments if any. */
1653 for (i = 0; token->args[i]; ++i) {
1654 if (ctx->args_num == RTE_DIM(ctx->args))
1656 ctx->args[ctx->args_num++] = token->args[i];
1661 /** Return number of completion entries (cmdline API). */
1663 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1665 struct context *ctx = &cmd_flow_context;
1666 const struct token *token = &token_list[ctx->curr];
1667 const enum index *list;
1671 /* Tell cmd_flow_parse() that context must be reinitialized. */
1673 /* Count number of tokens in current list. */
1675 list = ctx->next[ctx->next_num - 1];
1677 list = token->next[0];
1678 for (i = 0; list[i]; ++i)
1683 * If there is a single token, use its completion callback, otherwise
1684 * return the number of entries.
1686 token = &token_list[list[0]];
1687 if (i == 1 && token->comp) {
1688 /* Save index for cmd_flow_get_help(). */
1689 ctx->prev = list[0];
1690 return token->comp(ctx, token, 0, NULL, 0);
1695 /** Return a completion entry (cmdline API). */
1697 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1698 char *dst, unsigned int size)
1700 struct context *ctx = &cmd_flow_context;
1701 const struct token *token = &token_list[ctx->curr];
1702 const enum index *list;
1706 /* Tell cmd_flow_parse() that context must be reinitialized. */
1708 /* Count number of tokens in current list. */
1710 list = ctx->next[ctx->next_num - 1];
1712 list = token->next[0];
1713 for (i = 0; list[i]; ++i)
1717 /* If there is a single token, use its completion callback. */
1718 token = &token_list[list[0]];
1719 if (i == 1 && token->comp) {
1720 /* Save index for cmd_flow_get_help(). */
1721 ctx->prev = list[0];
1722 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1724 /* Otherwise make sure the index is valid and use defaults. */
1727 token = &token_list[list[index]];
1728 snprintf(dst, size, "%s", token->name);
1729 /* Save index for cmd_flow_get_help(). */
1730 ctx->prev = list[index];
1734 /** Populate help strings for current token (cmdline API). */
1736 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1738 struct context *ctx = &cmd_flow_context;
1739 const struct token *token = &token_list[ctx->prev];
1742 /* Tell cmd_flow_parse() that context must be reinitialized. */
1746 /* Set token type and update global help with details. */
1747 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1749 cmd_flow.help_str = token->help;
1751 cmd_flow.help_str = token->name;
1755 /** Token definition template (cmdline API). */
1756 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1757 .ops = &(struct cmdline_token_ops){
1758 .parse = cmd_flow_parse,
1759 .complete_get_nb = cmd_flow_complete_get_nb,
1760 .complete_get_elt = cmd_flow_complete_get_elt,
1761 .get_help = cmd_flow_get_help,
1766 /** Populate the next dynamic token. */
1768 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1769 cmdline_parse_token_hdr_t *(*hdrs)[])
1771 struct context *ctx = &cmd_flow_context;
1773 /* Always reinitialize context before requesting the first token. */
1775 cmd_flow_context_init(ctx);
1776 /* Return NULL when no more tokens are expected. */
1777 if (!ctx->next_num && ctx->curr) {
1781 /* Determine if command should end here. */
1782 if (ctx->eol && ctx->last && ctx->next_num) {
1783 const enum index *list = ctx->next[ctx->next_num - 1];
1786 for (i = 0; list[i]; ++i) {
1793 *hdr = &cmd_flow_token_hdr;
1796 /** Dispatch parsed buffer to function calls. */
1798 cmd_flow_parsed(const struct buffer *in)
1800 switch (in->command) {
1802 port_flow_validate(in->port, &in->args.vc.attr,
1803 in->args.vc.pattern, in->args.vc.actions);
1806 port_flow_create(in->port, &in->args.vc.attr,
1807 in->args.vc.pattern, in->args.vc.actions);
1810 port_flow_destroy(in->port, in->args.destroy.rule_n,
1811 in->args.destroy.rule);
1814 port_flow_flush(in->port);
1817 port_flow_query(in->port, in->args.query.rule,
1818 in->args.query.action);
1821 port_flow_list(in->port, in->args.list.group_n,
1822 in->args.list.group);
1829 /** Token generator and output processing callback (cmdline API). */
1831 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1834 cmd_flow_tok(arg0, arg2);
1836 cmd_flow_parsed(arg0);
1839 /** Global parser instance (cmdline API). */
1840 cmdline_parse_inst_t cmd_flow = {
1842 .data = NULL, /**< Unused. */
1843 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1846 }, /**< Tokens are returned by cmd_flow_tok(). */