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