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