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