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. */
64 /* Top-level command. */
67 /* Sub-level commands. */
75 /* Destroy arguments. */
78 /* Query arguments. */
84 /* Validate/create arguments. */
90 /* Validate/create pattern. */
97 /* Validate/create actions. */
105 /** Maximum number of subsequent tokens and arguments on the stack. */
106 #define CTX_STACK_SIZE 16
108 /** Parser context. */
110 /** Stack of subsequent token lists to process. */
111 const enum index *next[CTX_STACK_SIZE];
112 /** Arguments for stacked tokens. */
113 const void *args[CTX_STACK_SIZE];
114 enum index curr; /**< Current token index. */
115 enum index prev; /**< Index of the last token seen. */
116 int next_num; /**< Number of entries in next[]. */
117 int args_num; /**< Number of entries in args[]. */
118 uint32_t reparse:1; /**< Start over from the beginning. */
119 uint32_t eol:1; /**< EOL has been detected. */
120 uint32_t last:1; /**< No more arguments. */
121 uint16_t port; /**< Current port ID (for completions). */
122 uint32_t objdata; /**< Object-specific data. */
123 void *object; /**< Address of current object for relative offsets. */
126 /** Token argument. */
128 uint32_t hton:1; /**< Use network byte ordering. */
129 uint32_t sign:1; /**< Value is signed. */
130 uint32_t offset; /**< Relative offset from ctx->object. */
131 uint32_t size; /**< Field size. */
134 /** Parser token definition. */
136 /** Type displayed during completion (defaults to "TOKEN"). */
138 /** Help displayed during completion (defaults to token name). */
140 /** Private data used by parser functions. */
143 * Lists of subsequent tokens to push on the stack. Each call to the
144 * parser consumes the last entry of that stack.
146 const enum index *const *next;
147 /** Arguments stack for subsequent tokens that need them. */
148 const struct arg *const *args;
150 * Token-processing callback, returns -1 in case of error, the
151 * length of the matched string otherwise. If NULL, attempts to
152 * match the token name.
154 * If buf is not NULL, the result should be stored in it according
155 * to context. An error is returned if not large enough.
157 int (*call)(struct context *ctx, const struct token *token,
158 const char *str, unsigned int len,
159 void *buf, unsigned int size);
161 * Callback that provides possible values for this token, used for
162 * completion. Returns -1 in case of error, the number of possible
163 * values otherwise. If NULL, the token name is used.
165 * If buf is not NULL, entry index ent is written to buf and the
166 * full length of the entry is returned (same behavior as
169 int (*comp)(struct context *ctx, const struct token *token,
170 unsigned int ent, char *buf, unsigned int size);
171 /** Mandatory token name, no default value. */
175 /** Static initializer for the next field. */
176 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
178 /** Static initializer for a NEXT() entry. */
179 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
181 /** Static initializer for the args field. */
182 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
184 /** Static initializer for ARGS() to target a field. */
185 #define ARGS_ENTRY(s, f) \
186 (&(const struct arg){ \
187 .offset = offsetof(s, f), \
188 .size = sizeof(((s *)0)->f), \
191 /** Static initializer for ARGS() to target a pointer. */
192 #define ARGS_ENTRY_PTR(s, f) \
193 (&(const struct arg){ \
194 .size = sizeof(*((s *)0)->f), \
197 /** Parser output buffer layout expected by cmd_flow_parsed(). */
199 enum index command; /**< Flow command. */
200 uint16_t port; /**< Affected port ID. */
203 struct rte_flow_attr attr;
204 struct rte_flow_item *pattern;
205 struct rte_flow_action *actions;
209 } vc; /**< Validate/create arguments. */
213 } destroy; /**< Destroy arguments. */
216 enum rte_flow_action_type action;
217 } query; /**< Query arguments. */
221 } list; /**< List arguments. */
222 } args; /**< Command arguments. */
225 /** Private data for pattern items. */
226 struct parse_item_priv {
227 enum rte_flow_item_type type; /**< Item type. */
228 uint32_t size; /**< Size of item specification structure. */
231 #define PRIV_ITEM(t, s) \
232 (&(const struct parse_item_priv){ \
233 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
237 /** Private data for actions. */
238 struct parse_action_priv {
239 enum rte_flow_action_type type; /**< Action type. */
240 uint32_t size; /**< Size of action configuration structure. */
243 #define PRIV_ACTION(t, s) \
244 (&(const struct parse_action_priv){ \
245 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
249 static const enum index next_vc_attr[] = {
258 static const enum index next_destroy_attr[] = {
264 static const enum index next_list_attr[] = {
270 static const enum index next_item[] = {
277 static const enum index next_action[] = {
284 static int parse_init(struct context *, const struct token *,
285 const char *, unsigned int,
286 void *, unsigned int);
287 static int parse_vc(struct context *, const struct token *,
288 const char *, unsigned int,
289 void *, unsigned int);
290 static int parse_destroy(struct context *, const struct token *,
291 const char *, unsigned int,
292 void *, unsigned int);
293 static int parse_flush(struct context *, const struct token *,
294 const char *, unsigned int,
295 void *, unsigned int);
296 static int parse_query(struct context *, const struct token *,
297 const char *, unsigned int,
298 void *, unsigned int);
299 static int parse_action(struct context *, const struct token *,
300 const char *, unsigned int,
301 void *, unsigned int);
302 static int parse_list(struct context *, const struct token *,
303 const char *, unsigned int,
304 void *, unsigned int);
305 static int parse_int(struct context *, const struct token *,
306 const char *, unsigned int,
307 void *, unsigned int);
308 static int parse_port(struct context *, const struct token *,
309 const char *, unsigned int,
310 void *, unsigned int);
311 static int comp_none(struct context *, const struct token *,
312 unsigned int, char *, unsigned int);
313 static int comp_action(struct context *, const struct token *,
314 unsigned int, char *, unsigned int);
315 static int comp_port(struct context *, const struct token *,
316 unsigned int, char *, unsigned int);
317 static int comp_rule_id(struct context *, const struct token *,
318 unsigned int, char *, unsigned int);
320 /** Token definitions. */
321 static const struct token token_list[] = {
322 /* Special tokens. */
325 .help = "null entry, abused as the entry point",
326 .next = NEXT(NEXT_ENTRY(FLOW)),
331 .help = "command may end here",
337 .help = "integer value",
342 .name = "{unsigned}",
344 .help = "unsigned integer value",
351 .help = "rule identifier",
353 .comp = comp_rule_id,
358 .help = "port identifier",
363 .name = "{group_id}",
365 .help = "group identifier",
372 .help = "priority level",
376 /* Top-level command. */
379 .type = "{command} {port_id} [{arg} [...]]",
380 .help = "manage ingress/egress flow rules",
381 .next = NEXT(NEXT_ENTRY
390 /* Sub-level commands. */
393 .help = "check whether a flow rule can be created",
394 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
395 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
400 .help = "create a flow rule",
401 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
402 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
407 .help = "destroy specific flow rules",
408 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
409 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
410 .call = parse_destroy,
414 .help = "destroy all flow rules",
415 .next = NEXT(NEXT_ENTRY(PORT_ID)),
416 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
421 .help = "query an existing flow rule",
422 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
424 NEXT_ENTRY(PORT_ID)),
425 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
426 ARGS_ENTRY(struct buffer, args.query.rule),
427 ARGS_ENTRY(struct buffer, port)),
432 .help = "list existing flow rules",
433 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
434 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
437 /* Destroy arguments. */
440 .help = "specify a rule identifier",
441 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
442 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
443 .call = parse_destroy,
445 /* Query arguments. */
449 .help = "action to query, must be part of the rule",
450 .call = parse_action,
453 /* List arguments. */
456 .help = "specify a group",
457 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
458 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
461 /* Validate/create attributes. */
464 .help = "specify a group",
465 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
466 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
471 .help = "specify a priority level",
472 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
473 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
478 .help = "affect rule to ingress",
479 .next = NEXT(next_vc_attr),
484 .help = "affect rule to egress",
485 .next = NEXT(next_vc_attr),
488 /* Validate/create pattern. */
491 .help = "submit a list of pattern items",
492 .next = NEXT(next_item),
497 .help = "specify next pattern item",
498 .next = NEXT(next_item),
502 .help = "end list of pattern items",
503 .priv = PRIV_ITEM(END, 0),
504 .next = NEXT(NEXT_ENTRY(ACTIONS)),
509 .help = "no-op pattern item",
510 .priv = PRIV_ITEM(VOID, 0),
511 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
516 .help = "perform actions when pattern does not match",
517 .priv = PRIV_ITEM(INVERT, 0),
518 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
521 /* Validate/create actions. */
524 .help = "submit a list of associated actions",
525 .next = NEXT(next_action),
530 .help = "specify next action",
531 .next = NEXT(next_action),
535 .help = "end list of actions",
536 .priv = PRIV_ACTION(END, 0),
541 .help = "no-op action",
542 .priv = PRIV_ACTION(VOID, 0),
543 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
546 [ACTION_PASSTHRU] = {
548 .help = "let subsequent rule process matched packets",
549 .priv = PRIV_ACTION(PASSTHRU, 0),
550 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
555 /** Remove and return last entry from argument stack. */
556 static const struct arg *
557 pop_args(struct context *ctx)
559 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
562 /** Add entry on top of the argument stack. */
564 push_args(struct context *ctx, const struct arg *arg)
566 if (ctx->args_num == CTX_STACK_SIZE)
568 ctx->args[ctx->args_num++] = arg;
572 /** Default parsing function for token name matching. */
574 parse_default(struct context *ctx, const struct token *token,
575 const char *str, unsigned int len,
576 void *buf, unsigned int size)
581 if (strncmp(str, token->name, len))
586 /** Parse flow command, initialize output buffer for subsequent tokens. */
588 parse_init(struct context *ctx, const struct token *token,
589 const char *str, unsigned int len,
590 void *buf, unsigned int size)
592 struct buffer *out = buf;
594 /* Token name must match. */
595 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
597 /* Nothing else to do if there is no buffer. */
600 /* Make sure buffer is large enough. */
601 if (size < sizeof(*out))
603 /* Initialize buffer. */
604 memset(out, 0x00, sizeof(*out));
605 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
611 /** Parse tokens for validate/create commands. */
613 parse_vc(struct context *ctx, const struct token *token,
614 const char *str, unsigned int len,
615 void *buf, unsigned int size)
617 struct buffer *out = buf;
621 /* Token name must match. */
622 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
624 /* Nothing else to do if there is no buffer. */
628 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
630 if (sizeof(*out) > size)
632 out->command = ctx->curr;
635 out->args.vc.data = (uint8_t *)out + size;
639 ctx->object = &out->args.vc.attr;
645 out->args.vc.attr.ingress = 1;
648 out->args.vc.attr.egress = 1;
651 out->args.vc.pattern =
652 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
654 ctx->object = out->args.vc.pattern;
657 out->args.vc.actions =
658 (void *)RTE_ALIGN_CEIL((uintptr_t)
659 (out->args.vc.pattern +
660 out->args.vc.pattern_n),
662 ctx->object = out->args.vc.actions;
669 if (!out->args.vc.actions) {
670 const struct parse_item_priv *priv = token->priv;
671 struct rte_flow_item *item =
672 out->args.vc.pattern + out->args.vc.pattern_n;
674 data_size = priv->size * 3; /* spec, last, mask */
675 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
676 (out->args.vc.data - data_size),
678 if ((uint8_t *)item + sizeof(*item) > data)
680 *item = (struct rte_flow_item){
683 ++out->args.vc.pattern_n;
686 const struct parse_action_priv *priv = token->priv;
687 struct rte_flow_action *action =
688 out->args.vc.actions + out->args.vc.actions_n;
690 data_size = priv->size; /* configuration */
691 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
692 (out->args.vc.data - data_size),
694 if ((uint8_t *)action + sizeof(*action) > data)
696 *action = (struct rte_flow_action){
699 ++out->args.vc.actions_n;
700 ctx->object = action;
702 memset(data, 0, data_size);
703 out->args.vc.data = data;
704 ctx->objdata = data_size;
708 /** Parse tokens for destroy command. */
710 parse_destroy(struct context *ctx, const struct token *token,
711 const char *str, unsigned int len,
712 void *buf, unsigned int size)
714 struct buffer *out = buf;
716 /* Token name must match. */
717 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
719 /* Nothing else to do if there is no buffer. */
723 if (ctx->curr != DESTROY)
725 if (sizeof(*out) > size)
727 out->command = ctx->curr;
730 out->args.destroy.rule =
731 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
735 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
736 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
739 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
743 /** Parse tokens for flush command. */
745 parse_flush(struct context *ctx, const struct token *token,
746 const char *str, unsigned int len,
747 void *buf, unsigned int size)
749 struct buffer *out = buf;
751 /* Token name must match. */
752 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
754 /* Nothing else to do if there is no buffer. */
758 if (ctx->curr != FLUSH)
760 if (sizeof(*out) > size)
762 out->command = ctx->curr;
769 /** Parse tokens for query command. */
771 parse_query(struct context *ctx, const struct token *token,
772 const char *str, unsigned int len,
773 void *buf, unsigned int size)
775 struct buffer *out = buf;
777 /* Token name must match. */
778 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
780 /* Nothing else to do if there is no buffer. */
784 if (ctx->curr != QUERY)
786 if (sizeof(*out) > size)
788 out->command = ctx->curr;
795 /** Parse action names. */
797 parse_action(struct context *ctx, const struct token *token,
798 const char *str, unsigned int len,
799 void *buf, unsigned int size)
801 struct buffer *out = buf;
802 const struct arg *arg = pop_args(ctx);
806 /* Argument is expected. */
809 /* Parse action name. */
810 for (i = 0; next_action[i]; ++i) {
811 const struct parse_action_priv *priv;
813 token = &token_list[next_action[i]];
814 if (strncmp(token->name, str, len))
820 memcpy((uint8_t *)ctx->object + arg->offset,
830 /** Parse tokens for list command. */
832 parse_list(struct context *ctx, const struct token *token,
833 const char *str, unsigned int len,
834 void *buf, unsigned int size)
836 struct buffer *out = buf;
838 /* Token name must match. */
839 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
841 /* Nothing else to do if there is no buffer. */
845 if (ctx->curr != LIST)
847 if (sizeof(*out) > size)
849 out->command = ctx->curr;
852 out->args.list.group =
853 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
857 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
858 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
861 ctx->object = out->args.list.group + out->args.list.group_n++;
866 * Parse signed/unsigned integers 8 to 64-bit long.
868 * Last argument (ctx->args) is retrieved to determine integer type and
872 parse_int(struct context *ctx, const struct token *token,
873 const char *str, unsigned int len,
874 void *buf, unsigned int size)
876 const struct arg *arg = pop_args(ctx);
881 /* Argument is expected. */
886 (uintmax_t)strtoimax(str, &end, 0) :
887 strtoumax(str, &end, 0);
888 if (errno || (size_t)(end - str) != len)
892 buf = (uint8_t *)ctx->object + arg->offset;
895 case sizeof(uint8_t):
898 case sizeof(uint16_t):
899 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
901 case sizeof(uint32_t):
902 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
904 case sizeof(uint64_t):
905 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
916 /** Parse port and update context. */
918 parse_port(struct context *ctx, const struct token *token,
919 const char *str, unsigned int len,
920 void *buf, unsigned int size)
922 struct buffer *out = &(struct buffer){ .port = 0 };
932 ret = parse_int(ctx, token, str, len, out, size);
934 ctx->port = out->port;
940 /** No completion. */
942 comp_none(struct context *ctx, const struct token *token,
943 unsigned int ent, char *buf, unsigned int size)
953 /** Complete action names. */
955 comp_action(struct context *ctx, const struct token *token,
956 unsigned int ent, char *buf, unsigned int size)
962 for (i = 0; next_action[i]; ++i)
964 return snprintf(buf, size, "%s",
965 token_list[next_action[i]].name);
971 /** Complete available ports. */
973 comp_port(struct context *ctx, const struct token *token,
974 unsigned int ent, char *buf, unsigned int size)
981 FOREACH_PORT(p, ports) {
983 return snprintf(buf, size, "%u", p);
991 /** Complete available rule IDs. */
993 comp_rule_id(struct context *ctx, const struct token *token,
994 unsigned int ent, char *buf, unsigned int size)
997 struct rte_port *port;
998 struct port_flow *pf;
1001 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1002 ctx->port == (uint16_t)RTE_PORT_ALL)
1004 port = &ports[ctx->port];
1005 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1006 if (buf && i == ent)
1007 return snprintf(buf, size, "%u", pf->id);
1015 /** Internal context. */
1016 static struct context cmd_flow_context;
1018 /** Global parser instance (cmdline API). */
1019 cmdline_parse_inst_t cmd_flow;
1021 /** Initialize context. */
1023 cmd_flow_context_init(struct context *ctx)
1025 /* A full memset() is not necessary. */
1038 /** Parse a token (cmdline API). */
1040 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1043 struct context *ctx = &cmd_flow_context;
1044 const struct token *token;
1045 const enum index *list;
1050 /* Restart as requested. */
1052 cmd_flow_context_init(ctx);
1053 token = &token_list[ctx->curr];
1054 /* Check argument length. */
1057 for (len = 0; src[len]; ++len)
1058 if (src[len] == '#' || isspace(src[len]))
1062 /* Last argument and EOL detection. */
1063 for (i = len; src[i]; ++i)
1064 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1066 else if (!isspace(src[i])) {
1071 if (src[i] == '\r' || src[i] == '\n') {
1075 /* Initialize context if necessary. */
1076 if (!ctx->next_num) {
1079 ctx->next[ctx->next_num++] = token->next[0];
1081 /* Process argument through candidates. */
1082 ctx->prev = ctx->curr;
1083 list = ctx->next[ctx->next_num - 1];
1084 for (i = 0; list[i]; ++i) {
1085 const struct token *next = &token_list[list[i]];
1088 ctx->curr = list[i];
1090 tmp = next->call(ctx, next, src, len, result, size);
1092 tmp = parse_default(ctx, next, src, len, result, size);
1093 if (tmp == -1 || tmp != len)
1101 /* Push subsequent tokens if any. */
1103 for (i = 0; token->next[i]; ++i) {
1104 if (ctx->next_num == RTE_DIM(ctx->next))
1106 ctx->next[ctx->next_num++] = token->next[i];
1108 /* Push arguments if any. */
1110 for (i = 0; token->args[i]; ++i) {
1111 if (ctx->args_num == RTE_DIM(ctx->args))
1113 ctx->args[ctx->args_num++] = token->args[i];
1118 /** Return number of completion entries (cmdline API). */
1120 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1122 struct context *ctx = &cmd_flow_context;
1123 const struct token *token = &token_list[ctx->curr];
1124 const enum index *list;
1128 /* Tell cmd_flow_parse() that context must be reinitialized. */
1130 /* Count number of tokens in current list. */
1132 list = ctx->next[ctx->next_num - 1];
1134 list = token->next[0];
1135 for (i = 0; list[i]; ++i)
1140 * If there is a single token, use its completion callback, otherwise
1141 * return the number of entries.
1143 token = &token_list[list[0]];
1144 if (i == 1 && token->comp) {
1145 /* Save index for cmd_flow_get_help(). */
1146 ctx->prev = list[0];
1147 return token->comp(ctx, token, 0, NULL, 0);
1152 /** Return a completion entry (cmdline API). */
1154 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1155 char *dst, unsigned int size)
1157 struct context *ctx = &cmd_flow_context;
1158 const struct token *token = &token_list[ctx->curr];
1159 const enum index *list;
1163 /* Tell cmd_flow_parse() that context must be reinitialized. */
1165 /* Count number of tokens in current list. */
1167 list = ctx->next[ctx->next_num - 1];
1169 list = token->next[0];
1170 for (i = 0; list[i]; ++i)
1174 /* If there is a single token, use its completion callback. */
1175 token = &token_list[list[0]];
1176 if (i == 1 && token->comp) {
1177 /* Save index for cmd_flow_get_help(). */
1178 ctx->prev = list[0];
1179 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1181 /* Otherwise make sure the index is valid and use defaults. */
1184 token = &token_list[list[index]];
1185 snprintf(dst, size, "%s", token->name);
1186 /* Save index for cmd_flow_get_help(). */
1187 ctx->prev = list[index];
1191 /** Populate help strings for current token (cmdline API). */
1193 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1195 struct context *ctx = &cmd_flow_context;
1196 const struct token *token = &token_list[ctx->prev];
1199 /* Tell cmd_flow_parse() that context must be reinitialized. */
1203 /* Set token type and update global help with details. */
1204 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1206 cmd_flow.help_str = token->help;
1208 cmd_flow.help_str = token->name;
1212 /** Token definition template (cmdline API). */
1213 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1214 .ops = &(struct cmdline_token_ops){
1215 .parse = cmd_flow_parse,
1216 .complete_get_nb = cmd_flow_complete_get_nb,
1217 .complete_get_elt = cmd_flow_complete_get_elt,
1218 .get_help = cmd_flow_get_help,
1223 /** Populate the next dynamic token. */
1225 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1226 cmdline_parse_token_hdr_t *(*hdrs)[])
1228 struct context *ctx = &cmd_flow_context;
1230 /* Always reinitialize context before requesting the first token. */
1232 cmd_flow_context_init(ctx);
1233 /* Return NULL when no more tokens are expected. */
1234 if (!ctx->next_num && ctx->curr) {
1238 /* Determine if command should end here. */
1239 if (ctx->eol && ctx->last && ctx->next_num) {
1240 const enum index *list = ctx->next[ctx->next_num - 1];
1243 for (i = 0; list[i]; ++i) {
1250 *hdr = &cmd_flow_token_hdr;
1253 /** Dispatch parsed buffer to function calls. */
1255 cmd_flow_parsed(const struct buffer *in)
1257 switch (in->command) {
1259 port_flow_validate(in->port, &in->args.vc.attr,
1260 in->args.vc.pattern, in->args.vc.actions);
1263 port_flow_create(in->port, &in->args.vc.attr,
1264 in->args.vc.pattern, in->args.vc.actions);
1267 port_flow_destroy(in->port, in->args.destroy.rule_n,
1268 in->args.destroy.rule);
1271 port_flow_flush(in->port);
1274 port_flow_query(in->port, in->args.query.rule,
1275 in->args.query.action);
1278 port_flow_list(in->port, in->args.list.group_n,
1279 in->args.list.group);
1286 /** Token generator and output processing callback (cmdline API). */
1288 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1291 cmd_flow_tok(arg0, arg2);
1293 cmd_flow_parsed(arg0);
1296 /** Global parser instance (cmdline API). */
1297 cmdline_parse_inst_t cmd_flow = {
1299 .data = NULL, /**< Unused. */
1300 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1303 }, /**< Tokens are returned by cmd_flow_tok(). */