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. */
103 /* Validate/create actions. */
111 /** Maximum number of subsequent tokens and arguments on the stack. */
112 #define CTX_STACK_SIZE 16
114 /** Parser context. */
116 /** Stack of subsequent token lists to process. */
117 const enum index *next[CTX_STACK_SIZE];
118 /** Arguments for stacked tokens. */
119 const void *args[CTX_STACK_SIZE];
120 enum index curr; /**< Current token index. */
121 enum index prev; /**< Index of the last token seen. */
122 int next_num; /**< Number of entries in next[]. */
123 int args_num; /**< Number of entries in args[]. */
124 uint32_t reparse:1; /**< Start over from the beginning. */
125 uint32_t eol:1; /**< EOL has been detected. */
126 uint32_t last:1; /**< No more arguments. */
127 uint16_t port; /**< Current port ID (for completions). */
128 uint32_t objdata; /**< Object-specific data. */
129 void *object; /**< Address of current object for relative offsets. */
130 void *objmask; /**< Object a full mask must be written to. */
133 /** Token argument. */
135 uint32_t hton:1; /**< Use network byte ordering. */
136 uint32_t sign:1; /**< Value is signed. */
137 uint32_t offset; /**< Relative offset from ctx->object. */
138 uint32_t size; /**< Field size. */
141 /** Parser token definition. */
143 /** Type displayed during completion (defaults to "TOKEN"). */
145 /** Help displayed during completion (defaults to token name). */
147 /** Private data used by parser functions. */
150 * Lists of subsequent tokens to push on the stack. Each call to the
151 * parser consumes the last entry of that stack.
153 const enum index *const *next;
154 /** Arguments stack for subsequent tokens that need them. */
155 const struct arg *const *args;
157 * Token-processing callback, returns -1 in case of error, the
158 * length of the matched string otherwise. If NULL, attempts to
159 * match the token name.
161 * If buf is not NULL, the result should be stored in it according
162 * to context. An error is returned if not large enough.
164 int (*call)(struct context *ctx, const struct token *token,
165 const char *str, unsigned int len,
166 void *buf, unsigned int size);
168 * Callback that provides possible values for this token, used for
169 * completion. Returns -1 in case of error, the number of possible
170 * values otherwise. If NULL, the token name is used.
172 * If buf is not NULL, entry index ent is written to buf and the
173 * full length of the entry is returned (same behavior as
176 int (*comp)(struct context *ctx, const struct token *token,
177 unsigned int ent, char *buf, unsigned int size);
178 /** Mandatory token name, no default value. */
182 /** Static initializer for the next field. */
183 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
185 /** Static initializer for a NEXT() entry. */
186 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
188 /** Static initializer for the args field. */
189 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
191 /** Static initializer for ARGS() to target a field. */
192 #define ARGS_ENTRY(s, f) \
193 (&(const struct arg){ \
194 .offset = offsetof(s, f), \
195 .size = sizeof(((s *)0)->f), \
198 /** Static initializer for ARGS() to target a pointer. */
199 #define ARGS_ENTRY_PTR(s, f) \
200 (&(const struct arg){ \
201 .size = sizeof(*((s *)0)->f), \
204 /** Parser output buffer layout expected by cmd_flow_parsed(). */
206 enum index command; /**< Flow command. */
207 uint16_t port; /**< Affected port ID. */
210 struct rte_flow_attr attr;
211 struct rte_flow_item *pattern;
212 struct rte_flow_action *actions;
216 } vc; /**< Validate/create arguments. */
220 } destroy; /**< Destroy arguments. */
223 enum rte_flow_action_type action;
224 } query; /**< Query arguments. */
228 } list; /**< List arguments. */
229 } args; /**< Command arguments. */
232 /** Private data for pattern items. */
233 struct parse_item_priv {
234 enum rte_flow_item_type type; /**< Item type. */
235 uint32_t size; /**< Size of item specification structure. */
238 #define PRIV_ITEM(t, s) \
239 (&(const struct parse_item_priv){ \
240 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
244 /** Private data for actions. */
245 struct parse_action_priv {
246 enum rte_flow_action_type type; /**< Action type. */
247 uint32_t size; /**< Size of action configuration structure. */
250 #define PRIV_ACTION(t, s) \
251 (&(const struct parse_action_priv){ \
252 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
256 static const enum index next_vc_attr[] = {
265 static const enum index next_destroy_attr[] = {
271 static const enum index next_list_attr[] = {
278 static const enum index item_param[] = {
287 static const enum index next_item[] = {
294 static const enum index next_action[] = {
301 static int parse_init(struct context *, const struct token *,
302 const char *, unsigned int,
303 void *, unsigned int);
304 static int parse_vc(struct context *, const struct token *,
305 const char *, unsigned int,
306 void *, unsigned int);
307 static int parse_vc_spec(struct context *, const struct token *,
308 const char *, unsigned int, void *, unsigned int);
309 static int parse_destroy(struct context *, const struct token *,
310 const char *, unsigned int,
311 void *, unsigned int);
312 static int parse_flush(struct context *, const struct token *,
313 const char *, unsigned int,
314 void *, unsigned int);
315 static int parse_query(struct context *, const struct token *,
316 const char *, unsigned int,
317 void *, unsigned int);
318 static int parse_action(struct context *, const struct token *,
319 const char *, unsigned int,
320 void *, unsigned int);
321 static int parse_list(struct context *, const struct token *,
322 const char *, unsigned int,
323 void *, unsigned int);
324 static int parse_int(struct context *, const struct token *,
325 const char *, unsigned int,
326 void *, unsigned int);
327 static int parse_prefix(struct context *, const struct token *,
328 const char *, unsigned int,
329 void *, unsigned int);
330 static int parse_port(struct context *, const struct token *,
331 const char *, unsigned int,
332 void *, unsigned int);
333 static int comp_none(struct context *, const struct token *,
334 unsigned int, char *, unsigned int);
335 static int comp_action(struct context *, const struct token *,
336 unsigned int, char *, unsigned int);
337 static int comp_port(struct context *, const struct token *,
338 unsigned int, char *, unsigned int);
339 static int comp_rule_id(struct context *, const struct token *,
340 unsigned int, char *, unsigned int);
342 /** Token definitions. */
343 static const struct token token_list[] = {
344 /* Special tokens. */
347 .help = "null entry, abused as the entry point",
348 .next = NEXT(NEXT_ENTRY(FLOW)),
353 .help = "command may end here",
359 .help = "integer value",
364 .name = "{unsigned}",
366 .help = "unsigned integer value",
373 .help = "prefix length for bit-mask",
374 .call = parse_prefix,
380 .help = "rule identifier",
382 .comp = comp_rule_id,
387 .help = "port identifier",
392 .name = "{group_id}",
394 .help = "group identifier",
401 .help = "priority level",
405 /* Top-level command. */
408 .type = "{command} {port_id} [{arg} [...]]",
409 .help = "manage ingress/egress flow rules",
410 .next = NEXT(NEXT_ENTRY
419 /* Sub-level commands. */
422 .help = "check whether a flow rule can be created",
423 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
424 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
429 .help = "create a flow rule",
430 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
431 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
436 .help = "destroy specific flow rules",
437 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
438 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
439 .call = parse_destroy,
443 .help = "destroy all flow rules",
444 .next = NEXT(NEXT_ENTRY(PORT_ID)),
445 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
450 .help = "query an existing flow rule",
451 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
453 NEXT_ENTRY(PORT_ID)),
454 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
455 ARGS_ENTRY(struct buffer, args.query.rule),
456 ARGS_ENTRY(struct buffer, port)),
461 .help = "list existing flow rules",
462 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
463 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
466 /* Destroy arguments. */
469 .help = "specify a rule identifier",
470 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
471 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
472 .call = parse_destroy,
474 /* Query arguments. */
478 .help = "action to query, must be part of the rule",
479 .call = parse_action,
482 /* List arguments. */
485 .help = "specify a group",
486 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
487 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
490 /* Validate/create attributes. */
493 .help = "specify a group",
494 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
495 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
500 .help = "specify a priority level",
501 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
502 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
507 .help = "affect rule to ingress",
508 .next = NEXT(next_vc_attr),
513 .help = "affect rule to egress",
514 .next = NEXT(next_vc_attr),
517 /* Validate/create pattern. */
520 .help = "submit a list of pattern items",
521 .next = NEXT(next_item),
526 .help = "match value perfectly (with full bit-mask)",
527 .call = parse_vc_spec,
529 [ITEM_PARAM_SPEC] = {
531 .help = "match value according to configured bit-mask",
532 .call = parse_vc_spec,
534 [ITEM_PARAM_LAST] = {
536 .help = "specify upper bound to establish a range",
537 .call = parse_vc_spec,
539 [ITEM_PARAM_MASK] = {
541 .help = "specify bit-mask with relevant bits set to one",
542 .call = parse_vc_spec,
544 [ITEM_PARAM_PREFIX] = {
546 .help = "generate bit-mask from a prefix length",
547 .call = parse_vc_spec,
551 .help = "specify next pattern item",
552 .next = NEXT(next_item),
556 .help = "end list of pattern items",
557 .priv = PRIV_ITEM(END, 0),
558 .next = NEXT(NEXT_ENTRY(ACTIONS)),
563 .help = "no-op pattern item",
564 .priv = PRIV_ITEM(VOID, 0),
565 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
570 .help = "perform actions when pattern does not match",
571 .priv = PRIV_ITEM(INVERT, 0),
572 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
575 /* Validate/create actions. */
578 .help = "submit a list of associated actions",
579 .next = NEXT(next_action),
584 .help = "specify next action",
585 .next = NEXT(next_action),
589 .help = "end list of actions",
590 .priv = PRIV_ACTION(END, 0),
595 .help = "no-op action",
596 .priv = PRIV_ACTION(VOID, 0),
597 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
600 [ACTION_PASSTHRU] = {
602 .help = "let subsequent rule process matched packets",
603 .priv = PRIV_ACTION(PASSTHRU, 0),
604 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
609 /** Remove and return last entry from argument stack. */
610 static const struct arg *
611 pop_args(struct context *ctx)
613 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
616 /** Add entry on top of the argument stack. */
618 push_args(struct context *ctx, const struct arg *arg)
620 if (ctx->args_num == CTX_STACK_SIZE)
622 ctx->args[ctx->args_num++] = arg;
627 * Parse a prefix length and generate a bit-mask.
629 * Last argument (ctx->args) is retrieved to determine mask size, storage
630 * location and whether the result must use network byte ordering.
633 parse_prefix(struct context *ctx, const struct token *token,
634 const char *str, unsigned int len,
635 void *buf, unsigned int size)
637 const struct arg *arg = pop_args(ctx);
638 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
645 /* Argument is expected. */
649 u = strtoumax(str, &end, 0);
650 if (errno || (size_t)(end - str) != len)
655 if (bytes > size || bytes + !!extra > size)
659 buf = (uint8_t *)ctx->object + arg->offset;
660 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
662 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
663 memset(buf, 0x00, size - bytes);
665 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
669 memset(buf, 0xff, bytes);
670 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
672 ((uint8_t *)buf)[bytes] = conv[extra];
675 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
682 /** Default parsing function for token name matching. */
684 parse_default(struct context *ctx, const struct token *token,
685 const char *str, unsigned int len,
686 void *buf, unsigned int size)
691 if (strncmp(str, token->name, len))
696 /** Parse flow command, initialize output buffer for subsequent tokens. */
698 parse_init(struct context *ctx, const struct token *token,
699 const char *str, unsigned int len,
700 void *buf, unsigned int size)
702 struct buffer *out = buf;
704 /* Token name must match. */
705 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
707 /* Nothing else to do if there is no buffer. */
710 /* Make sure buffer is large enough. */
711 if (size < sizeof(*out))
713 /* Initialize buffer. */
714 memset(out, 0x00, sizeof(*out));
715 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
722 /** Parse tokens for validate/create commands. */
724 parse_vc(struct context *ctx, const struct token *token,
725 const char *str, unsigned int len,
726 void *buf, unsigned int size)
728 struct buffer *out = buf;
732 /* Token name must match. */
733 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
735 /* Nothing else to do if there is no buffer. */
739 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
741 if (sizeof(*out) > size)
743 out->command = ctx->curr;
747 out->args.vc.data = (uint8_t *)out + size;
751 ctx->object = &out->args.vc.attr;
758 out->args.vc.attr.ingress = 1;
761 out->args.vc.attr.egress = 1;
764 out->args.vc.pattern =
765 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
767 ctx->object = out->args.vc.pattern;
771 out->args.vc.actions =
772 (void *)RTE_ALIGN_CEIL((uintptr_t)
773 (out->args.vc.pattern +
774 out->args.vc.pattern_n),
776 ctx->object = out->args.vc.actions;
784 if (!out->args.vc.actions) {
785 const struct parse_item_priv *priv = token->priv;
786 struct rte_flow_item *item =
787 out->args.vc.pattern + out->args.vc.pattern_n;
789 data_size = priv->size * 3; /* spec, last, mask */
790 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
791 (out->args.vc.data - data_size),
793 if ((uint8_t *)item + sizeof(*item) > data)
795 *item = (struct rte_flow_item){
798 ++out->args.vc.pattern_n;
802 const struct parse_action_priv *priv = token->priv;
803 struct rte_flow_action *action =
804 out->args.vc.actions + out->args.vc.actions_n;
806 data_size = priv->size; /* configuration */
807 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
808 (out->args.vc.data - data_size),
810 if ((uint8_t *)action + sizeof(*action) > data)
812 *action = (struct rte_flow_action){
815 ++out->args.vc.actions_n;
816 ctx->object = action;
819 memset(data, 0, data_size);
820 out->args.vc.data = data;
821 ctx->objdata = data_size;
825 /** Parse pattern item parameter type. */
827 parse_vc_spec(struct context *ctx, const struct token *token,
828 const char *str, unsigned int len,
829 void *buf, unsigned int size)
831 struct buffer *out = buf;
832 struct rte_flow_item *item;
838 /* Token name must match. */
839 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
841 /* Parse parameter types. */
847 case ITEM_PARAM_SPEC:
850 case ITEM_PARAM_LAST:
853 case ITEM_PARAM_PREFIX:
854 /* Modify next token to expect a prefix. */
855 if (ctx->next_num < 2)
857 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
859 case ITEM_PARAM_MASK:
865 /* Nothing else to do if there is no buffer. */
868 if (!out->args.vc.pattern_n)
870 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
871 data_size = ctx->objdata / 3; /* spec, last, mask */
872 /* Point to selected object. */
873 ctx->object = out->args.vc.data + (data_size * index);
875 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
876 item->mask = ctx->objmask;
879 /* Update relevant item pointer. */
880 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
885 /** Parse tokens for destroy command. */
887 parse_destroy(struct context *ctx, const struct token *token,
888 const char *str, unsigned int len,
889 void *buf, unsigned int size)
891 struct buffer *out = buf;
893 /* Token name must match. */
894 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
896 /* Nothing else to do if there is no buffer. */
900 if (ctx->curr != DESTROY)
902 if (sizeof(*out) > size)
904 out->command = ctx->curr;
908 out->args.destroy.rule =
909 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
913 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
914 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
917 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
922 /** Parse tokens for flush command. */
924 parse_flush(struct context *ctx, const struct token *token,
925 const char *str, unsigned int len,
926 void *buf, unsigned int size)
928 struct buffer *out = buf;
930 /* Token name must match. */
931 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
933 /* Nothing else to do if there is no buffer. */
937 if (ctx->curr != FLUSH)
939 if (sizeof(*out) > size)
941 out->command = ctx->curr;
949 /** Parse tokens for query command. */
951 parse_query(struct context *ctx, const struct token *token,
952 const char *str, unsigned int len,
953 void *buf, unsigned int size)
955 struct buffer *out = buf;
957 /* Token name must match. */
958 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
960 /* Nothing else to do if there is no buffer. */
964 if (ctx->curr != QUERY)
966 if (sizeof(*out) > size)
968 out->command = ctx->curr;
976 /** Parse action names. */
978 parse_action(struct context *ctx, const struct token *token,
979 const char *str, unsigned int len,
980 void *buf, unsigned int size)
982 struct buffer *out = buf;
983 const struct arg *arg = pop_args(ctx);
987 /* Argument is expected. */
990 /* Parse action name. */
991 for (i = 0; next_action[i]; ++i) {
992 const struct parse_action_priv *priv;
994 token = &token_list[next_action[i]];
995 if (strncmp(token->name, str, len))
1001 memcpy((uint8_t *)ctx->object + arg->offset,
1007 push_args(ctx, arg);
1011 /** Parse tokens for list command. */
1013 parse_list(struct context *ctx, const struct token *token,
1014 const char *str, unsigned int len,
1015 void *buf, unsigned int size)
1017 struct buffer *out = buf;
1019 /* Token name must match. */
1020 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1022 /* Nothing else to do if there is no buffer. */
1025 if (!out->command) {
1026 if (ctx->curr != LIST)
1028 if (sizeof(*out) > size)
1030 out->command = ctx->curr;
1033 ctx->objmask = NULL;
1034 out->args.list.group =
1035 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1039 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
1040 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
1043 ctx->object = out->args.list.group + out->args.list.group_n++;
1044 ctx->objmask = NULL;
1049 * Parse signed/unsigned integers 8 to 64-bit long.
1051 * Last argument (ctx->args) is retrieved to determine integer type and
1055 parse_int(struct context *ctx, const struct token *token,
1056 const char *str, unsigned int len,
1057 void *buf, unsigned int size)
1059 const struct arg *arg = pop_args(ctx);
1064 /* Argument is expected. */
1069 (uintmax_t)strtoimax(str, &end, 0) :
1070 strtoumax(str, &end, 0);
1071 if (errno || (size_t)(end - str) != len)
1075 buf = (uint8_t *)ctx->object + arg->offset;
1079 case sizeof(uint8_t):
1080 *(uint8_t *)buf = u;
1082 case sizeof(uint16_t):
1083 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1085 case sizeof(uint32_t):
1086 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1088 case sizeof(uint64_t):
1089 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1094 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1096 buf = (uint8_t *)ctx->objmask + arg->offset;
1101 push_args(ctx, arg);
1105 /** Parse port and update context. */
1107 parse_port(struct context *ctx, const struct token *token,
1108 const char *str, unsigned int len,
1109 void *buf, unsigned int size)
1111 struct buffer *out = &(struct buffer){ .port = 0 };
1119 ctx->objmask = NULL;
1120 size = sizeof(*out);
1122 ret = parse_int(ctx, token, str, len, out, size);
1124 ctx->port = out->port;
1130 /** No completion. */
1132 comp_none(struct context *ctx, const struct token *token,
1133 unsigned int ent, char *buf, unsigned int size)
1143 /** Complete action names. */
1145 comp_action(struct context *ctx, const struct token *token,
1146 unsigned int ent, char *buf, unsigned int size)
1152 for (i = 0; next_action[i]; ++i)
1153 if (buf && i == ent)
1154 return snprintf(buf, size, "%s",
1155 token_list[next_action[i]].name);
1161 /** Complete available ports. */
1163 comp_port(struct context *ctx, const struct token *token,
1164 unsigned int ent, char *buf, unsigned int size)
1171 FOREACH_PORT(p, ports) {
1172 if (buf && i == ent)
1173 return snprintf(buf, size, "%u", p);
1181 /** Complete available rule IDs. */
1183 comp_rule_id(struct context *ctx, const struct token *token,
1184 unsigned int ent, char *buf, unsigned int size)
1187 struct rte_port *port;
1188 struct port_flow *pf;
1191 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1192 ctx->port == (uint16_t)RTE_PORT_ALL)
1194 port = &ports[ctx->port];
1195 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1196 if (buf && i == ent)
1197 return snprintf(buf, size, "%u", pf->id);
1205 /** Internal context. */
1206 static struct context cmd_flow_context;
1208 /** Global parser instance (cmdline API). */
1209 cmdline_parse_inst_t cmd_flow;
1211 /** Initialize context. */
1213 cmd_flow_context_init(struct context *ctx)
1215 /* A full memset() is not necessary. */
1226 ctx->objmask = NULL;
1229 /** Parse a token (cmdline API). */
1231 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1234 struct context *ctx = &cmd_flow_context;
1235 const struct token *token;
1236 const enum index *list;
1241 /* Restart as requested. */
1243 cmd_flow_context_init(ctx);
1244 token = &token_list[ctx->curr];
1245 /* Check argument length. */
1248 for (len = 0; src[len]; ++len)
1249 if (src[len] == '#' || isspace(src[len]))
1253 /* Last argument and EOL detection. */
1254 for (i = len; src[i]; ++i)
1255 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1257 else if (!isspace(src[i])) {
1262 if (src[i] == '\r' || src[i] == '\n') {
1266 /* Initialize context if necessary. */
1267 if (!ctx->next_num) {
1270 ctx->next[ctx->next_num++] = token->next[0];
1272 /* Process argument through candidates. */
1273 ctx->prev = ctx->curr;
1274 list = ctx->next[ctx->next_num - 1];
1275 for (i = 0; list[i]; ++i) {
1276 const struct token *next = &token_list[list[i]];
1279 ctx->curr = list[i];
1281 tmp = next->call(ctx, next, src, len, result, size);
1283 tmp = parse_default(ctx, next, src, len, result, size);
1284 if (tmp == -1 || tmp != len)
1292 /* Push subsequent tokens if any. */
1294 for (i = 0; token->next[i]; ++i) {
1295 if (ctx->next_num == RTE_DIM(ctx->next))
1297 ctx->next[ctx->next_num++] = token->next[i];
1299 /* Push arguments if any. */
1301 for (i = 0; token->args[i]; ++i) {
1302 if (ctx->args_num == RTE_DIM(ctx->args))
1304 ctx->args[ctx->args_num++] = token->args[i];
1309 /** Return number of completion entries (cmdline API). */
1311 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1313 struct context *ctx = &cmd_flow_context;
1314 const struct token *token = &token_list[ctx->curr];
1315 const enum index *list;
1319 /* Tell cmd_flow_parse() that context must be reinitialized. */
1321 /* Count number of tokens in current list. */
1323 list = ctx->next[ctx->next_num - 1];
1325 list = token->next[0];
1326 for (i = 0; list[i]; ++i)
1331 * If there is a single token, use its completion callback, otherwise
1332 * return the number of entries.
1334 token = &token_list[list[0]];
1335 if (i == 1 && token->comp) {
1336 /* Save index for cmd_flow_get_help(). */
1337 ctx->prev = list[0];
1338 return token->comp(ctx, token, 0, NULL, 0);
1343 /** Return a completion entry (cmdline API). */
1345 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1346 char *dst, unsigned int size)
1348 struct context *ctx = &cmd_flow_context;
1349 const struct token *token = &token_list[ctx->curr];
1350 const enum index *list;
1354 /* Tell cmd_flow_parse() that context must be reinitialized. */
1356 /* Count number of tokens in current list. */
1358 list = ctx->next[ctx->next_num - 1];
1360 list = token->next[0];
1361 for (i = 0; list[i]; ++i)
1365 /* If there is a single token, use its completion callback. */
1366 token = &token_list[list[0]];
1367 if (i == 1 && token->comp) {
1368 /* Save index for cmd_flow_get_help(). */
1369 ctx->prev = list[0];
1370 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1372 /* Otherwise make sure the index is valid and use defaults. */
1375 token = &token_list[list[index]];
1376 snprintf(dst, size, "%s", token->name);
1377 /* Save index for cmd_flow_get_help(). */
1378 ctx->prev = list[index];
1382 /** Populate help strings for current token (cmdline API). */
1384 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1386 struct context *ctx = &cmd_flow_context;
1387 const struct token *token = &token_list[ctx->prev];
1390 /* Tell cmd_flow_parse() that context must be reinitialized. */
1394 /* Set token type and update global help with details. */
1395 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1397 cmd_flow.help_str = token->help;
1399 cmd_flow.help_str = token->name;
1403 /** Token definition template (cmdline API). */
1404 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1405 .ops = &(struct cmdline_token_ops){
1406 .parse = cmd_flow_parse,
1407 .complete_get_nb = cmd_flow_complete_get_nb,
1408 .complete_get_elt = cmd_flow_complete_get_elt,
1409 .get_help = cmd_flow_get_help,
1414 /** Populate the next dynamic token. */
1416 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1417 cmdline_parse_token_hdr_t *(*hdrs)[])
1419 struct context *ctx = &cmd_flow_context;
1421 /* Always reinitialize context before requesting the first token. */
1423 cmd_flow_context_init(ctx);
1424 /* Return NULL when no more tokens are expected. */
1425 if (!ctx->next_num && ctx->curr) {
1429 /* Determine if command should end here. */
1430 if (ctx->eol && ctx->last && ctx->next_num) {
1431 const enum index *list = ctx->next[ctx->next_num - 1];
1434 for (i = 0; list[i]; ++i) {
1441 *hdr = &cmd_flow_token_hdr;
1444 /** Dispatch parsed buffer to function calls. */
1446 cmd_flow_parsed(const struct buffer *in)
1448 switch (in->command) {
1450 port_flow_validate(in->port, &in->args.vc.attr,
1451 in->args.vc.pattern, in->args.vc.actions);
1454 port_flow_create(in->port, &in->args.vc.attr,
1455 in->args.vc.pattern, in->args.vc.actions);
1458 port_flow_destroy(in->port, in->args.destroy.rule_n,
1459 in->args.destroy.rule);
1462 port_flow_flush(in->port);
1465 port_flow_query(in->port, in->args.query.rule,
1466 in->args.query.action);
1469 port_flow_list(in->port, in->args.list.group_n,
1470 in->args.list.group);
1477 /** Token generator and output processing callback (cmdline API). */
1479 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1482 cmd_flow_tok(arg0, arg2);
1484 cmd_flow_parsed(arg0);
1487 /** Global parser instance (cmdline API). */
1488 cmdline_parse_inst_t cmd_flow = {
1490 .data = NULL, /**< Unused. */
1491 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1494 }, /**< Tokens are returned by cmd_flow_tok(). */