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