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