app/testpmd: support flow bit-field
[dpdk.git] / app / test-pmd / cmdline_flow.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2016 6WIND S.A.
5  *   Copyright 2016 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
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
16  *       distribution.
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.
20  *
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.
32  */
33
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <inttypes.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <string.h>
41
42 #include <rte_common.h>
43 #include <rte_ethdev.h>
44 #include <rte_byteorder.h>
45 #include <cmdline_parse.h>
46 #include <rte_flow.h>
47
48 #include "testpmd.h"
49
50 /** Parser token indices. */
51 enum index {
52         /* Special tokens. */
53         ZERO = 0,
54         END,
55
56         /* Common tokens. */
57         INTEGER,
58         UNSIGNED,
59         PREFIX,
60         RULE_ID,
61         PORT_ID,
62         GROUP_ID,
63         PRIORITY_LEVEL,
64
65         /* Top-level command. */
66         FLOW,
67
68         /* Sub-level commands. */
69         VALIDATE,
70         CREATE,
71         DESTROY,
72         FLUSH,
73         QUERY,
74         LIST,
75
76         /* Destroy arguments. */
77         DESTROY_RULE,
78
79         /* Query arguments. */
80         QUERY_ACTION,
81
82         /* List arguments. */
83         LIST_GROUP,
84
85         /* Validate/create arguments. */
86         GROUP,
87         PRIORITY,
88         INGRESS,
89         EGRESS,
90
91         /* Validate/create pattern. */
92         PATTERN,
93         ITEM_PARAM_IS,
94         ITEM_PARAM_SPEC,
95         ITEM_PARAM_LAST,
96         ITEM_PARAM_MASK,
97         ITEM_PARAM_PREFIX,
98         ITEM_NEXT,
99         ITEM_END,
100         ITEM_VOID,
101         ITEM_INVERT,
102
103         /* Validate/create actions. */
104         ACTIONS,
105         ACTION_NEXT,
106         ACTION_END,
107         ACTION_VOID,
108         ACTION_PASSTHRU,
109 };
110
111 /** Maximum number of subsequent tokens and arguments on the stack. */
112 #define CTX_STACK_SIZE 16
113
114 /** Parser context. */
115 struct 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. */
131 };
132
133 /** Token argument. */
134 struct arg {
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. */
139         const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
140 };
141
142 /** Parser token definition. */
143 struct token {
144         /** Type displayed during completion (defaults to "TOKEN"). */
145         const char *type;
146         /** Help displayed during completion (defaults to token name). */
147         const char *help;
148         /** Private data used by parser functions. */
149         const void *priv;
150         /**
151          * Lists of subsequent tokens to push on the stack. Each call to the
152          * parser consumes the last entry of that stack.
153          */
154         const enum index *const *next;
155         /** Arguments stack for subsequent tokens that need them. */
156         const struct arg *const *args;
157         /**
158          * Token-processing callback, returns -1 in case of error, the
159          * length of the matched string otherwise. If NULL, attempts to
160          * match the token name.
161          *
162          * If buf is not NULL, the result should be stored in it according
163          * to context. An error is returned if not large enough.
164          */
165         int (*call)(struct context *ctx, const struct token *token,
166                     const char *str, unsigned int len,
167                     void *buf, unsigned int size);
168         /**
169          * Callback that provides possible values for this token, used for
170          * completion. Returns -1 in case of error, the number of possible
171          * values otherwise. If NULL, the token name is used.
172          *
173          * If buf is not NULL, entry index ent is written to buf and the
174          * full length of the entry is returned (same behavior as
175          * snprintf()).
176          */
177         int (*comp)(struct context *ctx, const struct token *token,
178                     unsigned int ent, char *buf, unsigned int size);
179         /** Mandatory token name, no default value. */
180         const char *name;
181 };
182
183 /** Static initializer for the next field. */
184 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
185
186 /** Static initializer for a NEXT() entry. */
187 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
188
189 /** Static initializer for the args field. */
190 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
191
192 /** Static initializer for ARGS() to target a field. */
193 #define ARGS_ENTRY(s, f) \
194         (&(const struct arg){ \
195                 .offset = offsetof(s, f), \
196                 .size = sizeof(((s *)0)->f), \
197         })
198
199 /** Static initializer for ARGS() to target a bit-field. */
200 #define ARGS_ENTRY_BF(s, f, b) \
201         (&(const struct arg){ \
202                 .size = sizeof(s), \
203                 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
204         })
205
206 /** Static initializer for ARGS() to target a pointer. */
207 #define ARGS_ENTRY_PTR(s, f) \
208         (&(const struct arg){ \
209                 .size = sizeof(*((s *)0)->f), \
210         })
211
212 /** Parser output buffer layout expected by cmd_flow_parsed(). */
213 struct buffer {
214         enum index command; /**< Flow command. */
215         uint16_t port; /**< Affected port ID. */
216         union {
217                 struct {
218                         struct rte_flow_attr attr;
219                         struct rte_flow_item *pattern;
220                         struct rte_flow_action *actions;
221                         uint32_t pattern_n;
222                         uint32_t actions_n;
223                         uint8_t *data;
224                 } vc; /**< Validate/create arguments. */
225                 struct {
226                         uint32_t *rule;
227                         uint32_t rule_n;
228                 } destroy; /**< Destroy arguments. */
229                 struct {
230                         uint32_t rule;
231                         enum rte_flow_action_type action;
232                 } query; /**< Query arguments. */
233                 struct {
234                         uint32_t *group;
235                         uint32_t group_n;
236                 } list; /**< List arguments. */
237         } args; /**< Command arguments. */
238 };
239
240 /** Private data for pattern items. */
241 struct parse_item_priv {
242         enum rte_flow_item_type type; /**< Item type. */
243         uint32_t size; /**< Size of item specification structure. */
244 };
245
246 #define PRIV_ITEM(t, s) \
247         (&(const struct parse_item_priv){ \
248                 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
249                 .size = s, \
250         })
251
252 /** Private data for actions. */
253 struct parse_action_priv {
254         enum rte_flow_action_type type; /**< Action type. */
255         uint32_t size; /**< Size of action configuration structure. */
256 };
257
258 #define PRIV_ACTION(t, s) \
259         (&(const struct parse_action_priv){ \
260                 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
261                 .size = s, \
262         })
263
264 static const enum index next_vc_attr[] = {
265         GROUP,
266         PRIORITY,
267         INGRESS,
268         EGRESS,
269         PATTERN,
270         ZERO,
271 };
272
273 static const enum index next_destroy_attr[] = {
274         DESTROY_RULE,
275         END,
276         ZERO,
277 };
278
279 static const enum index next_list_attr[] = {
280         LIST_GROUP,
281         END,
282         ZERO,
283 };
284
285 __rte_unused
286 static const enum index item_param[] = {
287         ITEM_PARAM_IS,
288         ITEM_PARAM_SPEC,
289         ITEM_PARAM_LAST,
290         ITEM_PARAM_MASK,
291         ITEM_PARAM_PREFIX,
292         ZERO,
293 };
294
295 static const enum index next_item[] = {
296         ITEM_END,
297         ITEM_VOID,
298         ITEM_INVERT,
299         ZERO,
300 };
301
302 static const enum index next_action[] = {
303         ACTION_END,
304         ACTION_VOID,
305         ACTION_PASSTHRU,
306         ZERO,
307 };
308
309 static int parse_init(struct context *, const struct token *,
310                       const char *, unsigned int,
311                       void *, unsigned int);
312 static int parse_vc(struct context *, const struct token *,
313                     const char *, unsigned int,
314                     void *, unsigned int);
315 static int parse_vc_spec(struct context *, const struct token *,
316                          const char *, unsigned int, void *, unsigned int);
317 static int parse_destroy(struct context *, const struct token *,
318                          const char *, unsigned int,
319                          void *, unsigned int);
320 static int parse_flush(struct context *, const struct token *,
321                        const char *, unsigned int,
322                        void *, unsigned int);
323 static int parse_query(struct context *, const struct token *,
324                        const char *, unsigned int,
325                        void *, unsigned int);
326 static int parse_action(struct context *, const struct token *,
327                         const char *, unsigned int,
328                         void *, unsigned int);
329 static int parse_list(struct context *, const struct token *,
330                       const char *, unsigned int,
331                       void *, unsigned int);
332 static int parse_int(struct context *, const struct token *,
333                      const char *, unsigned int,
334                      void *, unsigned int);
335 static int parse_prefix(struct context *, const struct token *,
336                         const char *, unsigned int,
337                         void *, unsigned int);
338 static int parse_port(struct context *, const struct token *,
339                       const char *, unsigned int,
340                       void *, unsigned int);
341 static int comp_none(struct context *, const struct token *,
342                      unsigned int, char *, unsigned int);
343 static int comp_action(struct context *, const struct token *,
344                        unsigned int, char *, unsigned int);
345 static int comp_port(struct context *, const struct token *,
346                      unsigned int, char *, unsigned int);
347 static int comp_rule_id(struct context *, const struct token *,
348                         unsigned int, char *, unsigned int);
349
350 /** Token definitions. */
351 static const struct token token_list[] = {
352         /* Special tokens. */
353         [ZERO] = {
354                 .name = "ZERO",
355                 .help = "null entry, abused as the entry point",
356                 .next = NEXT(NEXT_ENTRY(FLOW)),
357         },
358         [END] = {
359                 .name = "",
360                 .type = "RETURN",
361                 .help = "command may end here",
362         },
363         /* Common tokens. */
364         [INTEGER] = {
365                 .name = "{int}",
366                 .type = "INTEGER",
367                 .help = "integer value",
368                 .call = parse_int,
369                 .comp = comp_none,
370         },
371         [UNSIGNED] = {
372                 .name = "{unsigned}",
373                 .type = "UNSIGNED",
374                 .help = "unsigned integer value",
375                 .call = parse_int,
376                 .comp = comp_none,
377         },
378         [PREFIX] = {
379                 .name = "{prefix}",
380                 .type = "PREFIX",
381                 .help = "prefix length for bit-mask",
382                 .call = parse_prefix,
383                 .comp = comp_none,
384         },
385         [RULE_ID] = {
386                 .name = "{rule id}",
387                 .type = "RULE ID",
388                 .help = "rule identifier",
389                 .call = parse_int,
390                 .comp = comp_rule_id,
391         },
392         [PORT_ID] = {
393                 .name = "{port_id}",
394                 .type = "PORT ID",
395                 .help = "port identifier",
396                 .call = parse_port,
397                 .comp = comp_port,
398         },
399         [GROUP_ID] = {
400                 .name = "{group_id}",
401                 .type = "GROUP ID",
402                 .help = "group identifier",
403                 .call = parse_int,
404                 .comp = comp_none,
405         },
406         [PRIORITY_LEVEL] = {
407                 .name = "{level}",
408                 .type = "PRIORITY",
409                 .help = "priority level",
410                 .call = parse_int,
411                 .comp = comp_none,
412         },
413         /* Top-level command. */
414         [FLOW] = {
415                 .name = "flow",
416                 .type = "{command} {port_id} [{arg} [...]]",
417                 .help = "manage ingress/egress flow rules",
418                 .next = NEXT(NEXT_ENTRY
419                              (VALIDATE,
420                               CREATE,
421                               DESTROY,
422                               FLUSH,
423                               LIST,
424                               QUERY)),
425                 .call = parse_init,
426         },
427         /* Sub-level commands. */
428         [VALIDATE] = {
429                 .name = "validate",
430                 .help = "check whether a flow rule can be created",
431                 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
432                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
433                 .call = parse_vc,
434         },
435         [CREATE] = {
436                 .name = "create",
437                 .help = "create a flow rule",
438                 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
439                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
440                 .call = parse_vc,
441         },
442         [DESTROY] = {
443                 .name = "destroy",
444                 .help = "destroy specific flow rules",
445                 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
446                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
447                 .call = parse_destroy,
448         },
449         [FLUSH] = {
450                 .name = "flush",
451                 .help = "destroy all flow rules",
452                 .next = NEXT(NEXT_ENTRY(PORT_ID)),
453                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
454                 .call = parse_flush,
455         },
456         [QUERY] = {
457                 .name = "query",
458                 .help = "query an existing flow rule",
459                 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
460                              NEXT_ENTRY(RULE_ID),
461                              NEXT_ENTRY(PORT_ID)),
462                 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action),
463                              ARGS_ENTRY(struct buffer, args.query.rule),
464                              ARGS_ENTRY(struct buffer, port)),
465                 .call = parse_query,
466         },
467         [LIST] = {
468                 .name = "list",
469                 .help = "list existing flow rules",
470                 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
471                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
472                 .call = parse_list,
473         },
474         /* Destroy arguments. */
475         [DESTROY_RULE] = {
476                 .name = "rule",
477                 .help = "specify a rule identifier",
478                 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
479                 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
480                 .call = parse_destroy,
481         },
482         /* Query arguments. */
483         [QUERY_ACTION] = {
484                 .name = "{action}",
485                 .type = "ACTION",
486                 .help = "action to query, must be part of the rule",
487                 .call = parse_action,
488                 .comp = comp_action,
489         },
490         /* List arguments. */
491         [LIST_GROUP] = {
492                 .name = "group",
493                 .help = "specify a group",
494                 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
495                 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
496                 .call = parse_list,
497         },
498         /* Validate/create attributes. */
499         [GROUP] = {
500                 .name = "group",
501                 .help = "specify a group",
502                 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
503                 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
504                 .call = parse_vc,
505         },
506         [PRIORITY] = {
507                 .name = "priority",
508                 .help = "specify a priority level",
509                 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
510                 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
511                 .call = parse_vc,
512         },
513         [INGRESS] = {
514                 .name = "ingress",
515                 .help = "affect rule to ingress",
516                 .next = NEXT(next_vc_attr),
517                 .call = parse_vc,
518         },
519         [EGRESS] = {
520                 .name = "egress",
521                 .help = "affect rule to egress",
522                 .next = NEXT(next_vc_attr),
523                 .call = parse_vc,
524         },
525         /* Validate/create pattern. */
526         [PATTERN] = {
527                 .name = "pattern",
528                 .help = "submit a list of pattern items",
529                 .next = NEXT(next_item),
530                 .call = parse_vc,
531         },
532         [ITEM_PARAM_IS] = {
533                 .name = "is",
534                 .help = "match value perfectly (with full bit-mask)",
535                 .call = parse_vc_spec,
536         },
537         [ITEM_PARAM_SPEC] = {
538                 .name = "spec",
539                 .help = "match value according to configured bit-mask",
540                 .call = parse_vc_spec,
541         },
542         [ITEM_PARAM_LAST] = {
543                 .name = "last",
544                 .help = "specify upper bound to establish a range",
545                 .call = parse_vc_spec,
546         },
547         [ITEM_PARAM_MASK] = {
548                 .name = "mask",
549                 .help = "specify bit-mask with relevant bits set to one",
550                 .call = parse_vc_spec,
551         },
552         [ITEM_PARAM_PREFIX] = {
553                 .name = "prefix",
554                 .help = "generate bit-mask from a prefix length",
555                 .call = parse_vc_spec,
556         },
557         [ITEM_NEXT] = {
558                 .name = "/",
559                 .help = "specify next pattern item",
560                 .next = NEXT(next_item),
561         },
562         [ITEM_END] = {
563                 .name = "end",
564                 .help = "end list of pattern items",
565                 .priv = PRIV_ITEM(END, 0),
566                 .next = NEXT(NEXT_ENTRY(ACTIONS)),
567                 .call = parse_vc,
568         },
569         [ITEM_VOID] = {
570                 .name = "void",
571                 .help = "no-op pattern item",
572                 .priv = PRIV_ITEM(VOID, 0),
573                 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
574                 .call = parse_vc,
575         },
576         [ITEM_INVERT] = {
577                 .name = "invert",
578                 .help = "perform actions when pattern does not match",
579                 .priv = PRIV_ITEM(INVERT, 0),
580                 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
581                 .call = parse_vc,
582         },
583         /* Validate/create actions. */
584         [ACTIONS] = {
585                 .name = "actions",
586                 .help = "submit a list of associated actions",
587                 .next = NEXT(next_action),
588                 .call = parse_vc,
589         },
590         [ACTION_NEXT] = {
591                 .name = "/",
592                 .help = "specify next action",
593                 .next = NEXT(next_action),
594         },
595         [ACTION_END] = {
596                 .name = "end",
597                 .help = "end list of actions",
598                 .priv = PRIV_ACTION(END, 0),
599                 .call = parse_vc,
600         },
601         [ACTION_VOID] = {
602                 .name = "void",
603                 .help = "no-op action",
604                 .priv = PRIV_ACTION(VOID, 0),
605                 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
606                 .call = parse_vc,
607         },
608         [ACTION_PASSTHRU] = {
609                 .name = "passthru",
610                 .help = "let subsequent rule process matched packets",
611                 .priv = PRIV_ACTION(PASSTHRU, 0),
612                 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
613                 .call = parse_vc,
614         },
615 };
616
617 /** Remove and return last entry from argument stack. */
618 static const struct arg *
619 pop_args(struct context *ctx)
620 {
621         return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
622 }
623
624 /** Add entry on top of the argument stack. */
625 static int
626 push_args(struct context *ctx, const struct arg *arg)
627 {
628         if (ctx->args_num == CTX_STACK_SIZE)
629                 return -1;
630         ctx->args[ctx->args_num++] = arg;
631         return 0;
632 }
633
634 /** Spread value into buffer according to bit-mask. */
635 static size_t
636 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
637 {
638         uint32_t i = arg->size;
639         uint32_t end = 0;
640         int sub = 1;
641         int add = 0;
642         size_t len = 0;
643
644         if (!arg->mask)
645                 return 0;
646 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
647         if (!arg->hton) {
648                 i = 0;
649                 end = arg->size;
650                 sub = 0;
651                 add = 1;
652         }
653 #endif
654         while (i != end) {
655                 unsigned int shift = 0;
656                 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
657
658                 for (shift = 0; arg->mask[i] >> shift; ++shift) {
659                         if (!(arg->mask[i] & (1 << shift)))
660                                 continue;
661                         ++len;
662                         if (!dst)
663                                 continue;
664                         *buf &= ~(1 << shift);
665                         *buf |= (val & 1) << shift;
666                         val >>= 1;
667                 }
668                 i += add;
669         }
670         return len;
671 }
672
673 /**
674  * Parse a prefix length and generate a bit-mask.
675  *
676  * Last argument (ctx->args) is retrieved to determine mask size, storage
677  * location and whether the result must use network byte ordering.
678  */
679 static int
680 parse_prefix(struct context *ctx, const struct token *token,
681              const char *str, unsigned int len,
682              void *buf, unsigned int size)
683 {
684         const struct arg *arg = pop_args(ctx);
685         static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
686         char *end;
687         uintmax_t u;
688         unsigned int bytes;
689         unsigned int extra;
690
691         (void)token;
692         /* Argument is expected. */
693         if (!arg)
694                 return -1;
695         errno = 0;
696         u = strtoumax(str, &end, 0);
697         if (errno || (size_t)(end - str) != len)
698                 goto error;
699         if (arg->mask) {
700                 uintmax_t v = 0;
701
702                 extra = arg_entry_bf_fill(NULL, 0, arg);
703                 if (u > extra)
704                         goto error;
705                 if (!ctx->object)
706                         return len;
707                 extra -= u;
708                 while (u--)
709                         (v <<= 1, v |= 1);
710                 v <<= extra;
711                 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
712                     !arg_entry_bf_fill(ctx->objmask, -1, arg))
713                         goto error;
714                 return len;
715         }
716         bytes = u / 8;
717         extra = u % 8;
718         size = arg->size;
719         if (bytes > size || bytes + !!extra > size)
720                 goto error;
721         if (!ctx->object)
722                 return len;
723         buf = (uint8_t *)ctx->object + arg->offset;
724 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
725         if (!arg->hton) {
726                 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
727                 memset(buf, 0x00, size - bytes);
728                 if (extra)
729                         ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
730         } else
731 #endif
732         {
733                 memset(buf, 0xff, bytes);
734                 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
735                 if (extra)
736                         ((uint8_t *)buf)[bytes] = conv[extra];
737         }
738         if (ctx->objmask)
739                 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
740         return len;
741 error:
742         push_args(ctx, arg);
743         return -1;
744 }
745
746 /** Default parsing function for token name matching. */
747 static int
748 parse_default(struct context *ctx, const struct token *token,
749               const char *str, unsigned int len,
750               void *buf, unsigned int size)
751 {
752         (void)ctx;
753         (void)buf;
754         (void)size;
755         if (strncmp(str, token->name, len))
756                 return -1;
757         return len;
758 }
759
760 /** Parse flow command, initialize output buffer for subsequent tokens. */
761 static int
762 parse_init(struct context *ctx, const struct token *token,
763            const char *str, unsigned int len,
764            void *buf, unsigned int size)
765 {
766         struct buffer *out = buf;
767
768         /* Token name must match. */
769         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
770                 return -1;
771         /* Nothing else to do if there is no buffer. */
772         if (!out)
773                 return len;
774         /* Make sure buffer is large enough. */
775         if (size < sizeof(*out))
776                 return -1;
777         /* Initialize buffer. */
778         memset(out, 0x00, sizeof(*out));
779         memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
780         ctx->objdata = 0;
781         ctx->object = out;
782         ctx->objmask = NULL;
783         return len;
784 }
785
786 /** Parse tokens for validate/create commands. */
787 static int
788 parse_vc(struct context *ctx, const struct token *token,
789          const char *str, unsigned int len,
790          void *buf, unsigned int size)
791 {
792         struct buffer *out = buf;
793         uint8_t *data;
794         uint32_t data_size;
795
796         /* Token name must match. */
797         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
798                 return -1;
799         /* Nothing else to do if there is no buffer. */
800         if (!out)
801                 return len;
802         if (!out->command) {
803                 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
804                         return -1;
805                 if (sizeof(*out) > size)
806                         return -1;
807                 out->command = ctx->curr;
808                 ctx->objdata = 0;
809                 ctx->object = out;
810                 ctx->objmask = NULL;
811                 out->args.vc.data = (uint8_t *)out + size;
812                 return len;
813         }
814         ctx->objdata = 0;
815         ctx->object = &out->args.vc.attr;
816         ctx->objmask = NULL;
817         switch (ctx->curr) {
818         case GROUP:
819         case PRIORITY:
820                 return len;
821         case INGRESS:
822                 out->args.vc.attr.ingress = 1;
823                 return len;
824         case EGRESS:
825                 out->args.vc.attr.egress = 1;
826                 return len;
827         case PATTERN:
828                 out->args.vc.pattern =
829                         (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
830                                                sizeof(double));
831                 ctx->object = out->args.vc.pattern;
832                 ctx->objmask = NULL;
833                 return len;
834         case ACTIONS:
835                 out->args.vc.actions =
836                         (void *)RTE_ALIGN_CEIL((uintptr_t)
837                                                (out->args.vc.pattern +
838                                                 out->args.vc.pattern_n),
839                                                sizeof(double));
840                 ctx->object = out->args.vc.actions;
841                 ctx->objmask = NULL;
842                 return len;
843         default:
844                 if (!token->priv)
845                         return -1;
846                 break;
847         }
848         if (!out->args.vc.actions) {
849                 const struct parse_item_priv *priv = token->priv;
850                 struct rte_flow_item *item =
851                         out->args.vc.pattern + out->args.vc.pattern_n;
852
853                 data_size = priv->size * 3; /* spec, last, mask */
854                 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
855                                                (out->args.vc.data - data_size),
856                                                sizeof(double));
857                 if ((uint8_t *)item + sizeof(*item) > data)
858                         return -1;
859                 *item = (struct rte_flow_item){
860                         .type = priv->type,
861                 };
862                 ++out->args.vc.pattern_n;
863                 ctx->object = item;
864                 ctx->objmask = NULL;
865         } else {
866                 const struct parse_action_priv *priv = token->priv;
867                 struct rte_flow_action *action =
868                         out->args.vc.actions + out->args.vc.actions_n;
869
870                 data_size = priv->size; /* configuration */
871                 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
872                                                (out->args.vc.data - data_size),
873                                                sizeof(double));
874                 if ((uint8_t *)action + sizeof(*action) > data)
875                         return -1;
876                 *action = (struct rte_flow_action){
877                         .type = priv->type,
878                 };
879                 ++out->args.vc.actions_n;
880                 ctx->object = action;
881                 ctx->objmask = NULL;
882         }
883         memset(data, 0, data_size);
884         out->args.vc.data = data;
885         ctx->objdata = data_size;
886         return len;
887 }
888
889 /** Parse pattern item parameter type. */
890 static int
891 parse_vc_spec(struct context *ctx, const struct token *token,
892               const char *str, unsigned int len,
893               void *buf, unsigned int size)
894 {
895         struct buffer *out = buf;
896         struct rte_flow_item *item;
897         uint32_t data_size;
898         int index;
899         int objmask = 0;
900
901         (void)size;
902         /* Token name must match. */
903         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
904                 return -1;
905         /* Parse parameter types. */
906         switch (ctx->curr) {
907         case ITEM_PARAM_IS:
908                 index = 0;
909                 objmask = 1;
910                 break;
911         case ITEM_PARAM_SPEC:
912                 index = 0;
913                 break;
914         case ITEM_PARAM_LAST:
915                 index = 1;
916                 break;
917         case ITEM_PARAM_PREFIX:
918                 /* Modify next token to expect a prefix. */
919                 if (ctx->next_num < 2)
920                         return -1;
921                 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
922                 /* Fall through. */
923         case ITEM_PARAM_MASK:
924                 index = 2;
925                 break;
926         default:
927                 return -1;
928         }
929         /* Nothing else to do if there is no buffer. */
930         if (!out)
931                 return len;
932         if (!out->args.vc.pattern_n)
933                 return -1;
934         item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
935         data_size = ctx->objdata / 3; /* spec, last, mask */
936         /* Point to selected object. */
937         ctx->object = out->args.vc.data + (data_size * index);
938         if (objmask) {
939                 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
940                 item->mask = ctx->objmask;
941         } else
942                 ctx->objmask = NULL;
943         /* Update relevant item pointer. */
944         *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
945                 ctx->object;
946         return len;
947 }
948
949 /** Parse tokens for destroy command. */
950 static int
951 parse_destroy(struct context *ctx, const struct token *token,
952               const char *str, unsigned int len,
953               void *buf, unsigned int size)
954 {
955         struct buffer *out = buf;
956
957         /* Token name must match. */
958         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
959                 return -1;
960         /* Nothing else to do if there is no buffer. */
961         if (!out)
962                 return len;
963         if (!out->command) {
964                 if (ctx->curr != DESTROY)
965                         return -1;
966                 if (sizeof(*out) > size)
967                         return -1;
968                 out->command = ctx->curr;
969                 ctx->objdata = 0;
970                 ctx->object = out;
971                 ctx->objmask = NULL;
972                 out->args.destroy.rule =
973                         (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
974                                                sizeof(double));
975                 return len;
976         }
977         if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
978              sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
979                 return -1;
980         ctx->objdata = 0;
981         ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
982         ctx->objmask = NULL;
983         return len;
984 }
985
986 /** Parse tokens for flush command. */
987 static int
988 parse_flush(struct context *ctx, const struct token *token,
989             const char *str, unsigned int len,
990             void *buf, unsigned int size)
991 {
992         struct buffer *out = buf;
993
994         /* Token name must match. */
995         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
996                 return -1;
997         /* Nothing else to do if there is no buffer. */
998         if (!out)
999                 return len;
1000         if (!out->command) {
1001                 if (ctx->curr != FLUSH)
1002                         return -1;
1003                 if (sizeof(*out) > size)
1004                         return -1;
1005                 out->command = ctx->curr;
1006                 ctx->objdata = 0;
1007                 ctx->object = out;
1008                 ctx->objmask = NULL;
1009         }
1010         return len;
1011 }
1012
1013 /** Parse tokens for query command. */
1014 static int
1015 parse_query(struct context *ctx, const struct token *token,
1016             const char *str, unsigned int len,
1017             void *buf, unsigned int size)
1018 {
1019         struct buffer *out = buf;
1020
1021         /* Token name must match. */
1022         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1023                 return -1;
1024         /* Nothing else to do if there is no buffer. */
1025         if (!out)
1026                 return len;
1027         if (!out->command) {
1028                 if (ctx->curr != QUERY)
1029                         return -1;
1030                 if (sizeof(*out) > size)
1031                         return -1;
1032                 out->command = ctx->curr;
1033                 ctx->objdata = 0;
1034                 ctx->object = out;
1035                 ctx->objmask = NULL;
1036         }
1037         return len;
1038 }
1039
1040 /** Parse action names. */
1041 static int
1042 parse_action(struct context *ctx, const struct token *token,
1043              const char *str, unsigned int len,
1044              void *buf, unsigned int size)
1045 {
1046         struct buffer *out = buf;
1047         const struct arg *arg = pop_args(ctx);
1048         unsigned int i;
1049
1050         (void)size;
1051         /* Argument is expected. */
1052         if (!arg)
1053                 return -1;
1054         /* Parse action name. */
1055         for (i = 0; next_action[i]; ++i) {
1056                 const struct parse_action_priv *priv;
1057
1058                 token = &token_list[next_action[i]];
1059                 if (strncmp(token->name, str, len))
1060                         continue;
1061                 priv = token->priv;
1062                 if (!priv)
1063                         goto error;
1064                 if (out)
1065                         memcpy((uint8_t *)ctx->object + arg->offset,
1066                                &priv->type,
1067                                arg->size);
1068                 return len;
1069         }
1070 error:
1071         push_args(ctx, arg);
1072         return -1;
1073 }
1074
1075 /** Parse tokens for list command. */
1076 static int
1077 parse_list(struct context *ctx, const struct token *token,
1078            const char *str, unsigned int len,
1079            void *buf, unsigned int size)
1080 {
1081         struct buffer *out = buf;
1082
1083         /* Token name must match. */
1084         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1085                 return -1;
1086         /* Nothing else to do if there is no buffer. */
1087         if (!out)
1088                 return len;
1089         if (!out->command) {
1090                 if (ctx->curr != LIST)
1091                         return -1;
1092                 if (sizeof(*out) > size)
1093                         return -1;
1094                 out->command = ctx->curr;
1095                 ctx->objdata = 0;
1096                 ctx->object = out;
1097                 ctx->objmask = NULL;
1098                 out->args.list.group =
1099                         (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1100                                                sizeof(double));
1101                 return len;
1102         }
1103         if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
1104              sizeof(*out->args.list.group)) > (uint8_t *)out + size)
1105                 return -1;
1106         ctx->objdata = 0;
1107         ctx->object = out->args.list.group + out->args.list.group_n++;
1108         ctx->objmask = NULL;
1109         return len;
1110 }
1111
1112 /**
1113  * Parse signed/unsigned integers 8 to 64-bit long.
1114  *
1115  * Last argument (ctx->args) is retrieved to determine integer type and
1116  * storage location.
1117  */
1118 static int
1119 parse_int(struct context *ctx, const struct token *token,
1120           const char *str, unsigned int len,
1121           void *buf, unsigned int size)
1122 {
1123         const struct arg *arg = pop_args(ctx);
1124         uintmax_t u;
1125         char *end;
1126
1127         (void)token;
1128         /* Argument is expected. */
1129         if (!arg)
1130                 return -1;
1131         errno = 0;
1132         u = arg->sign ?
1133                 (uintmax_t)strtoimax(str, &end, 0) :
1134                 strtoumax(str, &end, 0);
1135         if (errno || (size_t)(end - str) != len)
1136                 goto error;
1137         if (!ctx->object)
1138                 return len;
1139         if (arg->mask) {
1140                 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
1141                     !arg_entry_bf_fill(ctx->objmask, -1, arg))
1142                         goto error;
1143                 return len;
1144         }
1145         buf = (uint8_t *)ctx->object + arg->offset;
1146         size = arg->size;
1147 objmask:
1148         switch (size) {
1149         case sizeof(uint8_t):
1150                 *(uint8_t *)buf = u;
1151                 break;
1152         case sizeof(uint16_t):
1153                 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1154                 break;
1155         case sizeof(uint32_t):
1156                 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1157                 break;
1158         case sizeof(uint64_t):
1159                 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1160                 break;
1161         default:
1162                 goto error;
1163         }
1164         if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1165                 u = -1;
1166                 buf = (uint8_t *)ctx->objmask + arg->offset;
1167                 goto objmask;
1168         }
1169         return len;
1170 error:
1171         push_args(ctx, arg);
1172         return -1;
1173 }
1174
1175 /** Parse port and update context. */
1176 static int
1177 parse_port(struct context *ctx, const struct token *token,
1178            const char *str, unsigned int len,
1179            void *buf, unsigned int size)
1180 {
1181         struct buffer *out = &(struct buffer){ .port = 0 };
1182         int ret;
1183
1184         if (buf)
1185                 out = buf;
1186         else {
1187                 ctx->objdata = 0;
1188                 ctx->object = out;
1189                 ctx->objmask = NULL;
1190                 size = sizeof(*out);
1191         }
1192         ret = parse_int(ctx, token, str, len, out, size);
1193         if (ret >= 0)
1194                 ctx->port = out->port;
1195         if (!buf)
1196                 ctx->object = NULL;
1197         return ret;
1198 }
1199
1200 /** No completion. */
1201 static int
1202 comp_none(struct context *ctx, const struct token *token,
1203           unsigned int ent, char *buf, unsigned int size)
1204 {
1205         (void)ctx;
1206         (void)token;
1207         (void)ent;
1208         (void)buf;
1209         (void)size;
1210         return 0;
1211 }
1212
1213 /** Complete action names. */
1214 static int
1215 comp_action(struct context *ctx, const struct token *token,
1216             unsigned int ent, char *buf, unsigned int size)
1217 {
1218         unsigned int i;
1219
1220         (void)ctx;
1221         (void)token;
1222         for (i = 0; next_action[i]; ++i)
1223                 if (buf && i == ent)
1224                         return snprintf(buf, size, "%s",
1225                                         token_list[next_action[i]].name);
1226         if (buf)
1227                 return -1;
1228         return i;
1229 }
1230
1231 /** Complete available ports. */
1232 static int
1233 comp_port(struct context *ctx, const struct token *token,
1234           unsigned int ent, char *buf, unsigned int size)
1235 {
1236         unsigned int i = 0;
1237         portid_t p;
1238
1239         (void)ctx;
1240         (void)token;
1241         FOREACH_PORT(p, ports) {
1242                 if (buf && i == ent)
1243                         return snprintf(buf, size, "%u", p);
1244                 ++i;
1245         }
1246         if (buf)
1247                 return -1;
1248         return i;
1249 }
1250
1251 /** Complete available rule IDs. */
1252 static int
1253 comp_rule_id(struct context *ctx, const struct token *token,
1254              unsigned int ent, char *buf, unsigned int size)
1255 {
1256         unsigned int i = 0;
1257         struct rte_port *port;
1258         struct port_flow *pf;
1259
1260         (void)token;
1261         if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1262             ctx->port == (uint16_t)RTE_PORT_ALL)
1263                 return -1;
1264         port = &ports[ctx->port];
1265         for (pf = port->flow_list; pf != NULL; pf = pf->next) {
1266                 if (buf && i == ent)
1267                         return snprintf(buf, size, "%u", pf->id);
1268                 ++i;
1269         }
1270         if (buf)
1271                 return -1;
1272         return i;
1273 }
1274
1275 /** Internal context. */
1276 static struct context cmd_flow_context;
1277
1278 /** Global parser instance (cmdline API). */
1279 cmdline_parse_inst_t cmd_flow;
1280
1281 /** Initialize context. */
1282 static void
1283 cmd_flow_context_init(struct context *ctx)
1284 {
1285         /* A full memset() is not necessary. */
1286         ctx->curr = ZERO;
1287         ctx->prev = ZERO;
1288         ctx->next_num = 0;
1289         ctx->args_num = 0;
1290         ctx->reparse = 0;
1291         ctx->eol = 0;
1292         ctx->last = 0;
1293         ctx->port = 0;
1294         ctx->objdata = 0;
1295         ctx->object = NULL;
1296         ctx->objmask = NULL;
1297 }
1298
1299 /** Parse a token (cmdline API). */
1300 static int
1301 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1302                unsigned int size)
1303 {
1304         struct context *ctx = &cmd_flow_context;
1305         const struct token *token;
1306         const enum index *list;
1307         int len;
1308         int i;
1309
1310         (void)hdr;
1311         /* Restart as requested. */
1312         if (ctx->reparse)
1313                 cmd_flow_context_init(ctx);
1314         token = &token_list[ctx->curr];
1315         /* Check argument length. */
1316         ctx->eol = 0;
1317         ctx->last = 1;
1318         for (len = 0; src[len]; ++len)
1319                 if (src[len] == '#' || isspace(src[len]))
1320                         break;
1321         if (!len)
1322                 return -1;
1323         /* Last argument and EOL detection. */
1324         for (i = len; src[i]; ++i)
1325                 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1326                         break;
1327                 else if (!isspace(src[i])) {
1328                         ctx->last = 0;
1329                         break;
1330                 }
1331         for (; src[i]; ++i)
1332                 if (src[i] == '\r' || src[i] == '\n') {
1333                         ctx->eol = 1;
1334                         break;
1335                 }
1336         /* Initialize context if necessary. */
1337         if (!ctx->next_num) {
1338                 if (!token->next)
1339                         return 0;
1340                 ctx->next[ctx->next_num++] = token->next[0];
1341         }
1342         /* Process argument through candidates. */
1343         ctx->prev = ctx->curr;
1344         list = ctx->next[ctx->next_num - 1];
1345         for (i = 0; list[i]; ++i) {
1346                 const struct token *next = &token_list[list[i]];
1347                 int tmp;
1348
1349                 ctx->curr = list[i];
1350                 if (next->call)
1351                         tmp = next->call(ctx, next, src, len, result, size);
1352                 else
1353                         tmp = parse_default(ctx, next, src, len, result, size);
1354                 if (tmp == -1 || tmp != len)
1355                         continue;
1356                 token = next;
1357                 break;
1358         }
1359         if (!list[i])
1360                 return -1;
1361         --ctx->next_num;
1362         /* Push subsequent tokens if any. */
1363         if (token->next)
1364                 for (i = 0; token->next[i]; ++i) {
1365                         if (ctx->next_num == RTE_DIM(ctx->next))
1366                                 return -1;
1367                         ctx->next[ctx->next_num++] = token->next[i];
1368                 }
1369         /* Push arguments if any. */
1370         if (token->args)
1371                 for (i = 0; token->args[i]; ++i) {
1372                         if (ctx->args_num == RTE_DIM(ctx->args))
1373                                 return -1;
1374                         ctx->args[ctx->args_num++] = token->args[i];
1375                 }
1376         return len;
1377 }
1378
1379 /** Return number of completion entries (cmdline API). */
1380 static int
1381 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1382 {
1383         struct context *ctx = &cmd_flow_context;
1384         const struct token *token = &token_list[ctx->curr];
1385         const enum index *list;
1386         int i;
1387
1388         (void)hdr;
1389         /* Tell cmd_flow_parse() that context must be reinitialized. */
1390         ctx->reparse = 1;
1391         /* Count number of tokens in current list. */
1392         if (ctx->next_num)
1393                 list = ctx->next[ctx->next_num - 1];
1394         else
1395                 list = token->next[0];
1396         for (i = 0; list[i]; ++i)
1397                 ;
1398         if (!i)
1399                 return 0;
1400         /*
1401          * If there is a single token, use its completion callback, otherwise
1402          * return the number of entries.
1403          */
1404         token = &token_list[list[0]];
1405         if (i == 1 && token->comp) {
1406                 /* Save index for cmd_flow_get_help(). */
1407                 ctx->prev = list[0];
1408                 return token->comp(ctx, token, 0, NULL, 0);
1409         }
1410         return i;
1411 }
1412
1413 /** Return a completion entry (cmdline API). */
1414 static int
1415 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1416                           char *dst, unsigned int size)
1417 {
1418         struct context *ctx = &cmd_flow_context;
1419         const struct token *token = &token_list[ctx->curr];
1420         const enum index *list;
1421         int i;
1422
1423         (void)hdr;
1424         /* Tell cmd_flow_parse() that context must be reinitialized. */
1425         ctx->reparse = 1;
1426         /* Count number of tokens in current list. */
1427         if (ctx->next_num)
1428                 list = ctx->next[ctx->next_num - 1];
1429         else
1430                 list = token->next[0];
1431         for (i = 0; list[i]; ++i)
1432                 ;
1433         if (!i)
1434                 return -1;
1435         /* If there is a single token, use its completion callback. */
1436         token = &token_list[list[0]];
1437         if (i == 1 && token->comp) {
1438                 /* Save index for cmd_flow_get_help(). */
1439                 ctx->prev = list[0];
1440                 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
1441         }
1442         /* Otherwise make sure the index is valid and use defaults. */
1443         if (index >= i)
1444                 return -1;
1445         token = &token_list[list[index]];
1446         snprintf(dst, size, "%s", token->name);
1447         /* Save index for cmd_flow_get_help(). */
1448         ctx->prev = list[index];
1449         return 0;
1450 }
1451
1452 /** Populate help strings for current token (cmdline API). */
1453 static int
1454 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1455 {
1456         struct context *ctx = &cmd_flow_context;
1457         const struct token *token = &token_list[ctx->prev];
1458
1459         (void)hdr;
1460         /* Tell cmd_flow_parse() that context must be reinitialized. */
1461         ctx->reparse = 1;
1462         if (!size)
1463                 return -1;
1464         /* Set token type and update global help with details. */
1465         snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1466         if (token->help)
1467                 cmd_flow.help_str = token->help;
1468         else
1469                 cmd_flow.help_str = token->name;
1470         return 0;
1471 }
1472
1473 /** Token definition template (cmdline API). */
1474 static struct cmdline_token_hdr cmd_flow_token_hdr = {
1475         .ops = &(struct cmdline_token_ops){
1476                 .parse = cmd_flow_parse,
1477                 .complete_get_nb = cmd_flow_complete_get_nb,
1478                 .complete_get_elt = cmd_flow_complete_get_elt,
1479                 .get_help = cmd_flow_get_help,
1480         },
1481         .offset = 0,
1482 };
1483
1484 /** Populate the next dynamic token. */
1485 static void
1486 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1487              cmdline_parse_token_hdr_t *(*hdrs)[])
1488 {
1489         struct context *ctx = &cmd_flow_context;
1490
1491         /* Always reinitialize context before requesting the first token. */
1492         if (!(hdr - *hdrs))
1493                 cmd_flow_context_init(ctx);
1494         /* Return NULL when no more tokens are expected. */
1495         if (!ctx->next_num && ctx->curr) {
1496                 *hdr = NULL;
1497                 return;
1498         }
1499         /* Determine if command should end here. */
1500         if (ctx->eol && ctx->last && ctx->next_num) {
1501                 const enum index *list = ctx->next[ctx->next_num - 1];
1502                 int i;
1503
1504                 for (i = 0; list[i]; ++i) {
1505                         if (list[i] != END)
1506                                 continue;
1507                         *hdr = NULL;
1508                         return;
1509                 }
1510         }
1511         *hdr = &cmd_flow_token_hdr;
1512 }
1513
1514 /** Dispatch parsed buffer to function calls. */
1515 static void
1516 cmd_flow_parsed(const struct buffer *in)
1517 {
1518         switch (in->command) {
1519         case VALIDATE:
1520                 port_flow_validate(in->port, &in->args.vc.attr,
1521                                    in->args.vc.pattern, in->args.vc.actions);
1522                 break;
1523         case CREATE:
1524                 port_flow_create(in->port, &in->args.vc.attr,
1525                                  in->args.vc.pattern, in->args.vc.actions);
1526                 break;
1527         case DESTROY:
1528                 port_flow_destroy(in->port, in->args.destroy.rule_n,
1529                                   in->args.destroy.rule);
1530                 break;
1531         case FLUSH:
1532                 port_flow_flush(in->port);
1533                 break;
1534         case QUERY:
1535                 port_flow_query(in->port, in->args.query.rule,
1536                                 in->args.query.action);
1537                 break;
1538         case LIST:
1539                 port_flow_list(in->port, in->args.list.group_n,
1540                                in->args.list.group);
1541                 break;
1542         default:
1543                 break;
1544         }
1545 }
1546
1547 /** Token generator and output processing callback (cmdline API). */
1548 static void
1549 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1550 {
1551         if (cl == NULL)
1552                 cmd_flow_tok(arg0, arg2);
1553         else
1554                 cmd_flow_parsed(arg0);
1555 }
1556
1557 /** Global parser instance (cmdline API). */
1558 cmdline_parse_inst_t cmd_flow = {
1559         .f = cmd_flow_cb,
1560         .data = NULL, /**< Unused. */
1561         .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1562         .tokens = {
1563                 NULL,
1564         }, /**< Tokens are returned by cmd_flow_tok(). */
1565 };