app/testpmd: add flow item spec prefix length
[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 };
140
141 /** Parser token definition. */
142 struct token {
143         /** Type displayed during completion (defaults to "TOKEN"). */
144         const char *type;
145         /** Help displayed during completion (defaults to token name). */
146         const char *help;
147         /** Private data used by parser functions. */
148         const void *priv;
149         /**
150          * Lists of subsequent tokens to push on the stack. Each call to the
151          * parser consumes the last entry of that stack.
152          */
153         const enum index *const *next;
154         /** Arguments stack for subsequent tokens that need them. */
155         const struct arg *const *args;
156         /**
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.
160          *
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.
163          */
164         int (*call)(struct context *ctx, const struct token *token,
165                     const char *str, unsigned int len,
166                     void *buf, unsigned int size);
167         /**
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.
171          *
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
174          * snprintf()).
175          */
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. */
179         const char *name;
180 };
181
182 /** Static initializer for the next field. */
183 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
184
185 /** Static initializer for a NEXT() entry. */
186 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
187
188 /** Static initializer for the args field. */
189 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
190
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), \
196         })
197
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), \
202         })
203
204 /** Parser output buffer layout expected by cmd_flow_parsed(). */
205 struct buffer {
206         enum index command; /**< Flow command. */
207         uint16_t port; /**< Affected port ID. */
208         union {
209                 struct {
210                         struct rte_flow_attr attr;
211                         struct rte_flow_item *pattern;
212                         struct rte_flow_action *actions;
213                         uint32_t pattern_n;
214                         uint32_t actions_n;
215                         uint8_t *data;
216                 } vc; /**< Validate/create arguments. */
217                 struct {
218                         uint32_t *rule;
219                         uint32_t rule_n;
220                 } destroy; /**< Destroy arguments. */
221                 struct {
222                         uint32_t rule;
223                         enum rte_flow_action_type action;
224                 } query; /**< Query arguments. */
225                 struct {
226                         uint32_t *group;
227                         uint32_t group_n;
228                 } list; /**< List arguments. */
229         } args; /**< Command arguments. */
230 };
231
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. */
236 };
237
238 #define PRIV_ITEM(t, s) \
239         (&(const struct parse_item_priv){ \
240                 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
241                 .size = s, \
242         })
243
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. */
248 };
249
250 #define PRIV_ACTION(t, s) \
251         (&(const struct parse_action_priv){ \
252                 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
253                 .size = s, \
254         })
255
256 static const enum index next_vc_attr[] = {
257         GROUP,
258         PRIORITY,
259         INGRESS,
260         EGRESS,
261         PATTERN,
262         ZERO,
263 };
264
265 static const enum index next_destroy_attr[] = {
266         DESTROY_RULE,
267         END,
268         ZERO,
269 };
270
271 static const enum index next_list_attr[] = {
272         LIST_GROUP,
273         END,
274         ZERO,
275 };
276
277 __rte_unused
278 static const enum index item_param[] = {
279         ITEM_PARAM_IS,
280         ITEM_PARAM_SPEC,
281         ITEM_PARAM_LAST,
282         ITEM_PARAM_MASK,
283         ITEM_PARAM_PREFIX,
284         ZERO,
285 };
286
287 static const enum index next_item[] = {
288         ITEM_END,
289         ITEM_VOID,
290         ITEM_INVERT,
291         ZERO,
292 };
293
294 static const enum index next_action[] = {
295         ACTION_END,
296         ACTION_VOID,
297         ACTION_PASSTHRU,
298         ZERO,
299 };
300
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);
341
342 /** Token definitions. */
343 static const struct token token_list[] = {
344         /* Special tokens. */
345         [ZERO] = {
346                 .name = "ZERO",
347                 .help = "null entry, abused as the entry point",
348                 .next = NEXT(NEXT_ENTRY(FLOW)),
349         },
350         [END] = {
351                 .name = "",
352                 .type = "RETURN",
353                 .help = "command may end here",
354         },
355         /* Common tokens. */
356         [INTEGER] = {
357                 .name = "{int}",
358                 .type = "INTEGER",
359                 .help = "integer value",
360                 .call = parse_int,
361                 .comp = comp_none,
362         },
363         [UNSIGNED] = {
364                 .name = "{unsigned}",
365                 .type = "UNSIGNED",
366                 .help = "unsigned integer value",
367                 .call = parse_int,
368                 .comp = comp_none,
369         },
370         [PREFIX] = {
371                 .name = "{prefix}",
372                 .type = "PREFIX",
373                 .help = "prefix length for bit-mask",
374                 .call = parse_prefix,
375                 .comp = comp_none,
376         },
377         [RULE_ID] = {
378                 .name = "{rule id}",
379                 .type = "RULE ID",
380                 .help = "rule identifier",
381                 .call = parse_int,
382                 .comp = comp_rule_id,
383         },
384         [PORT_ID] = {
385                 .name = "{port_id}",
386                 .type = "PORT ID",
387                 .help = "port identifier",
388                 .call = parse_port,
389                 .comp = comp_port,
390         },
391         [GROUP_ID] = {
392                 .name = "{group_id}",
393                 .type = "GROUP ID",
394                 .help = "group identifier",
395                 .call = parse_int,
396                 .comp = comp_none,
397         },
398         [PRIORITY_LEVEL] = {
399                 .name = "{level}",
400                 .type = "PRIORITY",
401                 .help = "priority level",
402                 .call = parse_int,
403                 .comp = comp_none,
404         },
405         /* Top-level command. */
406         [FLOW] = {
407                 .name = "flow",
408                 .type = "{command} {port_id} [{arg} [...]]",
409                 .help = "manage ingress/egress flow rules",
410                 .next = NEXT(NEXT_ENTRY
411                              (VALIDATE,
412                               CREATE,
413                               DESTROY,
414                               FLUSH,
415                               LIST,
416                               QUERY)),
417                 .call = parse_init,
418         },
419         /* Sub-level commands. */
420         [VALIDATE] = {
421                 .name = "validate",
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)),
425                 .call = parse_vc,
426         },
427         [CREATE] = {
428                 .name = "create",
429                 .help = "create a flow rule",
430                 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
431                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
432                 .call = parse_vc,
433         },
434         [DESTROY] = {
435                 .name = "destroy",
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,
440         },
441         [FLUSH] = {
442                 .name = "flush",
443                 .help = "destroy all flow rules",
444                 .next = NEXT(NEXT_ENTRY(PORT_ID)),
445                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
446                 .call = parse_flush,
447         },
448         [QUERY] = {
449                 .name = "query",
450                 .help = "query an existing flow rule",
451                 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
452                              NEXT_ENTRY(RULE_ID),
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)),
457                 .call = parse_query,
458         },
459         [LIST] = {
460                 .name = "list",
461                 .help = "list existing flow rules",
462                 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
463                 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
464                 .call = parse_list,
465         },
466         /* Destroy arguments. */
467         [DESTROY_RULE] = {
468                 .name = "rule",
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,
473         },
474         /* Query arguments. */
475         [QUERY_ACTION] = {
476                 .name = "{action}",
477                 .type = "ACTION",
478                 .help = "action to query, must be part of the rule",
479                 .call = parse_action,
480                 .comp = comp_action,
481         },
482         /* List arguments. */
483         [LIST_GROUP] = {
484                 .name = "group",
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)),
488                 .call = parse_list,
489         },
490         /* Validate/create attributes. */
491         [GROUP] = {
492                 .name = "group",
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)),
496                 .call = parse_vc,
497         },
498         [PRIORITY] = {
499                 .name = "priority",
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)),
503                 .call = parse_vc,
504         },
505         [INGRESS] = {
506                 .name = "ingress",
507                 .help = "affect rule to ingress",
508                 .next = NEXT(next_vc_attr),
509                 .call = parse_vc,
510         },
511         [EGRESS] = {
512                 .name = "egress",
513                 .help = "affect rule to egress",
514                 .next = NEXT(next_vc_attr),
515                 .call = parse_vc,
516         },
517         /* Validate/create pattern. */
518         [PATTERN] = {
519                 .name = "pattern",
520                 .help = "submit a list of pattern items",
521                 .next = NEXT(next_item),
522                 .call = parse_vc,
523         },
524         [ITEM_PARAM_IS] = {
525                 .name = "is",
526                 .help = "match value perfectly (with full bit-mask)",
527                 .call = parse_vc_spec,
528         },
529         [ITEM_PARAM_SPEC] = {
530                 .name = "spec",
531                 .help = "match value according to configured bit-mask",
532                 .call = parse_vc_spec,
533         },
534         [ITEM_PARAM_LAST] = {
535                 .name = "last",
536                 .help = "specify upper bound to establish a range",
537                 .call = parse_vc_spec,
538         },
539         [ITEM_PARAM_MASK] = {
540                 .name = "mask",
541                 .help = "specify bit-mask with relevant bits set to one",
542                 .call = parse_vc_spec,
543         },
544         [ITEM_PARAM_PREFIX] = {
545                 .name = "prefix",
546                 .help = "generate bit-mask from a prefix length",
547                 .call = parse_vc_spec,
548         },
549         [ITEM_NEXT] = {
550                 .name = "/",
551                 .help = "specify next pattern item",
552                 .next = NEXT(next_item),
553         },
554         [ITEM_END] = {
555                 .name = "end",
556                 .help = "end list of pattern items",
557                 .priv = PRIV_ITEM(END, 0),
558                 .next = NEXT(NEXT_ENTRY(ACTIONS)),
559                 .call = parse_vc,
560         },
561         [ITEM_VOID] = {
562                 .name = "void",
563                 .help = "no-op pattern item",
564                 .priv = PRIV_ITEM(VOID, 0),
565                 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
566                 .call = parse_vc,
567         },
568         [ITEM_INVERT] = {
569                 .name = "invert",
570                 .help = "perform actions when pattern does not match",
571                 .priv = PRIV_ITEM(INVERT, 0),
572                 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
573                 .call = parse_vc,
574         },
575         /* Validate/create actions. */
576         [ACTIONS] = {
577                 .name = "actions",
578                 .help = "submit a list of associated actions",
579                 .next = NEXT(next_action),
580                 .call = parse_vc,
581         },
582         [ACTION_NEXT] = {
583                 .name = "/",
584                 .help = "specify next action",
585                 .next = NEXT(next_action),
586         },
587         [ACTION_END] = {
588                 .name = "end",
589                 .help = "end list of actions",
590                 .priv = PRIV_ACTION(END, 0),
591                 .call = parse_vc,
592         },
593         [ACTION_VOID] = {
594                 .name = "void",
595                 .help = "no-op action",
596                 .priv = PRIV_ACTION(VOID, 0),
597                 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
598                 .call = parse_vc,
599         },
600         [ACTION_PASSTHRU] = {
601                 .name = "passthru",
602                 .help = "let subsequent rule process matched packets",
603                 .priv = PRIV_ACTION(PASSTHRU, 0),
604                 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
605                 .call = parse_vc,
606         },
607 };
608
609 /** Remove and return last entry from argument stack. */
610 static const struct arg *
611 pop_args(struct context *ctx)
612 {
613         return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
614 }
615
616 /** Add entry on top of the argument stack. */
617 static int
618 push_args(struct context *ctx, const struct arg *arg)
619 {
620         if (ctx->args_num == CTX_STACK_SIZE)
621                 return -1;
622         ctx->args[ctx->args_num++] = arg;
623         return 0;
624 }
625
626 /**
627  * Parse a prefix length and generate a bit-mask.
628  *
629  * Last argument (ctx->args) is retrieved to determine mask size, storage
630  * location and whether the result must use network byte ordering.
631  */
632 static int
633 parse_prefix(struct context *ctx, const struct token *token,
634              const char *str, unsigned int len,
635              void *buf, unsigned int size)
636 {
637         const struct arg *arg = pop_args(ctx);
638         static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
639         char *end;
640         uintmax_t u;
641         unsigned int bytes;
642         unsigned int extra;
643
644         (void)token;
645         /* Argument is expected. */
646         if (!arg)
647                 return -1;
648         errno = 0;
649         u = strtoumax(str, &end, 0);
650         if (errno || (size_t)(end - str) != len)
651                 goto error;
652         bytes = u / 8;
653         extra = u % 8;
654         size = arg->size;
655         if (bytes > size || bytes + !!extra > size)
656                 goto error;
657         if (!ctx->object)
658                 return len;
659         buf = (uint8_t *)ctx->object + arg->offset;
660 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
661         if (!arg->hton) {
662                 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
663                 memset(buf, 0x00, size - bytes);
664                 if (extra)
665                         ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
666         } else
667 #endif
668         {
669                 memset(buf, 0xff, bytes);
670                 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
671                 if (extra)
672                         ((uint8_t *)buf)[bytes] = conv[extra];
673         }
674         if (ctx->objmask)
675                 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
676         return len;
677 error:
678         push_args(ctx, arg);
679         return -1;
680 }
681
682 /** Default parsing function for token name matching. */
683 static int
684 parse_default(struct context *ctx, const struct token *token,
685               const char *str, unsigned int len,
686               void *buf, unsigned int size)
687 {
688         (void)ctx;
689         (void)buf;
690         (void)size;
691         if (strncmp(str, token->name, len))
692                 return -1;
693         return len;
694 }
695
696 /** Parse flow command, initialize output buffer for subsequent tokens. */
697 static int
698 parse_init(struct context *ctx, const struct token *token,
699            const char *str, unsigned int len,
700            void *buf, unsigned int size)
701 {
702         struct buffer *out = buf;
703
704         /* Token name must match. */
705         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
706                 return -1;
707         /* Nothing else to do if there is no buffer. */
708         if (!out)
709                 return len;
710         /* Make sure buffer is large enough. */
711         if (size < sizeof(*out))
712                 return -1;
713         /* Initialize buffer. */
714         memset(out, 0x00, sizeof(*out));
715         memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
716         ctx->objdata = 0;
717         ctx->object = out;
718         ctx->objmask = NULL;
719         return len;
720 }
721
722 /** Parse tokens for validate/create commands. */
723 static int
724 parse_vc(struct context *ctx, const struct token *token,
725          const char *str, unsigned int len,
726          void *buf, unsigned int size)
727 {
728         struct buffer *out = buf;
729         uint8_t *data;
730         uint32_t data_size;
731
732         /* Token name must match. */
733         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
734                 return -1;
735         /* Nothing else to do if there is no buffer. */
736         if (!out)
737                 return len;
738         if (!out->command) {
739                 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
740                         return -1;
741                 if (sizeof(*out) > size)
742                         return -1;
743                 out->command = ctx->curr;
744                 ctx->objdata = 0;
745                 ctx->object = out;
746                 ctx->objmask = NULL;
747                 out->args.vc.data = (uint8_t *)out + size;
748                 return len;
749         }
750         ctx->objdata = 0;
751         ctx->object = &out->args.vc.attr;
752         ctx->objmask = NULL;
753         switch (ctx->curr) {
754         case GROUP:
755         case PRIORITY:
756                 return len;
757         case INGRESS:
758                 out->args.vc.attr.ingress = 1;
759                 return len;
760         case EGRESS:
761                 out->args.vc.attr.egress = 1;
762                 return len;
763         case PATTERN:
764                 out->args.vc.pattern =
765                         (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
766                                                sizeof(double));
767                 ctx->object = out->args.vc.pattern;
768                 ctx->objmask = NULL;
769                 return len;
770         case ACTIONS:
771                 out->args.vc.actions =
772                         (void *)RTE_ALIGN_CEIL((uintptr_t)
773                                                (out->args.vc.pattern +
774                                                 out->args.vc.pattern_n),
775                                                sizeof(double));
776                 ctx->object = out->args.vc.actions;
777                 ctx->objmask = NULL;
778                 return len;
779         default:
780                 if (!token->priv)
781                         return -1;
782                 break;
783         }
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;
788
789                 data_size = priv->size * 3; /* spec, last, mask */
790                 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
791                                                (out->args.vc.data - data_size),
792                                                sizeof(double));
793                 if ((uint8_t *)item + sizeof(*item) > data)
794                         return -1;
795                 *item = (struct rte_flow_item){
796                         .type = priv->type,
797                 };
798                 ++out->args.vc.pattern_n;
799                 ctx->object = item;
800                 ctx->objmask = NULL;
801         } else {
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;
805
806                 data_size = priv->size; /* configuration */
807                 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
808                                                (out->args.vc.data - data_size),
809                                                sizeof(double));
810                 if ((uint8_t *)action + sizeof(*action) > data)
811                         return -1;
812                 *action = (struct rte_flow_action){
813                         .type = priv->type,
814                 };
815                 ++out->args.vc.actions_n;
816                 ctx->object = action;
817                 ctx->objmask = NULL;
818         }
819         memset(data, 0, data_size);
820         out->args.vc.data = data;
821         ctx->objdata = data_size;
822         return len;
823 }
824
825 /** Parse pattern item parameter type. */
826 static int
827 parse_vc_spec(struct context *ctx, const struct token *token,
828               const char *str, unsigned int len,
829               void *buf, unsigned int size)
830 {
831         struct buffer *out = buf;
832         struct rte_flow_item *item;
833         uint32_t data_size;
834         int index;
835         int objmask = 0;
836
837         (void)size;
838         /* Token name must match. */
839         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
840                 return -1;
841         /* Parse parameter types. */
842         switch (ctx->curr) {
843         case ITEM_PARAM_IS:
844                 index = 0;
845                 objmask = 1;
846                 break;
847         case ITEM_PARAM_SPEC:
848                 index = 0;
849                 break;
850         case ITEM_PARAM_LAST:
851                 index = 1;
852                 break;
853         case ITEM_PARAM_PREFIX:
854                 /* Modify next token to expect a prefix. */
855                 if (ctx->next_num < 2)
856                         return -1;
857                 ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
858                 /* Fall through. */
859         case ITEM_PARAM_MASK:
860                 index = 2;
861                 break;
862         default:
863                 return -1;
864         }
865         /* Nothing else to do if there is no buffer. */
866         if (!out)
867                 return len;
868         if (!out->args.vc.pattern_n)
869                 return -1;
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);
874         if (objmask) {
875                 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
876                 item->mask = ctx->objmask;
877         } else
878                 ctx->objmask = NULL;
879         /* Update relevant item pointer. */
880         *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
881                 ctx->object;
882         return len;
883 }
884
885 /** Parse tokens for destroy command. */
886 static int
887 parse_destroy(struct context *ctx, const struct token *token,
888               const char *str, unsigned int len,
889               void *buf, unsigned int size)
890 {
891         struct buffer *out = buf;
892
893         /* Token name must match. */
894         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
895                 return -1;
896         /* Nothing else to do if there is no buffer. */
897         if (!out)
898                 return len;
899         if (!out->command) {
900                 if (ctx->curr != DESTROY)
901                         return -1;
902                 if (sizeof(*out) > size)
903                         return -1;
904                 out->command = ctx->curr;
905                 ctx->objdata = 0;
906                 ctx->object = out;
907                 ctx->objmask = NULL;
908                 out->args.destroy.rule =
909                         (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
910                                                sizeof(double));
911                 return len;
912         }
913         if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
914              sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
915                 return -1;
916         ctx->objdata = 0;
917         ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
918         ctx->objmask = NULL;
919         return len;
920 }
921
922 /** Parse tokens for flush command. */
923 static int
924 parse_flush(struct context *ctx, const struct token *token,
925             const char *str, unsigned int len,
926             void *buf, unsigned int size)
927 {
928         struct buffer *out = buf;
929
930         /* Token name must match. */
931         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
932                 return -1;
933         /* Nothing else to do if there is no buffer. */
934         if (!out)
935                 return len;
936         if (!out->command) {
937                 if (ctx->curr != FLUSH)
938                         return -1;
939                 if (sizeof(*out) > size)
940                         return -1;
941                 out->command = ctx->curr;
942                 ctx->objdata = 0;
943                 ctx->object = out;
944                 ctx->objmask = NULL;
945         }
946         return len;
947 }
948
949 /** Parse tokens for query command. */
950 static int
951 parse_query(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 != QUERY)
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         }
973         return len;
974 }
975
976 /** Parse action names. */
977 static int
978 parse_action(struct context *ctx, const struct token *token,
979              const char *str, unsigned int len,
980              void *buf, unsigned int size)
981 {
982         struct buffer *out = buf;
983         const struct arg *arg = pop_args(ctx);
984         unsigned int i;
985
986         (void)size;
987         /* Argument is expected. */
988         if (!arg)
989                 return -1;
990         /* Parse action name. */
991         for (i = 0; next_action[i]; ++i) {
992                 const struct parse_action_priv *priv;
993
994                 token = &token_list[next_action[i]];
995                 if (strncmp(token->name, str, len))
996                         continue;
997                 priv = token->priv;
998                 if (!priv)
999                         goto error;
1000                 if (out)
1001                         memcpy((uint8_t *)ctx->object + arg->offset,
1002                                &priv->type,
1003                                arg->size);
1004                 return len;
1005         }
1006 error:
1007         push_args(ctx, arg);
1008         return -1;
1009 }
1010
1011 /** Parse tokens for list command. */
1012 static int
1013 parse_list(struct context *ctx, const struct token *token,
1014            const char *str, unsigned int len,
1015            void *buf, unsigned int size)
1016 {
1017         struct buffer *out = buf;
1018
1019         /* Token name must match. */
1020         if (parse_default(ctx, token, str, len, NULL, 0) < 0)
1021                 return -1;
1022         /* Nothing else to do if there is no buffer. */
1023         if (!out)
1024                 return len;
1025         if (!out->command) {
1026                 if (ctx->curr != LIST)
1027                         return -1;
1028                 if (sizeof(*out) > size)
1029                         return -1;
1030                 out->command = ctx->curr;
1031                 ctx->objdata = 0;
1032                 ctx->object = out;
1033                 ctx->objmask = NULL;
1034                 out->args.list.group =
1035                         (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
1036                                                sizeof(double));
1037                 return len;
1038         }
1039         if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
1040              sizeof(*out->args.list.group)) > (uint8_t *)out + size)
1041                 return -1;
1042         ctx->objdata = 0;
1043         ctx->object = out->args.list.group + out->args.list.group_n++;
1044         ctx->objmask = NULL;
1045         return len;
1046 }
1047
1048 /**
1049  * Parse signed/unsigned integers 8 to 64-bit long.
1050  *
1051  * Last argument (ctx->args) is retrieved to determine integer type and
1052  * storage location.
1053  */
1054 static int
1055 parse_int(struct context *ctx, const struct token *token,
1056           const char *str, unsigned int len,
1057           void *buf, unsigned int size)
1058 {
1059         const struct arg *arg = pop_args(ctx);
1060         uintmax_t u;
1061         char *end;
1062
1063         (void)token;
1064         /* Argument is expected. */
1065         if (!arg)
1066                 return -1;
1067         errno = 0;
1068         u = arg->sign ?
1069                 (uintmax_t)strtoimax(str, &end, 0) :
1070                 strtoumax(str, &end, 0);
1071         if (errno || (size_t)(end - str) != len)
1072                 goto error;
1073         if (!ctx->object)
1074                 return len;
1075         buf = (uint8_t *)ctx->object + arg->offset;
1076         size = arg->size;
1077 objmask:
1078         switch (size) {
1079         case sizeof(uint8_t):
1080                 *(uint8_t *)buf = u;
1081                 break;
1082         case sizeof(uint16_t):
1083                 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
1084                 break;
1085         case sizeof(uint32_t):
1086                 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
1087                 break;
1088         case sizeof(uint64_t):
1089                 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
1090                 break;
1091         default:
1092                 goto error;
1093         }
1094         if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
1095                 u = -1;
1096                 buf = (uint8_t *)ctx->objmask + arg->offset;
1097                 goto objmask;
1098         }
1099         return len;
1100 error:
1101         push_args(ctx, arg);
1102         return -1;
1103 }
1104
1105 /** Parse port and update context. */
1106 static int
1107 parse_port(struct context *ctx, const struct token *token,
1108            const char *str, unsigned int len,
1109            void *buf, unsigned int size)
1110 {
1111         struct buffer *out = &(struct buffer){ .port = 0 };
1112         int ret;
1113
1114         if (buf)
1115                 out = buf;
1116         else {
1117                 ctx->objdata = 0;
1118                 ctx->object = out;
1119                 ctx->objmask = NULL;
1120                 size = sizeof(*out);
1121         }
1122         ret = parse_int(ctx, token, str, len, out, size);
1123         if (ret >= 0)
1124                 ctx->port = out->port;
1125         if (!buf)
1126                 ctx->object = NULL;
1127         return ret;
1128 }
1129
1130 /** No completion. */
1131 static int
1132 comp_none(struct context *ctx, const struct token *token,
1133           unsigned int ent, char *buf, unsigned int size)
1134 {
1135         (void)ctx;
1136         (void)token;
1137         (void)ent;
1138         (void)buf;
1139         (void)size;
1140         return 0;
1141 }
1142
1143 /** Complete action names. */
1144 static int
1145 comp_action(struct context *ctx, const struct token *token,
1146             unsigned int ent, char *buf, unsigned int size)
1147 {
1148         unsigned int i;
1149
1150         (void)ctx;
1151         (void)token;
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);
1156         if (buf)
1157                 return -1;
1158         return i;
1159 }
1160
1161 /** Complete available ports. */
1162 static int
1163 comp_port(struct context *ctx, const struct token *token,
1164           unsigned int ent, char *buf, unsigned int size)
1165 {
1166         unsigned int i = 0;
1167         portid_t p;
1168
1169         (void)ctx;
1170         (void)token;
1171         FOREACH_PORT(p, ports) {
1172                 if (buf && i == ent)
1173                         return snprintf(buf, size, "%u", p);
1174                 ++i;
1175         }
1176         if (buf)
1177                 return -1;
1178         return i;
1179 }
1180
1181 /** Complete available rule IDs. */
1182 static int
1183 comp_rule_id(struct context *ctx, const struct token *token,
1184              unsigned int ent, char *buf, unsigned int size)
1185 {
1186         unsigned int i = 0;
1187         struct rte_port *port;
1188         struct port_flow *pf;
1189
1190         (void)token;
1191         if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
1192             ctx->port == (uint16_t)RTE_PORT_ALL)
1193                 return -1;
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);
1198                 ++i;
1199         }
1200         if (buf)
1201                 return -1;
1202         return i;
1203 }
1204
1205 /** Internal context. */
1206 static struct context cmd_flow_context;
1207
1208 /** Global parser instance (cmdline API). */
1209 cmdline_parse_inst_t cmd_flow;
1210
1211 /** Initialize context. */
1212 static void
1213 cmd_flow_context_init(struct context *ctx)
1214 {
1215         /* A full memset() is not necessary. */
1216         ctx->curr = ZERO;
1217         ctx->prev = ZERO;
1218         ctx->next_num = 0;
1219         ctx->args_num = 0;
1220         ctx->reparse = 0;
1221         ctx->eol = 0;
1222         ctx->last = 0;
1223         ctx->port = 0;
1224         ctx->objdata = 0;
1225         ctx->object = NULL;
1226         ctx->objmask = NULL;
1227 }
1228
1229 /** Parse a token (cmdline API). */
1230 static int
1231 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
1232                unsigned int size)
1233 {
1234         struct context *ctx = &cmd_flow_context;
1235         const struct token *token;
1236         const enum index *list;
1237         int len;
1238         int i;
1239
1240         (void)hdr;
1241         /* Restart as requested. */
1242         if (ctx->reparse)
1243                 cmd_flow_context_init(ctx);
1244         token = &token_list[ctx->curr];
1245         /* Check argument length. */
1246         ctx->eol = 0;
1247         ctx->last = 1;
1248         for (len = 0; src[len]; ++len)
1249                 if (src[len] == '#' || isspace(src[len]))
1250                         break;
1251         if (!len)
1252                 return -1;
1253         /* Last argument and EOL detection. */
1254         for (i = len; src[i]; ++i)
1255                 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
1256                         break;
1257                 else if (!isspace(src[i])) {
1258                         ctx->last = 0;
1259                         break;
1260                 }
1261         for (; src[i]; ++i)
1262                 if (src[i] == '\r' || src[i] == '\n') {
1263                         ctx->eol = 1;
1264                         break;
1265                 }
1266         /* Initialize context if necessary. */
1267         if (!ctx->next_num) {
1268                 if (!token->next)
1269                         return 0;
1270                 ctx->next[ctx->next_num++] = token->next[0];
1271         }
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]];
1277                 int tmp;
1278
1279                 ctx->curr = list[i];
1280                 if (next->call)
1281                         tmp = next->call(ctx, next, src, len, result, size);
1282                 else
1283                         tmp = parse_default(ctx, next, src, len, result, size);
1284                 if (tmp == -1 || tmp != len)
1285                         continue;
1286                 token = next;
1287                 break;
1288         }
1289         if (!list[i])
1290                 return -1;
1291         --ctx->next_num;
1292         /* Push subsequent tokens if any. */
1293         if (token->next)
1294                 for (i = 0; token->next[i]; ++i) {
1295                         if (ctx->next_num == RTE_DIM(ctx->next))
1296                                 return -1;
1297                         ctx->next[ctx->next_num++] = token->next[i];
1298                 }
1299         /* Push arguments if any. */
1300         if (token->args)
1301                 for (i = 0; token->args[i]; ++i) {
1302                         if (ctx->args_num == RTE_DIM(ctx->args))
1303                                 return -1;
1304                         ctx->args[ctx->args_num++] = token->args[i];
1305                 }
1306         return len;
1307 }
1308
1309 /** Return number of completion entries (cmdline API). */
1310 static int
1311 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
1312 {
1313         struct context *ctx = &cmd_flow_context;
1314         const struct token *token = &token_list[ctx->curr];
1315         const enum index *list;
1316         int i;
1317
1318         (void)hdr;
1319         /* Tell cmd_flow_parse() that context must be reinitialized. */
1320         ctx->reparse = 1;
1321         /* Count number of tokens in current list. */
1322         if (ctx->next_num)
1323                 list = ctx->next[ctx->next_num - 1];
1324         else
1325                 list = token->next[0];
1326         for (i = 0; list[i]; ++i)
1327                 ;
1328         if (!i)
1329                 return 0;
1330         /*
1331          * If there is a single token, use its completion callback, otherwise
1332          * return the number of entries.
1333          */
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);
1339         }
1340         return i;
1341 }
1342
1343 /** Return a completion entry (cmdline API). */
1344 static int
1345 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
1346                           char *dst, unsigned int size)
1347 {
1348         struct context *ctx = &cmd_flow_context;
1349         const struct token *token = &token_list[ctx->curr];
1350         const enum index *list;
1351         int i;
1352
1353         (void)hdr;
1354         /* Tell cmd_flow_parse() that context must be reinitialized. */
1355         ctx->reparse = 1;
1356         /* Count number of tokens in current list. */
1357         if (ctx->next_num)
1358                 list = ctx->next[ctx->next_num - 1];
1359         else
1360                 list = token->next[0];
1361         for (i = 0; list[i]; ++i)
1362                 ;
1363         if (!i)
1364                 return -1;
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;
1371         }
1372         /* Otherwise make sure the index is valid and use defaults. */
1373         if (index >= i)
1374                 return -1;
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];
1379         return 0;
1380 }
1381
1382 /** Populate help strings for current token (cmdline API). */
1383 static int
1384 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
1385 {
1386         struct context *ctx = &cmd_flow_context;
1387         const struct token *token = &token_list[ctx->prev];
1388
1389         (void)hdr;
1390         /* Tell cmd_flow_parse() that context must be reinitialized. */
1391         ctx->reparse = 1;
1392         if (!size)
1393                 return -1;
1394         /* Set token type and update global help with details. */
1395         snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
1396         if (token->help)
1397                 cmd_flow.help_str = token->help;
1398         else
1399                 cmd_flow.help_str = token->name;
1400         return 0;
1401 }
1402
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,
1410         },
1411         .offset = 0,
1412 };
1413
1414 /** Populate the next dynamic token. */
1415 static void
1416 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
1417              cmdline_parse_token_hdr_t *(*hdrs)[])
1418 {
1419         struct context *ctx = &cmd_flow_context;
1420
1421         /* Always reinitialize context before requesting the first token. */
1422         if (!(hdr - *hdrs))
1423                 cmd_flow_context_init(ctx);
1424         /* Return NULL when no more tokens are expected. */
1425         if (!ctx->next_num && ctx->curr) {
1426                 *hdr = NULL;
1427                 return;
1428         }
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];
1432                 int i;
1433
1434                 for (i = 0; list[i]; ++i) {
1435                         if (list[i] != END)
1436                                 continue;
1437                         *hdr = NULL;
1438                         return;
1439                 }
1440         }
1441         *hdr = &cmd_flow_token_hdr;
1442 }
1443
1444 /** Dispatch parsed buffer to function calls. */
1445 static void
1446 cmd_flow_parsed(const struct buffer *in)
1447 {
1448         switch (in->command) {
1449         case VALIDATE:
1450                 port_flow_validate(in->port, &in->args.vc.attr,
1451                                    in->args.vc.pattern, in->args.vc.actions);
1452                 break;
1453         case CREATE:
1454                 port_flow_create(in->port, &in->args.vc.attr,
1455                                  in->args.vc.pattern, in->args.vc.actions);
1456                 break;
1457         case DESTROY:
1458                 port_flow_destroy(in->port, in->args.destroy.rule_n,
1459                                   in->args.destroy.rule);
1460                 break;
1461         case FLUSH:
1462                 port_flow_flush(in->port);
1463                 break;
1464         case QUERY:
1465                 port_flow_query(in->port, in->args.query.rule,
1466                                 in->args.query.action);
1467                 break;
1468         case LIST:
1469                 port_flow_list(in->port, in->args.list.group_n,
1470                                in->args.list.group);
1471                 break;
1472         default:
1473                 break;
1474         }
1475 }
1476
1477 /** Token generator and output processing callback (cmdline API). */
1478 static void
1479 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
1480 {
1481         if (cl == NULL)
1482                 cmd_flow_tok(arg0, arg2);
1483         else
1484                 cmd_flow_parsed(arg0);
1485 }
1486
1487 /** Global parser instance (cmdline API). */
1488 cmdline_parse_inst_t cmd_flow = {
1489         .f = cmd_flow_cb,
1490         .data = NULL, /**< Unused. */
1491         .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
1492         .tokens = {
1493                 NULL,
1494         }, /**< Tokens are returned by cmd_flow_tok(). */
1495 };