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. */
101 /* Validate/create actions. */
109 /** Maximum number of subsequent tokens and arguments on the stack. */
110 #define CTX_STACK_SIZE 16
112 /** Parser context. */
114 /** Stack of subsequent token lists to process. */
115 const enum index *next[CTX_STACK_SIZE];
116 /** Arguments for stacked tokens. */
117 const void *args[CTX_STACK_SIZE];
118 enum index curr; /**< Current token index. */
119 enum index prev; /**< Index of the last token seen. */
120 int next_num; /**< Number of entries in next[]. */
121 int args_num; /**< Number of entries in args[]. */
122 uint32_t reparse:1; /**< Start over from the beginning. */
123 uint32_t eol:1; /**< EOL has been detected. */
124 uint32_t last:1; /**< No more arguments. */
125 uint16_t port; /**< Current port ID (for completions). */
126 uint32_t objdata; /**< Object-specific data. */
127 void *object; /**< Address of current object for relative offsets. */
128 void *objmask; /**< Object a full mask must be written to. */
131 /** Token argument. */
133 uint32_t hton:1; /**< Use network byte ordering. */
134 uint32_t sign:1; /**< Value is signed. */
135 uint32_t offset; /**< Relative offset from ctx->object. */
136 uint32_t size; /**< Field size. */
139 /** Parser token definition. */
141 /** Type displayed during completion (defaults to "TOKEN"). */
143 /** Help displayed during completion (defaults to token name). */
145 /** Private data used by parser functions. */
148 * Lists of subsequent tokens to push on the stack. Each call to the
149 * parser consumes the last entry of that stack.
151 const enum index *const *next;
152 /** Arguments stack for subsequent tokens that need them. */
153 const struct arg *const *args;
155 * Token-processing callback, returns -1 in case of error, the
156 * length of the matched string otherwise. If NULL, attempts to
157 * match the token name.
159 * If buf is not NULL, the result should be stored in it according
160 * to context. An error is returned if not large enough.
162 int (*call)(struct context *ctx, const struct token *token,
163 const char *str, unsigned int len,
164 void *buf, unsigned int size);
166 * Callback that provides possible values for this token, used for
167 * completion. Returns -1 in case of error, the number of possible
168 * values otherwise. If NULL, the token name is used.
170 * If buf is not NULL, entry index ent is written to buf and the
171 * full length of the entry is returned (same behavior as
174 int (*comp)(struct context *ctx, const struct token *token,
175 unsigned int ent, char *buf, unsigned int size);
176 /** Mandatory token name, no default value. */
180 /** Static initializer for the next field. */
181 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
183 /** Static initializer for a NEXT() entry. */
184 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
186 /** Static initializer for the args field. */
187 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
189 /** Static initializer for ARGS() to target a field. */
190 #define ARGS_ENTRY(s, f) \
191 (&(const struct arg){ \
192 .offset = offsetof(s, f), \
193 .size = sizeof(((s *)0)->f), \
196 /** Static initializer for ARGS() to target a pointer. */
197 #define ARGS_ENTRY_PTR(s, f) \
198 (&(const struct arg){ \
199 .size = sizeof(*((s *)0)->f), \
202 /** Parser output buffer layout expected by cmd_flow_parsed(). */
204 enum index command; /**< Flow command. */
205 uint16_t port; /**< Affected port ID. */
208 struct rte_flow_attr attr;
209 struct rte_flow_item *pattern;
210 struct rte_flow_action *actions;
214 } vc; /**< Validate/create arguments. */
218 } destroy; /**< Destroy arguments. */
221 enum rte_flow_action_type action;
222 } query; /**< Query arguments. */
226 } list; /**< List arguments. */
227 } args; /**< Command arguments. */
230 /** Private data for pattern items. */
231 struct parse_item_priv {
232 enum rte_flow_item_type type; /**< Item type. */
233 uint32_t size; /**< Size of item specification structure. */
236 #define PRIV_ITEM(t, s) \
237 (&(const struct parse_item_priv){ \
238 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
242 /** Private data for actions. */
243 struct parse_action_priv {
244 enum rte_flow_action_type type; /**< Action type. */
245 uint32_t size; /**< Size of action configuration structure. */
248 #define PRIV_ACTION(t, s) \
249 (&(const struct parse_action_priv){ \
250 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
254 static const enum index next_vc_attr[] = {
263 static const enum index next_destroy_attr[] = {
269 static const enum index next_list_attr[] = {
276 static const enum index item_param[] = {
284 static const enum index next_item[] = {
291 static const enum index next_action[] = {
298 static int parse_init(struct context *, const struct token *,
299 const char *, unsigned int,
300 void *, unsigned int);
301 static int parse_vc(struct context *, const struct token *,
302 const char *, unsigned int,
303 void *, unsigned int);
304 static int parse_vc_spec(struct context *, const struct token *,
305 const char *, unsigned int, void *, unsigned int);
306 static int parse_destroy(struct context *, const struct token *,
307 const char *, unsigned int,
308 void *, unsigned int);
309 static int parse_flush(struct context *, const struct token *,
310 const char *, unsigned int,
311 void *, unsigned int);
312 static int parse_query(struct context *, const struct token *,
313 const char *, unsigned int,
314 void *, unsigned int);
315 static int parse_action(struct context *, const struct token *,
316 const char *, unsigned int,
317 void *, unsigned int);
318 static int parse_list(struct context *, const struct token *,
319 const char *, unsigned int,
320 void *, unsigned int);
321 static int parse_int(struct context *, const struct token *,
322 const char *, unsigned int,
323 void *, unsigned int);
324 static int parse_port(struct context *, const struct token *,
325 const char *, unsigned int,
326 void *, unsigned int);
327 static int comp_none(struct context *, const struct token *,
328 unsigned int, char *, unsigned int);
329 static int comp_action(struct context *, const struct token *,
330 unsigned int, char *, unsigned int);
331 static int comp_port(struct context *, const struct token *,
332 unsigned int, char *, unsigned int);
333 static int comp_rule_id(struct context *, const struct token *,
334 unsigned int, char *, unsigned int);
336 /** Token definitions. */
337 static const struct token token_list[] = {
338 /* Special tokens. */
341 .help = "null entry, abused as the entry point",
342 .next = NEXT(NEXT_ENTRY(FLOW)),
347 .help = "command may end here",
353 .help = "integer value",
358 .name = "{unsigned}",
360 .help = "unsigned integer value",
367 .help = "rule identifier",
369 .comp = comp_rule_id,
374 .help = "port identifier",
379 .name = "{group_id}",
381 .help = "group identifier",
388 .help = "priority level",
392 /* Top-level command. */
395 .type = "{command} {port_id} [{arg} [...]]",
396 .help = "manage ingress/egress flow rules",
397 .next = NEXT(NEXT_ENTRY
406 /* Sub-level commands. */
409 .help = "check whether a flow rule can be created",
410 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
411 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
416 .help = "create a flow rule",
417 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
418 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
423 .help = "destroy specific flow rules",
424 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
425 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
426 .call = parse_destroy,
430 .help = "destroy all flow rules",
431 .next = NEXT(NEXT_ENTRY(PORT_ID)),
432 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
437 .help = "query an existing flow rule",
438 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
440 NEXT_ENTRY(PORT_ID)),
441 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
442 ARGS_ENTRY(struct buffer, args.query.rule),
443 ARGS_ENTRY(struct buffer, port)),
448 .help = "list existing flow rules",
449 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
450 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
453 /* Destroy arguments. */
456 .help = "specify a rule identifier",
457 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
458 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
459 .call = parse_destroy,
461 /* Query arguments. */
465 .help = "action to query, must be part of the rule",
466 .call = parse_action,
469 /* List arguments. */
472 .help = "specify a group",
473 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
474 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
477 /* Validate/create attributes. */
480 .help = "specify a group",
481 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
482 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
487 .help = "specify a priority level",
488 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
489 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
494 .help = "affect rule to ingress",
495 .next = NEXT(next_vc_attr),
500 .help = "affect rule to egress",
501 .next = NEXT(next_vc_attr),
504 /* Validate/create pattern. */
507 .help = "submit a list of pattern items",
508 .next = NEXT(next_item),
513 .help = "match value perfectly (with full bit-mask)",
514 .call = parse_vc_spec,
516 [ITEM_PARAM_SPEC] = {
518 .help = "match value according to configured bit-mask",
519 .call = parse_vc_spec,
521 [ITEM_PARAM_LAST] = {
523 .help = "specify upper bound to establish a range",
524 .call = parse_vc_spec,
526 [ITEM_PARAM_MASK] = {
528 .help = "specify bit-mask with relevant bits set to one",
529 .call = parse_vc_spec,
533 .help = "specify next pattern item",
534 .next = NEXT(next_item),
538 .help = "end list of pattern items",
539 .priv = PRIV_ITEM(END, 0),
540 .next = NEXT(NEXT_ENTRY(ACTIONS)),
545 .help = "no-op pattern item",
546 .priv = PRIV_ITEM(VOID, 0),
547 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
552 .help = "perform actions when pattern does not match",
553 .priv = PRIV_ITEM(INVERT, 0),
554 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
557 /* Validate/create actions. */
560 .help = "submit a list of associated actions",
561 .next = NEXT(next_action),
566 .help = "specify next action",
567 .next = NEXT(next_action),
571 .help = "end list of actions",
572 .priv = PRIV_ACTION(END, 0),
577 .help = "no-op action",
578 .priv = PRIV_ACTION(VOID, 0),
579 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
582 [ACTION_PASSTHRU] = {
584 .help = "let subsequent rule process matched packets",
585 .priv = PRIV_ACTION(PASSTHRU, 0),
586 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
591 /** Remove and return last entry from argument stack. */
592 static const struct arg *
593 pop_args(struct context *ctx)
595 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
598 /** Add entry on top of the argument stack. */
600 push_args(struct context *ctx, const struct arg *arg)
602 if (ctx->args_num == CTX_STACK_SIZE)
604 ctx->args[ctx->args_num++] = arg;
608 /** Default parsing function for token name matching. */
610 parse_default(struct context *ctx, const struct token *token,
611 const char *str, unsigned int len,
612 void *buf, unsigned int size)
617 if (strncmp(str, token->name, len))
622 /** Parse flow command, initialize output buffer for subsequent tokens. */
624 parse_init(struct context *ctx, const struct token *token,
625 const char *str, unsigned int len,
626 void *buf, unsigned int size)
628 struct buffer *out = buf;
630 /* Token name must match. */
631 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
633 /* Nothing else to do if there is no buffer. */
636 /* Make sure buffer is large enough. */
637 if (size < sizeof(*out))
639 /* Initialize buffer. */
640 memset(out, 0x00, sizeof(*out));
641 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
648 /** Parse tokens for validate/create commands. */
650 parse_vc(struct context *ctx, const struct token *token,
651 const char *str, unsigned int len,
652 void *buf, unsigned int size)
654 struct buffer *out = buf;
658 /* Token name must match. */
659 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
661 /* Nothing else to do if there is no buffer. */
665 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
667 if (sizeof(*out) > size)
669 out->command = ctx->curr;
673 out->args.vc.data = (uint8_t *)out + size;
677 ctx->object = &out->args.vc.attr;
684 out->args.vc.attr.ingress = 1;
687 out->args.vc.attr.egress = 1;
690 out->args.vc.pattern =
691 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
693 ctx->object = out->args.vc.pattern;
697 out->args.vc.actions =
698 (void *)RTE_ALIGN_CEIL((uintptr_t)
699 (out->args.vc.pattern +
700 out->args.vc.pattern_n),
702 ctx->object = out->args.vc.actions;
710 if (!out->args.vc.actions) {
711 const struct parse_item_priv *priv = token->priv;
712 struct rte_flow_item *item =
713 out->args.vc.pattern + out->args.vc.pattern_n;
715 data_size = priv->size * 3; /* spec, last, mask */
716 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
717 (out->args.vc.data - data_size),
719 if ((uint8_t *)item + sizeof(*item) > data)
721 *item = (struct rte_flow_item){
724 ++out->args.vc.pattern_n;
728 const struct parse_action_priv *priv = token->priv;
729 struct rte_flow_action *action =
730 out->args.vc.actions + out->args.vc.actions_n;
732 data_size = priv->size; /* configuration */
733 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
734 (out->args.vc.data - data_size),
736 if ((uint8_t *)action + sizeof(*action) > data)
738 *action = (struct rte_flow_action){
741 ++out->args.vc.actions_n;
742 ctx->object = action;
745 memset(data, 0, data_size);
746 out->args.vc.data = data;
747 ctx->objdata = data_size;
751 /** Parse pattern item parameter type. */
753 parse_vc_spec(struct context *ctx, const struct token *token,
754 const char *str, unsigned int len,
755 void *buf, unsigned int size)
757 struct buffer *out = buf;
758 struct rte_flow_item *item;
764 /* Token name must match. */
765 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
767 /* Parse parameter types. */
773 case ITEM_PARAM_SPEC:
776 case ITEM_PARAM_LAST:
779 case ITEM_PARAM_MASK:
785 /* Nothing else to do if there is no buffer. */
788 if (!out->args.vc.pattern_n)
790 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
791 data_size = ctx->objdata / 3; /* spec, last, mask */
792 /* Point to selected object. */
793 ctx->object = out->args.vc.data + (data_size * index);
795 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
796 item->mask = ctx->objmask;
799 /* Update relevant item pointer. */
800 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
805 /** Parse tokens for destroy command. */
807 parse_destroy(struct context *ctx, const struct token *token,
808 const char *str, unsigned int len,
809 void *buf, unsigned int size)
811 struct buffer *out = buf;
813 /* Token name must match. */
814 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
816 /* Nothing else to do if there is no buffer. */
820 if (ctx->curr != DESTROY)
822 if (sizeof(*out) > size)
824 out->command = ctx->curr;
828 out->args.destroy.rule =
829 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
833 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
834 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
837 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
842 /** Parse tokens for flush command. */
844 parse_flush(struct context *ctx, const struct token *token,
845 const char *str, unsigned int len,
846 void *buf, unsigned int size)
848 struct buffer *out = buf;
850 /* Token name must match. */
851 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
853 /* Nothing else to do if there is no buffer. */
857 if (ctx->curr != FLUSH)
859 if (sizeof(*out) > size)
861 out->command = ctx->curr;
869 /** Parse tokens for query command. */
871 parse_query(struct context *ctx, const struct token *token,
872 const char *str, unsigned int len,
873 void *buf, unsigned int size)
875 struct buffer *out = buf;
877 /* Token name must match. */
878 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
880 /* Nothing else to do if there is no buffer. */
884 if (ctx->curr != QUERY)
886 if (sizeof(*out) > size)
888 out->command = ctx->curr;
896 /** Parse action names. */
898 parse_action(struct context *ctx, const struct token *token,
899 const char *str, unsigned int len,
900 void *buf, unsigned int size)
902 struct buffer *out = buf;
903 const struct arg *arg = pop_args(ctx);
907 /* Argument is expected. */
910 /* Parse action name. */
911 for (i = 0; next_action[i]; ++i) {
912 const struct parse_action_priv *priv;
914 token = &token_list[next_action[i]];
915 if (strncmp(token->name, str, len))
921 memcpy((uint8_t *)ctx->object + arg->offset,
931 /** Parse tokens for list command. */
933 parse_list(struct context *ctx, const struct token *token,
934 const char *str, unsigned int len,
935 void *buf, unsigned int size)
937 struct buffer *out = buf;
939 /* Token name must match. */
940 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
942 /* Nothing else to do if there is no buffer. */
946 if (ctx->curr != LIST)
948 if (sizeof(*out) > size)
950 out->command = ctx->curr;
954 out->args.list.group =
955 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
959 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
960 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
963 ctx->object = out->args.list.group + out->args.list.group_n++;
969 * Parse signed/unsigned integers 8 to 64-bit long.
971 * Last argument (ctx->args) is retrieved to determine integer type and
975 parse_int(struct context *ctx, const struct token *token,
976 const char *str, unsigned int len,
977 void *buf, unsigned int size)
979 const struct arg *arg = pop_args(ctx);
984 /* Argument is expected. */
989 (uintmax_t)strtoimax(str, &end, 0) :
990 strtoumax(str, &end, 0);
991 if (errno || (size_t)(end - str) != len)
995 buf = (uint8_t *)ctx->object + arg->offset;
999 case sizeof(uint8_t):
1000 *(uint8_t *)buf = u;
1002 case sizeof(uint16_t):
1003 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1005 case sizeof(uint32_t):
1006 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1008 case sizeof(uint64_t):
1009 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1014 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1016 buf = (uint8_t *)ctx->objmask + arg->offset;
1021 push_args(ctx, arg);
1025 /** Parse port and update context. */
1027 parse_port(struct context *ctx, const struct token *token,
1028 const char *str, unsigned int len,
1029 void *buf, unsigned int size)
1031 struct buffer *out = &(struct buffer){ .port = 0 };
1039 ctx->objmask = NULL;
1040 size = sizeof(*out);
1042 ret = parse_int(ctx, token, str, len, out, size);
1044 ctx->port = out->port;
1050 /** No completion. */
1052 comp_none(struct context *ctx, const struct token *token,
1053 unsigned int ent, char *buf, unsigned int size)
1063 /** Complete action names. */
1065 comp_action(struct context *ctx, const struct token *token,
1066 unsigned int ent, char *buf, unsigned int size)
1072 for (i = 0; next_action[i]; ++i)
1073 if (buf && i == ent)
1074 return snprintf(buf, size, "%s",
1075 token_list[next_action[i]].name);
1081 /** Complete available ports. */
1083 comp_port(struct context *ctx, const struct token *token,
1084 unsigned int ent, char *buf, unsigned int size)
1091 FOREACH_PORT(p, ports) {
1092 if (buf && i == ent)
1093 return snprintf(buf, size, "%u", p);
1101 /** Complete available rule IDs. */
1103 comp_rule_id(struct context *ctx, const struct token *token,
1104 unsigned int ent, char *buf, unsigned int size)
1107 struct rte_port *port;
1108 struct port_flow *pf;
1111 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1112 ctx->port == (uint16_t)RTE_PORT_ALL)
1114 port = &ports[ctx->port];
1115 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1116 if (buf && i == ent)
1117 return snprintf(buf, size, "%u", pf->id);
1125 /** Internal context. */
1126 static struct context cmd_flow_context;
1128 /** Global parser instance (cmdline API). */
1129 cmdline_parse_inst_t cmd_flow;
1131 /** Initialize context. */
1133 cmd_flow_context_init(struct context *ctx)
1135 /* A full memset() is not necessary. */
1146 ctx->objmask = NULL;
1149 /** Parse a token (cmdline API). */
1151 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1154 struct context *ctx = &cmd_flow_context;
1155 const struct token *token;
1156 const enum index *list;
1161 /* Restart as requested. */
1163 cmd_flow_context_init(ctx);
1164 token = &token_list[ctx->curr];
1165 /* Check argument length. */
1168 for (len = 0; src[len]; ++len)
1169 if (src[len] == '#' || isspace(src[len]))
1173 /* Last argument and EOL detection. */
1174 for (i = len; src[i]; ++i)
1175 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1177 else if (!isspace(src[i])) {
1182 if (src[i] == '\r' || src[i] == '\n') {
1186 /* Initialize context if necessary. */
1187 if (!ctx->next_num) {
1190 ctx->next[ctx->next_num++] = token->next[0];
1192 /* Process argument through candidates. */
1193 ctx->prev = ctx->curr;
1194 list = ctx->next[ctx->next_num - 1];
1195 for (i = 0; list[i]; ++i) {
1196 const struct token *next = &token_list[list[i]];
1199 ctx->curr = list[i];
1201 tmp = next->call(ctx, next, src, len, result, size);
1203 tmp = parse_default(ctx, next, src, len, result, size);
1204 if (tmp == -1 || tmp != len)
1212 /* Push subsequent tokens if any. */
1214 for (i = 0; token->next[i]; ++i) {
1215 if (ctx->next_num == RTE_DIM(ctx->next))
1217 ctx->next[ctx->next_num++] = token->next[i];
1219 /* Push arguments if any. */
1221 for (i = 0; token->args[i]; ++i) {
1222 if (ctx->args_num == RTE_DIM(ctx->args))
1224 ctx->args[ctx->args_num++] = token->args[i];
1229 /** Return number of completion entries (cmdline API). */
1231 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1233 struct context *ctx = &cmd_flow_context;
1234 const struct token *token = &token_list[ctx->curr];
1235 const enum index *list;
1239 /* Tell cmd_flow_parse() that context must be reinitialized. */
1241 /* Count number of tokens in current list. */
1243 list = ctx->next[ctx->next_num - 1];
1245 list = token->next[0];
1246 for (i = 0; list[i]; ++i)
1251 * If there is a single token, use its completion callback, otherwise
1252 * return the number of entries.
1254 token = &token_list[list[0]];
1255 if (i == 1 && token->comp) {
1256 /* Save index for cmd_flow_get_help(). */
1257 ctx->prev = list[0];
1258 return token->comp(ctx, token, 0, NULL, 0);
1263 /** Return a completion entry (cmdline API). */
1265 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1266 char *dst, unsigned int size)
1268 struct context *ctx = &cmd_flow_context;
1269 const struct token *token = &token_list[ctx->curr];
1270 const enum index *list;
1274 /* Tell cmd_flow_parse() that context must be reinitialized. */
1276 /* Count number of tokens in current list. */
1278 list = ctx->next[ctx->next_num - 1];
1280 list = token->next[0];
1281 for (i = 0; list[i]; ++i)
1285 /* If there is a single token, use its completion callback. */
1286 token = &token_list[list[0]];
1287 if (i == 1 && token->comp) {
1288 /* Save index for cmd_flow_get_help(). */
1289 ctx->prev = list[0];
1290 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1292 /* Otherwise make sure the index is valid and use defaults. */
1295 token = &token_list[list[index]];
1296 snprintf(dst, size, "%s", token->name);
1297 /* Save index for cmd_flow_get_help(). */
1298 ctx->prev = list[index];
1302 /** Populate help strings for current token (cmdline API). */
1304 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1306 struct context *ctx = &cmd_flow_context;
1307 const struct token *token = &token_list[ctx->prev];
1310 /* Tell cmd_flow_parse() that context must be reinitialized. */
1314 /* Set token type and update global help with details. */
1315 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1317 cmd_flow.help_str = token->help;
1319 cmd_flow.help_str = token->name;
1323 /** Token definition template (cmdline API). */
1324 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1325 .ops = &(struct cmdline_token_ops){
1326 .parse = cmd_flow_parse,
1327 .complete_get_nb = cmd_flow_complete_get_nb,
1328 .complete_get_elt = cmd_flow_complete_get_elt,
1329 .get_help = cmd_flow_get_help,
1334 /** Populate the next dynamic token. */
1336 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1337 cmdline_parse_token_hdr_t *(*hdrs)[])
1339 struct context *ctx = &cmd_flow_context;
1341 /* Always reinitialize context before requesting the first token. */
1343 cmd_flow_context_init(ctx);
1344 /* Return NULL when no more tokens are expected. */
1345 if (!ctx->next_num && ctx->curr) {
1349 /* Determine if command should end here. */
1350 if (ctx->eol && ctx->last && ctx->next_num) {
1351 const enum index *list = ctx->next[ctx->next_num - 1];
1354 for (i = 0; list[i]; ++i) {
1361 *hdr = &cmd_flow_token_hdr;
1364 /** Dispatch parsed buffer to function calls. */
1366 cmd_flow_parsed(const struct buffer *in)
1368 switch (in->command) {
1370 port_flow_validate(in->port, &in->args.vc.attr,
1371 in->args.vc.pattern, in->args.vc.actions);
1374 port_flow_create(in->port, &in->args.vc.attr,
1375 in->args.vc.pattern, in->args.vc.actions);
1378 port_flow_destroy(in->port, in->args.destroy.rule_n,
1379 in->args.destroy.rule);
1382 port_flow_flush(in->port);
1385 port_flow_query(in->port, in->args.query.rule,
1386 in->args.query.action);
1389 port_flow_list(in->port, in->args.list.group_n,
1390 in->args.list.group);
1397 /** Token generator and output processing callback (cmdline API). */
1399 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1402 cmd_flow_tok(arg0, arg2);
1404 cmd_flow_parsed(arg0);
1407 /** Global parser instance (cmdline API). */
1408 cmdline_parse_inst_t cmd_flow = {
1410 .data = NULL, /**< Unused. */
1411 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1414 }, /**< Tokens are returned by cmd_flow_tok(). */