ethdev: bring in async queue-based flow rules operations
[dpdk.git] / lib / pipeline / rte_swx_pipeline_spec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
9
10 #include "rte_swx_pipeline.h"
11
12 #define MAX_LINE_LENGTH RTE_SWX_INSTRUCTION_SIZE
13 #define MAX_TOKENS RTE_SWX_INSTRUCTION_TOKENS_MAX
14
15 #define STRUCT_BLOCK 0
16 #define ACTION_BLOCK 1
17 #define TABLE_BLOCK 2
18 #define TABLE_KEY_BLOCK 3
19 #define TABLE_ACTIONS_BLOCK 4
20 #define SELECTOR_BLOCK 5
21 #define SELECTOR_SELECTOR_BLOCK 6
22 #define LEARNER_BLOCK 7
23 #define LEARNER_KEY_BLOCK 8
24 #define LEARNER_ACTIONS_BLOCK 9
25 #define APPLY_BLOCK 10
26
27 /*
28  * extobj.
29  *
30  * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
31  */
32 struct extobj_spec {
33         char *name;
34         char *extern_type_name;
35         char *pragma;
36 };
37
38 static void
39 extobj_spec_free(struct extobj_spec *s)
40 {
41         if (!s)
42                 return;
43
44         free(s->name);
45         s->name = NULL;
46
47         free(s->extern_type_name);
48         s->extern_type_name = NULL;
49
50         free(s->pragma);
51         s->pragma = NULL;
52 }
53
54 static int
55 extobj_statement_parse(struct extobj_spec *s,
56                        char **tokens,
57                        uint32_t n_tokens,
58                        uint32_t n_lines,
59                        uint32_t *err_line,
60                        const char **err_msg)
61 {
62         /* Check format. */
63         if (((n_tokens != 4) && (n_tokens != 6)) ||
64             ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
65             ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
66                                  strcmp(tokens[4], "pragma")))) {
67                 if (err_line)
68                         *err_line = n_lines;
69                 if (err_msg)
70                         *err_msg = "Invalid extobj statement.";
71                 return -EINVAL;
72         }
73
74         /* spec. */
75         s->name = strdup(tokens[1]);
76         s->extern_type_name = strdup(tokens[3]);
77         s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
78
79         if (!s->name ||
80             !s->extern_type_name ||
81             ((n_tokens == 6) && !s->pragma)) {
82                 free(s->name);
83                 free(s->extern_type_name);
84                 free(s->pragma);
85
86                 if (err_line)
87                         *err_line = n_lines;
88                 if (err_msg)
89                         *err_msg = "Memory allocation failed.";
90                 return -ENOMEM;
91         }
92
93         return 0;
94 }
95
96 /*
97  * struct.
98  *
99  * struct STRUCT_TYPE_NAME {
100  *      bit<SIZE> | varbit<SIZE> FIELD_NAME
101  *      ...
102  * }
103  */
104 struct struct_spec {
105         char *name;
106         struct rte_swx_field_params *fields;
107         uint32_t n_fields;
108         int varbit;
109 };
110
111 static void
112 struct_spec_free(struct struct_spec *s)
113 {
114         uint32_t i;
115
116         if (!s)
117                 return;
118
119         free(s->name);
120         s->name = NULL;
121
122         for (i = 0; i < s->n_fields; i++) {
123                 uintptr_t name = (uintptr_t)s->fields[i].name;
124
125                 free((void *)name);
126         }
127
128         free(s->fields);
129         s->fields = NULL;
130
131         s->n_fields = 0;
132
133         s->varbit = 0;
134 }
135
136 static int
137 struct_statement_parse(struct struct_spec *s,
138                        uint32_t *block_mask,
139                        char **tokens,
140                        uint32_t n_tokens,
141                        uint32_t n_lines,
142                        uint32_t *err_line,
143                        const char **err_msg)
144 {
145         /* Check format. */
146         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
147                 if (err_line)
148                         *err_line = n_lines;
149                 if (err_msg)
150                         *err_msg = "Invalid struct statement.";
151                 return -EINVAL;
152         }
153
154         /* spec. */
155         s->name = strdup(tokens[1]);
156         if (!s->name) {
157                 if (err_line)
158                         *err_line = n_lines;
159                 if (err_msg)
160                         *err_msg = "Memory allocation failed.";
161                 return -ENOMEM;
162         }
163
164         /* block_mask. */
165         *block_mask |= 1 << STRUCT_BLOCK;
166
167         return 0;
168 }
169
170 static int
171 struct_block_parse(struct struct_spec *s,
172                    uint32_t *block_mask,
173                    char **tokens,
174                    uint32_t n_tokens,
175                    uint32_t n_lines,
176                    uint32_t *err_line,
177                    const char **err_msg)
178 {
179         struct rte_swx_field_params *new_fields;
180         char *p = tokens[0], *name = NULL;
181         uint32_t n_bits;
182         int varbit = 0, error = 0, error_size_invalid = 0, error_varbit_not_last = 0;
183
184         /* Handle end of block. */
185         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
186                 *block_mask &= ~(1 << STRUCT_BLOCK);
187                 return 0;
188         }
189
190         /* Check format. */
191         if (n_tokens != 2) {
192                 error = -EINVAL;
193                 goto error;
194         }
195
196         if (s->varbit) {
197                 error = -EINVAL;
198                 error_varbit_not_last = 1;
199                 goto error;
200         }
201
202         if (!strncmp(p, "bit<", strlen("bit<"))) {
203                 size_t len = strlen(p);
204
205                 if ((len < strlen("bit< >")) || (p[len - 1] != '>')) {
206                         error = -EINVAL;
207                         goto error;
208                 }
209
210                 /* Remove the "bit<" and ">". */
211                 p[strlen(p) - 1] = 0;
212                 p += strlen("bit<");
213         } else if (!strncmp(p, "varbit<", strlen("varbit<"))) {
214                 size_t len = strlen(p);
215
216                 if ((len < strlen("varbit< >")) || (p[len - 1] != '>')) {
217                         error = -EINVAL;
218                         goto error;
219                 }
220
221                 /* Remove the "varbit<" and ">". */
222                 p[strlen(p) - 1] = 0;
223                 p += strlen("varbit<");
224
225                 /* Set the varbit flag. */
226                 varbit = 1;
227         } else {
228                 error = -EINVAL;
229                 goto error;
230         }
231
232         n_bits = strtoul(p, &p, 0);
233         if ((p[0]) ||
234             !n_bits ||
235             (n_bits % 8) ||
236             ((n_bits > 64) && !varbit)) {
237                 error = -EINVAL;
238                 error_size_invalid = 1;
239                 goto error;
240         }
241
242         /* spec. */
243         name = strdup(tokens[1]);
244         if (!name) {
245                 error = -ENOMEM;
246                 goto error;
247         }
248
249         new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
250         if (!new_fields) {
251                 error = -ENOMEM;
252                 goto error;
253         }
254
255         s->fields = new_fields;
256         s->fields[s->n_fields].name = name;
257         s->fields[s->n_fields].n_bits = n_bits;
258         s->n_fields++;
259         s->varbit = varbit;
260
261         return 0;
262
263 error:
264         free(name);
265
266         if (err_line)
267                 *err_line = n_lines;
268
269         if (err_msg) {
270                 *err_msg = "Invalid struct field statement.";
271
272                 if ((error == -EINVAL) && error_varbit_not_last)
273                         *err_msg = "Varbit field is not the last struct field.";
274
275                 if ((error == -EINVAL) && error_size_invalid)
276                         *err_msg = "Invalid struct field size.";
277
278                 if (error == -ENOMEM)
279                         *err_msg = "Memory allocation failed.";
280         }
281
282         return error;
283 }
284
285 /*
286  * header.
287  *
288  * header HEADER_NAME instanceof STRUCT_TYPE_NAME
289  */
290 struct header_spec {
291         char *name;
292         char *struct_type_name;
293 };
294
295 static void
296 header_spec_free(struct header_spec *s)
297 {
298         if (!s)
299                 return;
300
301         free(s->name);
302         s->name = NULL;
303
304         free(s->struct_type_name);
305         s->struct_type_name = NULL;
306 }
307
308 static int
309 header_statement_parse(struct header_spec *s,
310                        char **tokens,
311                        uint32_t n_tokens,
312                        uint32_t n_lines,
313                        uint32_t *err_line,
314                        const char **err_msg)
315 {
316         /* Check format. */
317         if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
318                 if (err_line)
319                         *err_line = n_lines;
320                 if (err_msg)
321                         *err_msg = "Invalid header statement.";
322                 return -EINVAL;
323         }
324
325         /* spec. */
326         s->name = strdup(tokens[1]);
327         s->struct_type_name = strdup(tokens[3]);
328
329         if (!s->name || !s->struct_type_name) {
330                 free(s->name);
331                 free(s->struct_type_name);
332
333                 if (err_line)
334                         *err_line = n_lines;
335                 if (err_msg)
336                         *err_msg = "Memory allocation failed.";
337                 return -ENOMEM;
338         }
339
340         return 0;
341 }
342
343 /*
344  * metadata.
345  *
346  * metadata instanceof STRUCT_TYPE_NAME
347  */
348 struct metadata_spec {
349         char *struct_type_name;
350 };
351
352 static void
353 metadata_spec_free(struct metadata_spec *s)
354 {
355         if (!s)
356                 return;
357
358         free(s->struct_type_name);
359         s->struct_type_name = NULL;
360 }
361
362 static int
363 metadata_statement_parse(struct metadata_spec *s,
364                          char **tokens,
365                          uint32_t n_tokens,
366                          uint32_t n_lines,
367                          uint32_t *err_line,
368                          const char **err_msg)
369 {
370         /* Check format. */
371         if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
372                 if (err_line)
373                         *err_line = n_lines;
374                 if (err_msg)
375                         *err_msg = "Invalid metadata statement.";
376                 return -EINVAL;
377         }
378
379         /* spec. */
380         s->struct_type_name = strdup(tokens[2]);
381         if (!s->struct_type_name) {
382                 if (err_line)
383                         *err_line = n_lines;
384                 if (err_msg)
385                         *err_msg = "Memory allocation failed.";
386                 return -ENOMEM;
387         }
388
389         return 0;
390 }
391
392 /*
393  * action.
394  *
395  * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
396  *      INSTRUCTION
397  *      ...
398  * }
399  */
400 struct action_spec {
401         char *name;
402         char *args_struct_type_name;
403         const char **instructions;
404         uint32_t n_instructions;
405 };
406
407 static void
408 action_spec_free(struct action_spec *s)
409 {
410         uint32_t i;
411
412         if (!s)
413                 return;
414
415         free(s->name);
416         s->name = NULL;
417
418         free(s->args_struct_type_name);
419         s->args_struct_type_name = NULL;
420
421         for (i = 0; i < s->n_instructions; i++) {
422                 uintptr_t instr = (uintptr_t)s->instructions[i];
423
424                 free((void *)instr);
425         }
426
427         free(s->instructions);
428         s->instructions = NULL;
429
430         s->n_instructions = 0;
431 }
432
433 static int
434 action_statement_parse(struct action_spec *s,
435                        uint32_t *block_mask,
436                        char **tokens,
437                        uint32_t n_tokens,
438                        uint32_t n_lines,
439                        uint32_t *err_line,
440                        const char **err_msg)
441 {
442         /* Check format. */
443         if (((n_tokens != 5) && (n_tokens != 6)) ||
444             ((n_tokens == 5) &&
445              (strcmp(tokens[2], "args") ||
446               strcmp(tokens[3], "none") ||
447               strcmp(tokens[4], "{"))) ||
448             ((n_tokens == 6) &&
449              (strcmp(tokens[2], "args") ||
450               strcmp(tokens[3], "instanceof") ||
451               strcmp(tokens[5], "{")))) {
452                 if (err_line)
453                         *err_line = n_lines;
454                 if (err_msg)
455                         *err_msg = "Invalid action statement.";
456                 return -EINVAL;
457         }
458
459         /* spec. */
460         s->name = strdup(tokens[1]);
461         s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
462
463         if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
464                 if (err_line)
465                         *err_line = n_lines;
466                 if (err_msg)
467                         *err_msg = "Memory allocation failed.";
468                 return -ENOMEM;
469         }
470
471         /* block_mask. */
472         *block_mask |= 1 << ACTION_BLOCK;
473
474         return 0;
475 }
476
477 static int
478 action_block_parse(struct action_spec *s,
479                    uint32_t *block_mask,
480                    char **tokens,
481                    uint32_t n_tokens,
482                    uint32_t n_lines,
483                    uint32_t *err_line,
484                    const char **err_msg)
485 {
486         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
487         const char **new_instructions;
488         uint32_t i;
489
490         /* Handle end of block. */
491         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
492                 *block_mask &= ~(1 << ACTION_BLOCK);
493                 return 0;
494         }
495
496         /* spec. */
497         buffer[0] = 0;
498         for (i = 0; i < n_tokens; i++) {
499                 if (i)
500                         strcat(buffer, " ");
501                 strcat(buffer, tokens[i]);
502         }
503
504         instr = strdup(buffer);
505         if (!instr) {
506                 if (err_line)
507                         *err_line = n_lines;
508                 if (err_msg)
509                         *err_msg = "Memory allocation failed.";
510                 return -ENOMEM;
511         }
512
513         new_instructions = realloc(s->instructions,
514                                    (s->n_instructions + 1) * sizeof(char *));
515         if (!new_instructions) {
516                 free(instr);
517
518                 if (err_line)
519                         *err_line = n_lines;
520                 if (err_msg)
521                         *err_msg = "Memory allocation failed.";
522                 return -ENOMEM;
523         }
524
525         s->instructions = new_instructions;
526         s->instructions[s->n_instructions] = instr;
527         s->n_instructions++;
528
529         return 0;
530 }
531
532 /*
533  * table.
534  *
535  * table {
536  *      key {
537  *              MATCH_FIELD_NAME exact | wildcard | lpm
538  *              ...
539  *      }
540  *      actions {
541  *              ACTION_NAME [ @tableonly | @defaultonly ]
542  *              ...
543  *      }
544  *      default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
545  *      instanceof TABLE_TYPE_NAME
546  *      pragma ARGS
547  *      size SIZE
548  * }
549  */
550 struct table_spec {
551         char *name;
552         struct rte_swx_pipeline_table_params params;
553         char *recommended_table_type_name;
554         char *args;
555         uint32_t size;
556 };
557
558 static void
559 table_spec_free(struct table_spec *s)
560 {
561         uintptr_t default_action_name;
562         uint32_t i;
563
564         if (!s)
565                 return;
566
567         free(s->name);
568         s->name = NULL;
569
570         for (i = 0; i < s->params.n_fields; i++) {
571                 uintptr_t name = (uintptr_t)s->params.fields[i].name;
572
573                 free((void *)name);
574         }
575
576         free(s->params.fields);
577         s->params.fields = NULL;
578
579         s->params.n_fields = 0;
580
581         for (i = 0; i < s->params.n_actions; i++) {
582                 uintptr_t name = (uintptr_t)s->params.action_names[i];
583
584                 free((void *)name);
585         }
586
587         free(s->params.action_names);
588         s->params.action_names = NULL;
589
590         s->params.n_actions = 0;
591
592         default_action_name = (uintptr_t)s->params.default_action_name;
593         free((void *)default_action_name);
594         s->params.default_action_name = NULL;
595
596         free(s->params.default_action_data);
597         s->params.default_action_data = NULL;
598
599         free(s->params.action_is_for_table_entries);
600         s->params.action_is_for_table_entries = NULL;
601
602         free(s->params.action_is_for_default_entry);
603         s->params.action_is_for_default_entry = NULL;
604
605         s->params.default_action_is_const = 0;
606
607         free(s->recommended_table_type_name);
608         s->recommended_table_type_name = NULL;
609
610         free(s->args);
611         s->args = NULL;
612
613         s->size = 0;
614 }
615
616 static int
617 table_key_statement_parse(uint32_t *block_mask,
618                           char **tokens,
619                           uint32_t n_tokens,
620                           uint32_t n_lines,
621                           uint32_t *err_line,
622                           const char **err_msg)
623 {
624         /* Check format. */
625         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
626                 if (err_line)
627                         *err_line = n_lines;
628                 if (err_msg)
629                         *err_msg = "Invalid key statement.";
630                 return -EINVAL;
631         }
632
633         /* block_mask. */
634         *block_mask |= 1 << TABLE_KEY_BLOCK;
635
636         return 0;
637 }
638
639 static int
640 table_key_block_parse(struct table_spec *s,
641                       uint32_t *block_mask,
642                       char **tokens,
643                       uint32_t n_tokens,
644                       uint32_t n_lines,
645                       uint32_t *err_line,
646                       const char **err_msg)
647 {
648         struct rte_swx_match_field_params *new_fields;
649         enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
650         char *name;
651
652         /* Handle end of block. */
653         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
654                 *block_mask &= ~(1 << TABLE_KEY_BLOCK);
655                 return 0;
656         }
657
658         /* Check input arguments. */
659         if ((n_tokens != 2) ||
660             (strcmp(tokens[1], "exact") &&
661              strcmp(tokens[1], "wildcard") &&
662              strcmp(tokens[1], "lpm"))) {
663                 if (err_line)
664                         *err_line = n_lines;
665                 if (err_msg)
666                         *err_msg = "Invalid match field statement.";
667                 return -EINVAL;
668         }
669
670         if (!strcmp(tokens[1], "wildcard"))
671                 match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
672         if (!strcmp(tokens[1], "lpm"))
673                 match_type = RTE_SWX_TABLE_MATCH_LPM;
674         if (!strcmp(tokens[1], "exact"))
675                 match_type = RTE_SWX_TABLE_MATCH_EXACT;
676
677         name = strdup(tokens[0]);
678         if (!name) {
679                 if (err_line)
680                         *err_line = n_lines;
681                 if (err_msg)
682                         *err_msg = "Memory allocation failed.";
683                 return -ENOMEM;
684         }
685
686         new_fields = realloc(s->params.fields,
687                              (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
688         if (!new_fields) {
689                 free(name);
690
691                 if (err_line)
692                         *err_line = n_lines;
693                 if (err_msg)
694                         *err_msg = "Memory allocation failed.";
695                 return -ENOMEM;
696         }
697
698         s->params.fields = new_fields;
699         s->params.fields[s->params.n_fields].name = name;
700         s->params.fields[s->params.n_fields].match_type = match_type;
701         s->params.n_fields++;
702
703         return 0;
704 }
705
706 static int
707 table_actions_statement_parse(uint32_t *block_mask,
708                               char **tokens,
709                               uint32_t n_tokens,
710                               uint32_t n_lines,
711                               uint32_t *err_line,
712                               const char **err_msg)
713 {
714         /* Check format. */
715         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
716                 if (err_line)
717                         *err_line = n_lines;
718                 if (err_msg)
719                         *err_msg = "Invalid actions statement.";
720                 return -EINVAL;
721         }
722
723         /* block_mask. */
724         *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
725
726         return 0;
727 }
728
729 static int
730 table_actions_block_parse(struct table_spec *s,
731                           uint32_t *block_mask,
732                           char **tokens,
733                           uint32_t n_tokens,
734                           uint32_t n_lines,
735                           uint32_t *err_line,
736                           const char **err_msg)
737 {
738         const char **new_action_names = NULL;
739         int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
740         char *name = NULL;
741         int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
742
743         /* Handle end of block. */
744         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
745                 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
746                 return 0;
747         }
748
749         /* Check input arguments. */
750         if ((n_tokens > 2) ||
751             ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
752               strcmp(tokens[1], "@defaultonly"))) {
753                 if (err_line)
754                         *err_line = n_lines;
755                 if (err_msg)
756                         *err_msg = "Invalid action name statement.";
757                 return -EINVAL;
758         }
759
760         name = strdup(tokens[0]);
761
762         if (n_tokens == 2) {
763                 if (!strcmp(tokens[1], "@tableonly"))
764                         action_is_for_default_entry = 0;
765
766                 if (!strcmp(tokens[1], "@defaultonly"))
767                         action_is_for_table_entries = 0;
768         }
769
770         new_action_names = realloc(s->params.action_names,
771                                    (s->params.n_actions + 1) * sizeof(char *));
772         new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
773                                                   (s->params.n_actions + 1) * sizeof(int));
774         new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
775                                                   (s->params.n_actions + 1) * sizeof(int));
776
777         if (!name ||
778             !new_action_names ||
779             !new_action_is_for_table_entries ||
780             !new_action_is_for_default_entry) {
781                 free(name);
782                 free(new_action_names);
783                 free(new_action_is_for_table_entries);
784                 free(new_action_is_for_default_entry);
785
786                 if (err_line)
787                         *err_line = n_lines;
788                 if (err_msg)
789                         *err_msg = "Memory allocation failed.";
790                 return -ENOMEM;
791         }
792
793         s->params.action_names = new_action_names;
794         s->params.action_names[s->params.n_actions] = name;
795
796         s->params.action_is_for_table_entries = new_action_is_for_table_entries;
797         s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
798
799         s->params.action_is_for_default_entry = new_action_is_for_default_entry;
800         s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
801
802         s->params.n_actions++;
803
804         return 0;
805 }
806
807 static int
808 table_statement_parse(struct table_spec *s,
809                       uint32_t *block_mask,
810                       char **tokens,
811                       uint32_t n_tokens,
812                       uint32_t n_lines,
813                       uint32_t *err_line,
814                       const char **err_msg)
815 {
816         /* Check format. */
817         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
818                 if (err_line)
819                         *err_line = n_lines;
820                 if (err_msg)
821                         *err_msg = "Invalid table statement.";
822                 return -EINVAL;
823         }
824
825         /* spec. */
826         s->name = strdup(tokens[1]);
827         if (!s->name) {
828                 if (err_line)
829                         *err_line = n_lines;
830                 if (err_msg)
831                         *err_msg = "Memory allocation failed.";
832                 return -ENOMEM;
833         }
834
835         /* block_mask. */
836         *block_mask |= 1 << TABLE_BLOCK;
837
838         return 0;
839 }
840
841 static int
842 table_block_parse(struct table_spec *s,
843                   uint32_t *block_mask,
844                   char **tokens,
845                   uint32_t n_tokens,
846                   uint32_t n_lines,
847                   uint32_t *err_line,
848                   const char **err_msg)
849 {
850         if (*block_mask & (1 << TABLE_KEY_BLOCK))
851                 return table_key_block_parse(s,
852                                              block_mask,
853                                              tokens,
854                                              n_tokens,
855                                              n_lines,
856                                              err_line,
857                                              err_msg);
858
859         if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
860                 return table_actions_block_parse(s,
861                                                  block_mask,
862                                                  tokens,
863                                                  n_tokens,
864                                                  n_lines,
865                                                  err_line,
866                                                  err_msg);
867
868         /* Handle end of block. */
869         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
870                 *block_mask &= ~(1 << TABLE_BLOCK);
871                 return 0;
872         }
873
874         if (!strcmp(tokens[0], "key"))
875                 return table_key_statement_parse(block_mask,
876                                                  tokens,
877                                                  n_tokens,
878                                                  n_lines,
879                                                  err_line,
880                                                  err_msg);
881
882         if (!strcmp(tokens[0], "actions"))
883                 return table_actions_statement_parse(block_mask,
884                                                      tokens,
885                                                      n_tokens,
886                                                      n_lines,
887                                                      err_line,
888                                                      err_msg);
889
890         if (!strcmp(tokens[0], "default_action")) {
891                 if (((n_tokens != 4) && (n_tokens != 5)) ||
892                     strcmp(tokens[2], "args") ||
893                     strcmp(tokens[3], "none") ||
894                     ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
895                         if (err_line)
896                                 *err_line = n_lines;
897                         if (err_msg)
898                                 *err_msg = "Invalid default_action statement.";
899                         return -EINVAL;
900                 }
901
902                 if (s->params.default_action_name) {
903                         if (err_line)
904                                 *err_line = n_lines;
905                         if (err_msg)
906                                 *err_msg = "Duplicate default_action stmt.";
907                         return -EINVAL;
908                 }
909
910                 s->params.default_action_name = strdup(tokens[1]);
911                 if (!s->params.default_action_name) {
912                         if (err_line)
913                                 *err_line = n_lines;
914                         if (err_msg)
915                                 *err_msg = "Memory allocation failed.";
916                         return -ENOMEM;
917                 }
918
919                 if (n_tokens == 5)
920                         s->params.default_action_is_const = 1;
921
922                 return 0;
923         }
924
925         if (!strcmp(tokens[0], "instanceof")) {
926                 if (n_tokens != 2) {
927                         if (err_line)
928                                 *err_line = n_lines;
929                         if (err_msg)
930                                 *err_msg = "Invalid instanceof statement.";
931                         return -EINVAL;
932                 }
933
934                 if (s->recommended_table_type_name) {
935                         if (err_line)
936                                 *err_line = n_lines;
937                         if (err_msg)
938                                 *err_msg = "Duplicate instanceof statement.";
939                         return -EINVAL;
940                 }
941
942                 s->recommended_table_type_name = strdup(tokens[1]);
943                 if (!s->recommended_table_type_name) {
944                         if (err_line)
945                                 *err_line = n_lines;
946                         if (err_msg)
947                                 *err_msg = "Memory allocation failed.";
948                         return -ENOMEM;
949                 }
950
951                 return 0;
952         }
953
954         if (!strcmp(tokens[0], "pragma")) {
955                 if (n_tokens != 2) {
956                         if (err_line)
957                                 *err_line = n_lines;
958                         if (err_msg)
959                                 *err_msg = "Invalid pragma statement.";
960                         return -EINVAL;
961                 }
962
963                 if (s->args) {
964                         if (err_line)
965                                 *err_line = n_lines;
966                         if (err_msg)
967                                 *err_msg = "Duplicate pragma statement.";
968                         return -EINVAL;
969                 }
970
971                 s->args = strdup(tokens[1]);
972                 if (!s->args) {
973                         if (err_line)
974                                 *err_line = n_lines;
975                         if (err_msg)
976                                 *err_msg = "Memory allocation failed.";
977                         return -ENOMEM;
978                 }
979
980                 return 0;
981         }
982
983         if (!strcmp(tokens[0], "size")) {
984                 char *p = tokens[1];
985
986                 if (n_tokens != 2) {
987                         if (err_line)
988                                 *err_line = n_lines;
989                         if (err_msg)
990                                 *err_msg = "Invalid pragma statement.";
991                         return -EINVAL;
992                 }
993
994                 s->size = strtoul(p, &p, 0);
995                 if (p[0]) {
996                         if (err_line)
997                                 *err_line = n_lines;
998                         if (err_msg)
999                                 *err_msg = "Invalid size argument.";
1000                         return -EINVAL;
1001                 }
1002
1003                 return 0;
1004         }
1005
1006         /* Anything else. */
1007         if (err_line)
1008                 *err_line = n_lines;
1009         if (err_msg)
1010                 *err_msg = "Invalid statement.";
1011         return -EINVAL;
1012 }
1013
1014 /*
1015  * selector.
1016  *
1017  * selector SELECTOR_NAME {
1018  *      group_id FIELD_NAME
1019  *      selector {
1020  *              FIELD_NAME
1021  *              ...
1022  *      }
1023  *      member_id FIELD_NAME
1024  *      n_groups N_GROUPS
1025  *      n_members_per_group N_MEMBERS_PER_GROUP
1026  * }
1027  */
1028 struct selector_spec {
1029         char *name;
1030         struct rte_swx_pipeline_selector_params params;
1031 };
1032
1033 static void
1034 selector_spec_free(struct selector_spec *s)
1035 {
1036         uintptr_t field_name;
1037         uint32_t i;
1038
1039         if (!s)
1040                 return;
1041
1042         /* name. */
1043         free(s->name);
1044         s->name = NULL;
1045
1046         /* params->group_id_field_name. */
1047         field_name = (uintptr_t)s->params.group_id_field_name;
1048         free((void *)field_name);
1049         s->params.group_id_field_name = NULL;
1050
1051         /* params->selector_field_names. */
1052         for (i = 0; i < s->params.n_selector_fields; i++) {
1053                 field_name = (uintptr_t)s->params.selector_field_names[i];
1054
1055                 free((void *)field_name);
1056         }
1057
1058         free(s->params.selector_field_names);
1059         s->params.selector_field_names = NULL;
1060
1061         s->params.n_selector_fields = 0;
1062
1063         /* params->member_id_field_name. */
1064         field_name = (uintptr_t)s->params.member_id_field_name;
1065         free((void *)field_name);
1066         s->params.member_id_field_name = NULL;
1067
1068         /* params->n_groups_max. */
1069         s->params.n_groups_max = 0;
1070
1071         /* params->n_members_per_group_max. */
1072         s->params.n_members_per_group_max = 0;
1073 }
1074
1075 static int
1076 selector_statement_parse(struct selector_spec *s,
1077                          uint32_t *block_mask,
1078                          char **tokens,
1079                          uint32_t n_tokens,
1080                          uint32_t n_lines,
1081                          uint32_t *err_line,
1082                          const char **err_msg)
1083 {
1084         /* Check format. */
1085         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1086                 if (err_line)
1087                         *err_line = n_lines;
1088                 if (err_msg)
1089                         *err_msg = "Invalid selector statement.";
1090                 return -EINVAL;
1091         }
1092
1093         /* spec. */
1094         s->name = strdup(tokens[1]);
1095         if (!s->name) {
1096                 if (err_line)
1097                         *err_line = n_lines;
1098                 if (err_msg)
1099                         *err_msg = "Memory allocation failed.";
1100                 return -ENOMEM;
1101         }
1102
1103         /* block_mask. */
1104         *block_mask |= 1 << SELECTOR_BLOCK;
1105
1106         return 0;
1107 }
1108
1109 static int
1110 selector_selector_statement_parse(uint32_t *block_mask,
1111                                   char **tokens,
1112                                   uint32_t n_tokens,
1113                                   uint32_t n_lines,
1114                                   uint32_t *err_line,
1115                                   const char **err_msg)
1116 {
1117         /* Check format. */
1118         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1119                 if (err_line)
1120                         *err_line = n_lines;
1121                 if (err_msg)
1122                         *err_msg = "Invalid selector statement.";
1123                 return -EINVAL;
1124         }
1125
1126         /* block_mask. */
1127         *block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
1128
1129         return 0;
1130 }
1131
1132 static int
1133 selector_selector_block_parse(struct selector_spec *s,
1134                               uint32_t *block_mask,
1135                               char **tokens,
1136                               uint32_t n_tokens,
1137                               uint32_t n_lines,
1138                               uint32_t *err_line,
1139                               const char **err_msg)
1140 {
1141         const char **new_fields;
1142         char *name;
1143
1144         /* Handle end of block. */
1145         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1146                 *block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
1147                 return 0;
1148         }
1149
1150         /* Check input arguments. */
1151         if (n_tokens != 1) {
1152                 if (err_line)
1153                         *err_line = n_lines;
1154                 if (err_msg)
1155                         *err_msg = "Invalid selector field statement.";
1156                 return -EINVAL;
1157         }
1158
1159         name = strdup(tokens[0]);
1160         if (!name) {
1161                 if (err_line)
1162                         *err_line = n_lines;
1163                 if (err_msg)
1164                         *err_msg = "Memory allocation failed.";
1165                 return -ENOMEM;
1166         }
1167
1168         new_fields = realloc(s->params.selector_field_names,
1169                              (s->params.n_selector_fields + 1) * sizeof(char *));
1170         if (!new_fields) {
1171                 free(name);
1172
1173                 if (err_line)
1174                         *err_line = n_lines;
1175                 if (err_msg)
1176                         *err_msg = "Memory allocation failed.";
1177                 return -ENOMEM;
1178         }
1179
1180         s->params.selector_field_names = new_fields;
1181         s->params.selector_field_names[s->params.n_selector_fields] = name;
1182         s->params.n_selector_fields++;
1183
1184         return 0;
1185 }
1186
1187 static int
1188 selector_block_parse(struct selector_spec *s,
1189                      uint32_t *block_mask,
1190                      char **tokens,
1191                      uint32_t n_tokens,
1192                      uint32_t n_lines,
1193                      uint32_t *err_line,
1194                      const char **err_msg)
1195 {
1196         if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK))
1197                 return selector_selector_block_parse(s,
1198                                                      block_mask,
1199                                                      tokens,
1200                                                      n_tokens,
1201                                                      n_lines,
1202                                                      err_line,
1203                                                      err_msg);
1204
1205         /* Handle end of block. */
1206         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1207                 *block_mask &= ~(1 << SELECTOR_BLOCK);
1208                 return 0;
1209         }
1210
1211         if (!strcmp(tokens[0], "group_id")) {
1212                 if (n_tokens != 2) {
1213                         if (err_line)
1214                                 *err_line = n_lines;
1215                         if (err_msg)
1216                                 *err_msg = "Invalid group_id statement.";
1217                         return -EINVAL;
1218                 }
1219
1220                 s->params.group_id_field_name = strdup(tokens[1]);
1221                 if (!s->params.group_id_field_name) {
1222                         if (err_line)
1223                                 *err_line = n_lines;
1224                         if (err_msg)
1225                                 *err_msg = "Memory allocation failed.";
1226                         return -ENOMEM;
1227                 }
1228
1229                 return 0;
1230         }
1231
1232         if (!strcmp(tokens[0], "selector"))
1233                 return selector_selector_statement_parse(block_mask,
1234                                                          tokens,
1235                                                          n_tokens,
1236                                                          n_lines,
1237                                                          err_line,
1238                                                          err_msg);
1239
1240         if (!strcmp(tokens[0], "member_id")) {
1241                 if (n_tokens != 2) {
1242                         if (err_line)
1243                                 *err_line = n_lines;
1244                         if (err_msg)
1245                                 *err_msg = "Invalid member_id statement.";
1246                         return -EINVAL;
1247                 }
1248
1249                 s->params.member_id_field_name = strdup(tokens[1]);
1250                 if (!s->params.member_id_field_name) {
1251                         if (err_line)
1252                                 *err_line = n_lines;
1253                         if (err_msg)
1254                                 *err_msg = "Memory allocation failed.";
1255                         return -ENOMEM;
1256                 }
1257
1258                 return 0;
1259         }
1260
1261         if (!strcmp(tokens[0], "n_groups_max")) {
1262                 char *p = tokens[1];
1263
1264                 if (n_tokens != 2) {
1265                         if (err_line)
1266                                 *err_line = n_lines;
1267                         if (err_msg)
1268                                 *err_msg = "Invalid n_groups statement.";
1269                         return -EINVAL;
1270                 }
1271
1272                 s->params.n_groups_max = strtoul(p, &p, 0);
1273                 if (p[0]) {
1274                         if (err_line)
1275                                 *err_line = n_lines;
1276                         if (err_msg)
1277                                 *err_msg = "Invalid n_groups argument.";
1278                         return -EINVAL;
1279                 }
1280
1281                 return 0;
1282         }
1283
1284         if (!strcmp(tokens[0], "n_members_per_group_max")) {
1285                 char *p = tokens[1];
1286
1287                 if (n_tokens != 2) {
1288                         if (err_line)
1289                                 *err_line = n_lines;
1290                         if (err_msg)
1291                                 *err_msg = "Invalid n_members_per_group statement.";
1292                         return -EINVAL;
1293                 }
1294
1295                 s->params.n_members_per_group_max = strtoul(p, &p, 0);
1296                 if (p[0]) {
1297                         if (err_line)
1298                                 *err_line = n_lines;
1299                         if (err_msg)
1300                                 *err_msg = "Invalid n_members_per_group argument.";
1301                         return -EINVAL;
1302                 }
1303
1304                 return 0;
1305         }
1306
1307         /* Anything else. */
1308         if (err_line)
1309                 *err_line = n_lines;
1310         if (err_msg)
1311                 *err_msg = "Invalid statement.";
1312         return -EINVAL;
1313 }
1314
1315 /*
1316  * learner.
1317  *
1318  * learner {
1319  *      key {
1320  *              MATCH_FIELD_NAME
1321  *              ...
1322  *      }
1323  *      actions {
1324  *              ACTION_NAME [ @tableonly | @defaultonly]
1325  *              ...
1326  *      }
1327  *      default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
1328  *      size SIZE
1329  *      timeout TIMEOUT_IN_SECONDS
1330  * }
1331  */
1332 struct learner_spec {
1333         char *name;
1334         struct rte_swx_pipeline_learner_params params;
1335         uint32_t size;
1336         uint32_t timeout;
1337 };
1338
1339 static void
1340 learner_spec_free(struct learner_spec *s)
1341 {
1342         uintptr_t default_action_name;
1343         uint32_t i;
1344
1345         if (!s)
1346                 return;
1347
1348         free(s->name);
1349         s->name = NULL;
1350
1351         for (i = 0; i < s->params.n_fields; i++) {
1352                 uintptr_t name = (uintptr_t)s->params.field_names[i];
1353
1354                 free((void *)name);
1355         }
1356
1357         free(s->params.field_names);
1358         s->params.field_names = NULL;
1359
1360         s->params.n_fields = 0;
1361
1362         for (i = 0; i < s->params.n_actions; i++) {
1363                 uintptr_t name = (uintptr_t)s->params.action_names[i];
1364
1365                 free((void *)name);
1366         }
1367
1368         free(s->params.action_names);
1369         s->params.action_names = NULL;
1370
1371         s->params.n_actions = 0;
1372
1373         default_action_name = (uintptr_t)s->params.default_action_name;
1374         free((void *)default_action_name);
1375         s->params.default_action_name = NULL;
1376
1377         free(s->params.default_action_data);
1378         s->params.default_action_data = NULL;
1379
1380         free(s->params.action_is_for_table_entries);
1381         s->params.action_is_for_table_entries = NULL;
1382
1383         free(s->params.action_is_for_default_entry);
1384         s->params.action_is_for_default_entry = NULL;
1385
1386         s->params.default_action_is_const = 0;
1387
1388         s->size = 0;
1389
1390         s->timeout = 0;
1391 }
1392
1393 static int
1394 learner_key_statement_parse(uint32_t *block_mask,
1395                             char **tokens,
1396                             uint32_t n_tokens,
1397                             uint32_t n_lines,
1398                             uint32_t *err_line,
1399                             const char **err_msg)
1400 {
1401         /* Check format. */
1402         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1403                 if (err_line)
1404                         *err_line = n_lines;
1405                 if (err_msg)
1406                         *err_msg = "Invalid key statement.";
1407                 return -EINVAL;
1408         }
1409
1410         /* block_mask. */
1411         *block_mask |= 1 << LEARNER_KEY_BLOCK;
1412
1413         return 0;
1414 }
1415
1416 static int
1417 learner_key_block_parse(struct learner_spec *s,
1418                         uint32_t *block_mask,
1419                         char **tokens,
1420                         uint32_t n_tokens,
1421                         uint32_t n_lines,
1422                         uint32_t *err_line,
1423                         const char **err_msg)
1424 {
1425         const char **new_field_names = NULL;
1426         char *field_name = NULL;
1427
1428         /* Handle end of block. */
1429         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1430                 *block_mask &= ~(1 << LEARNER_KEY_BLOCK);
1431                 return 0;
1432         }
1433
1434         /* Check input arguments. */
1435         if (n_tokens != 1) {
1436                 if (err_line)
1437                         *err_line = n_lines;
1438                 if (err_msg)
1439                         *err_msg = "Invalid match field statement.";
1440                 return -EINVAL;
1441         }
1442
1443         field_name = strdup(tokens[0]);
1444         new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
1445         if (!field_name || !new_field_names) {
1446                 free(field_name);
1447                 free(new_field_names);
1448
1449                 if (err_line)
1450                         *err_line = n_lines;
1451                 if (err_msg)
1452                         *err_msg = "Memory allocation failed.";
1453                 return -ENOMEM;
1454         }
1455
1456         s->params.field_names = new_field_names;
1457         s->params.field_names[s->params.n_fields] = field_name;
1458         s->params.n_fields++;
1459
1460         return 0;
1461 }
1462
1463 static int
1464 learner_actions_statement_parse(uint32_t *block_mask,
1465                                 char **tokens,
1466                                 uint32_t n_tokens,
1467                                 uint32_t n_lines,
1468                                 uint32_t *err_line,
1469                                 const char **err_msg)
1470 {
1471         /* Check format. */
1472         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1473                 if (err_line)
1474                         *err_line = n_lines;
1475                 if (err_msg)
1476                         *err_msg = "Invalid actions statement.";
1477                 return -EINVAL;
1478         }
1479
1480         /* block_mask. */
1481         *block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
1482
1483         return 0;
1484 }
1485
1486 static int
1487 learner_actions_block_parse(struct learner_spec *s,
1488                             uint32_t *block_mask,
1489                             char **tokens,
1490                             uint32_t n_tokens,
1491                             uint32_t n_lines,
1492                             uint32_t *err_line,
1493                             const char **err_msg)
1494 {
1495         const char **new_action_names = NULL;
1496         int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
1497         char *name = NULL;
1498         int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
1499
1500         /* Handle end of block. */
1501         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1502                 *block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
1503                 return 0;
1504         }
1505
1506         /* Check input arguments. */
1507         if ((n_tokens > 2) ||
1508             ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
1509               strcmp(tokens[1], "@defaultonly"))) {
1510                 if (err_line)
1511                         *err_line = n_lines;
1512                 if (err_msg)
1513                         *err_msg = "Invalid action name statement.";
1514                 return -EINVAL;
1515         }
1516
1517         name = strdup(tokens[0]);
1518
1519         if (n_tokens == 2) {
1520                 if (!strcmp(tokens[1], "@tableonly"))
1521                         action_is_for_default_entry = 0;
1522
1523                 if (!strcmp(tokens[1], "@defaultonly"))
1524                         action_is_for_table_entries = 0;
1525         }
1526
1527         new_action_names = realloc(s->params.action_names,
1528                                    (s->params.n_actions + 1) * sizeof(char *));
1529         new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
1530                                                   (s->params.n_actions + 1) * sizeof(int));
1531         new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
1532                                                   (s->params.n_actions + 1) * sizeof(int));
1533
1534         if (!name ||
1535             !new_action_names ||
1536             !new_action_is_for_table_entries ||
1537             !new_action_is_for_default_entry) {
1538                 free(name);
1539                 free(new_action_names);
1540                 free(new_action_is_for_table_entries);
1541                 free(new_action_is_for_default_entry);
1542
1543                 if (err_line)
1544                         *err_line = n_lines;
1545                 if (err_msg)
1546                         *err_msg = "Memory allocation failed.";
1547                 return -ENOMEM;
1548         }
1549
1550         s->params.action_names = new_action_names;
1551         s->params.action_names[s->params.n_actions] = name;
1552
1553         s->params.action_is_for_table_entries = new_action_is_for_table_entries;
1554         s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
1555
1556         s->params.action_is_for_default_entry = new_action_is_for_default_entry;
1557         s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
1558
1559         s->params.n_actions++;
1560
1561         return 0;
1562 }
1563
1564 static int
1565 learner_statement_parse(struct learner_spec *s,
1566                       uint32_t *block_mask,
1567                       char **tokens,
1568                       uint32_t n_tokens,
1569                       uint32_t n_lines,
1570                       uint32_t *err_line,
1571                       const char **err_msg)
1572 {
1573         /* Check format. */
1574         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1575                 if (err_line)
1576                         *err_line = n_lines;
1577                 if (err_msg)
1578                         *err_msg = "Invalid learner statement.";
1579                 return -EINVAL;
1580         }
1581
1582         /* spec. */
1583         s->name = strdup(tokens[1]);
1584         if (!s->name) {
1585                 if (err_line)
1586                         *err_line = n_lines;
1587                 if (err_msg)
1588                         *err_msg = "Memory allocation failed.";
1589                 return -ENOMEM;
1590         }
1591
1592         /* block_mask. */
1593         *block_mask |= 1 << LEARNER_BLOCK;
1594
1595         return 0;
1596 }
1597
1598 static int
1599 learner_block_parse(struct learner_spec *s,
1600                     uint32_t *block_mask,
1601                     char **tokens,
1602                     uint32_t n_tokens,
1603                     uint32_t n_lines,
1604                     uint32_t *err_line,
1605                     const char **err_msg)
1606 {
1607         if (*block_mask & (1 << LEARNER_KEY_BLOCK))
1608                 return learner_key_block_parse(s,
1609                                                block_mask,
1610                                                tokens,
1611                                                n_tokens,
1612                                                n_lines,
1613                                                err_line,
1614                                                err_msg);
1615
1616         if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
1617                 return learner_actions_block_parse(s,
1618                                                    block_mask,
1619                                                    tokens,
1620                                                    n_tokens,
1621                                                    n_lines,
1622                                                    err_line,
1623                                                    err_msg);
1624
1625         /* Handle end of block. */
1626         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1627                 *block_mask &= ~(1 << LEARNER_BLOCK);
1628                 return 0;
1629         }
1630
1631         if (!strcmp(tokens[0], "key"))
1632                 return learner_key_statement_parse(block_mask,
1633                                                    tokens,
1634                                                    n_tokens,
1635                                                    n_lines,
1636                                                    err_line,
1637                                                    err_msg);
1638
1639         if (!strcmp(tokens[0], "actions"))
1640                 return learner_actions_statement_parse(block_mask,
1641                                                        tokens,
1642                                                        n_tokens,
1643                                                        n_lines,
1644                                                        err_line,
1645                                                        err_msg);
1646
1647         if (!strcmp(tokens[0], "default_action")) {
1648                 if (((n_tokens != 4) && (n_tokens != 5)) ||
1649                     strcmp(tokens[2], "args") ||
1650                     strcmp(tokens[3], "none") ||
1651                     ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
1652                         if (err_line)
1653                                 *err_line = n_lines;
1654                         if (err_msg)
1655                                 *err_msg = "Invalid default_action statement.";
1656                         return -EINVAL;
1657                 }
1658
1659                 if (s->params.default_action_name) {
1660                         if (err_line)
1661                                 *err_line = n_lines;
1662                         if (err_msg)
1663                                 *err_msg = "Duplicate default_action stmt.";
1664                         return -EINVAL;
1665                 }
1666
1667                 s->params.default_action_name = strdup(tokens[1]);
1668                 if (!s->params.default_action_name) {
1669                         if (err_line)
1670                                 *err_line = n_lines;
1671                         if (err_msg)
1672                                 *err_msg = "Memory allocation failed.";
1673                         return -ENOMEM;
1674                 }
1675
1676                 if (n_tokens == 5)
1677                         s->params.default_action_is_const = 1;
1678
1679                 return 0;
1680         }
1681
1682         if (!strcmp(tokens[0], "size")) {
1683                 char *p = tokens[1];
1684
1685                 if (n_tokens != 2) {
1686                         if (err_line)
1687                                 *err_line = n_lines;
1688                         if (err_msg)
1689                                 *err_msg = "Invalid size statement.";
1690                         return -EINVAL;
1691                 }
1692
1693                 s->size = strtoul(p, &p, 0);
1694                 if (p[0]) {
1695                         if (err_line)
1696                                 *err_line = n_lines;
1697                         if (err_msg)
1698                                 *err_msg = "Invalid size argument.";
1699                         return -EINVAL;
1700                 }
1701
1702                 return 0;
1703         }
1704
1705         if (!strcmp(tokens[0], "timeout")) {
1706                 char *p = tokens[1];
1707
1708                 if (n_tokens != 2) {
1709                         if (err_line)
1710                                 *err_line = n_lines;
1711                         if (err_msg)
1712                                 *err_msg = "Invalid timeout statement.";
1713                         return -EINVAL;
1714                 }
1715
1716                 s->timeout = strtoul(p, &p, 0);
1717                 if (p[0]) {
1718                         if (err_line)
1719                                 *err_line = n_lines;
1720                         if (err_msg)
1721                                 *err_msg = "Invalid timeout argument.";
1722                         return -EINVAL;
1723                 }
1724
1725                 return 0;
1726         }
1727
1728         /* Anything else. */
1729         if (err_line)
1730                 *err_line = n_lines;
1731         if (err_msg)
1732                 *err_msg = "Invalid statement.";
1733         return -EINVAL;
1734 }
1735
1736 /*
1737  * regarray.
1738  *
1739  * regarray NAME size SIZE initval INITVAL
1740  */
1741 struct regarray_spec {
1742         char *name;
1743         uint64_t init_val;
1744         uint32_t size;
1745 };
1746
1747 static void
1748 regarray_spec_free(struct regarray_spec *s)
1749 {
1750         if (!s)
1751                 return;
1752
1753         free(s->name);
1754         s->name = NULL;
1755 }
1756
1757 static int
1758 regarray_statement_parse(struct regarray_spec *s,
1759                          char **tokens,
1760                          uint32_t n_tokens,
1761                          uint32_t n_lines,
1762                          uint32_t *err_line,
1763                          const char **err_msg)
1764 {
1765         char *p;
1766
1767         /* Check format. */
1768         if ((n_tokens != 6) ||
1769              strcmp(tokens[2], "size") ||
1770              strcmp(tokens[4], "initval")) {
1771                 if (err_line)
1772                         *err_line = n_lines;
1773                 if (err_msg)
1774                         *err_msg = "Invalid regarray statement.";
1775                 return -EINVAL;
1776         }
1777
1778         /* spec. */
1779         s->name = strdup(tokens[1]);
1780         if (!s->name) {
1781                 if (err_line)
1782                         *err_line = n_lines;
1783                 if (err_msg)
1784                         *err_msg = "Memory allocation failed.";
1785                 return -ENOMEM;
1786         }
1787
1788         p = tokens[3];
1789         s->size = strtoul(p, &p, 0);
1790         if (p[0] || !s->size) {
1791                 if (err_line)
1792                         *err_line = n_lines;
1793                 if (err_msg)
1794                         *err_msg = "Invalid size argument.";
1795                 return -EINVAL;
1796         }
1797
1798         p = tokens[5];
1799         s->init_val = strtoull(p, &p, 0);
1800         if (p[0]) {
1801                 if (err_line)
1802                         *err_line = n_lines;
1803                 if (err_msg)
1804                         *err_msg = "Invalid initval argument.";
1805                 return -EINVAL;
1806         }
1807
1808         return 0;
1809 }
1810
1811 /*
1812  * metarray.
1813  *
1814  * metarray NAME size SIZE
1815  */
1816 struct metarray_spec {
1817         char *name;
1818         uint32_t size;
1819 };
1820
1821 static void
1822 metarray_spec_free(struct metarray_spec *s)
1823 {
1824         if (!s)
1825                 return;
1826
1827         free(s->name);
1828         s->name = NULL;
1829 }
1830
1831 static int
1832 metarray_statement_parse(struct metarray_spec *s,
1833                          char **tokens,
1834                          uint32_t n_tokens,
1835                          uint32_t n_lines,
1836                          uint32_t *err_line,
1837                          const char **err_msg)
1838 {
1839         char *p;
1840
1841         /* Check format. */
1842         if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
1843                 if (err_line)
1844                         *err_line = n_lines;
1845                 if (err_msg)
1846                         *err_msg = "Invalid metarray statement.";
1847                 return -EINVAL;
1848         }
1849
1850         /* spec. */
1851         s->name = strdup(tokens[1]);
1852         if (!s->name) {
1853                 if (err_line)
1854                         *err_line = n_lines;
1855                 if (err_msg)
1856                         *err_msg = "Memory allocation failed.";
1857                 return -ENOMEM;
1858         }
1859
1860         p = tokens[3];
1861         s->size = strtoul(p, &p, 0);
1862         if (p[0] || !s->size) {
1863                 if (err_line)
1864                         *err_line = n_lines;
1865                 if (err_msg)
1866                         *err_msg = "Invalid size argument.";
1867                 return -EINVAL;
1868         }
1869
1870         return 0;
1871 }
1872
1873 /*
1874  * apply.
1875  *
1876  * apply {
1877  *      INSTRUCTION
1878  *      ...
1879  * }
1880  */
1881 struct apply_spec {
1882         const char **instructions;
1883         uint32_t n_instructions;
1884 };
1885
1886 static void
1887 apply_spec_free(struct apply_spec *s)
1888 {
1889         uint32_t i;
1890
1891         if (!s)
1892                 return;
1893
1894         for (i = 0; i < s->n_instructions; i++) {
1895                 uintptr_t instr = (uintptr_t)s->instructions[i];
1896
1897                 free((void *)instr);
1898         }
1899
1900         free(s->instructions);
1901         s->instructions = NULL;
1902
1903         s->n_instructions = 0;
1904 }
1905
1906 static int
1907 apply_statement_parse(uint32_t *block_mask,
1908                       char **tokens,
1909                       uint32_t n_tokens,
1910                       uint32_t n_lines,
1911                       uint32_t *err_line,
1912                       const char **err_msg)
1913 {
1914         /* Check format. */
1915         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1916                 if (err_line)
1917                         *err_line = n_lines;
1918                 if (err_msg)
1919                         *err_msg = "Invalid apply statement.";
1920                 return -EINVAL;
1921         }
1922
1923         /* block_mask. */
1924         *block_mask |= 1 << APPLY_BLOCK;
1925
1926         return 0;
1927 }
1928
1929 static int
1930 apply_block_parse(struct apply_spec *s,
1931                   uint32_t *block_mask,
1932                   char **tokens,
1933                   uint32_t n_tokens,
1934                   uint32_t n_lines,
1935                   uint32_t *err_line,
1936                   const char **err_msg)
1937 {
1938         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1939         const char **new_instructions;
1940         uint32_t i;
1941
1942         /* Handle end of block. */
1943         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1944                 *block_mask &= ~(1 << APPLY_BLOCK);
1945                 return 0;
1946         }
1947
1948         /* spec. */
1949         buffer[0] = 0;
1950         for (i = 0; i < n_tokens; i++) {
1951                 if (i)
1952                         strcat(buffer, " ");
1953                 strcat(buffer, tokens[i]);
1954         }
1955
1956         instr = strdup(buffer);
1957         if (!instr) {
1958                 if (err_line)
1959                         *err_line = n_lines;
1960                 if (err_msg)
1961                         *err_msg = "Memory allocation failed.";
1962                 return -ENOMEM;
1963         }
1964
1965         new_instructions = realloc(s->instructions,
1966                                    (s->n_instructions + 1) * sizeof(char *));
1967         if (!new_instructions) {
1968                 free(instr);
1969
1970                 if (err_line)
1971                         *err_line = n_lines;
1972                 if (err_msg)
1973                         *err_msg = "Memory allocation failed.";
1974                 return -ENOMEM;
1975         }
1976
1977         s->instructions = new_instructions;
1978         s->instructions[s->n_instructions] = instr;
1979         s->n_instructions++;
1980
1981         return 0;
1982 }
1983
1984 /*
1985  * Pipeline.
1986  */
1987 int
1988 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1989                                  FILE *spec,
1990                                  uint32_t *err_line,
1991                                  const char **err_msg)
1992 {
1993         struct extobj_spec extobj_spec = {0};
1994         struct struct_spec struct_spec = {0};
1995         struct header_spec header_spec = {0};
1996         struct metadata_spec metadata_spec = {0};
1997         struct action_spec action_spec = {0};
1998         struct table_spec table_spec = {0};
1999         struct selector_spec selector_spec = {0};
2000         struct learner_spec learner_spec = {0};
2001         struct regarray_spec regarray_spec = {0};
2002         struct metarray_spec metarray_spec = {0};
2003         struct apply_spec apply_spec = {0};
2004         uint32_t n_lines;
2005         uint32_t block_mask = 0;
2006         int status;
2007
2008         /* Check the input arguments. */
2009         if (!p) {
2010                 if (err_line)
2011                         *err_line = 0;
2012                 if (err_msg)
2013                         *err_msg = "Null pipeline argument.";
2014                 status = -EINVAL;
2015                 goto error;
2016         }
2017
2018         if (!spec) {
2019                 if (err_line)
2020                         *err_line = 0;
2021                 if (err_msg)
2022                         *err_msg = "Null specification file argument.";
2023                 status = -EINVAL;
2024                 goto error;
2025         }
2026
2027         for (n_lines = 1; ; n_lines++) {
2028                 char line[MAX_LINE_LENGTH];
2029                 char *tokens[MAX_TOKENS], *ptr = line;
2030                 uint32_t n_tokens = 0;
2031
2032                 /* Read next line. */
2033                 if (!fgets(line, sizeof(line), spec))
2034                         break;
2035
2036                 /* Parse the line into tokens. */
2037                 for ( ; ; ) {
2038                         char *token;
2039
2040                         /* Get token. */
2041                         token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
2042                         if (!token)
2043                                 break;
2044
2045                         /* Handle comments. */
2046                         if ((token[0] == '#') ||
2047                             (token[0] == ';') ||
2048                             ((token[0] == '/') && (token[1] == '/'))) {
2049                                 break;
2050                         }
2051
2052                         /* Handle excessively long lines. */
2053                         if (n_tokens >= MAX_TOKENS) {
2054                                 if (err_line)
2055                                         *err_line = n_lines;
2056                                 if (err_msg)
2057                                         *err_msg = "Too many tokens.";
2058                                 status = -EINVAL;
2059                                 goto error;
2060                         }
2061
2062                         /* Handle excessively long tokens. */
2063                         if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2064                             RTE_SWX_NAME_SIZE) {
2065                                 if (err_line)
2066                                         *err_line = n_lines;
2067                                 if (err_msg)
2068                                         *err_msg = "Token too big.";
2069                                 status = -EINVAL;
2070                                 goto error;
2071                         }
2072
2073                         /* Save token. */
2074                         tokens[n_tokens] = token;
2075                         n_tokens++;
2076                 }
2077
2078                 /* Handle empty lines. */
2079                 if (!n_tokens)
2080                         continue;
2081
2082                 /* struct block. */
2083                 if (block_mask & (1 << STRUCT_BLOCK)) {
2084                         status = struct_block_parse(&struct_spec,
2085                                                     &block_mask,
2086                                                     tokens,
2087                                                     n_tokens,
2088                                                     n_lines,
2089                                                     err_line,
2090                                                     err_msg);
2091                         if (status)
2092                                 goto error;
2093
2094                         if (block_mask & (1 << STRUCT_BLOCK))
2095                                 continue;
2096
2097                         /* End of block. */
2098                         status = rte_swx_pipeline_struct_type_register(p,
2099                                 struct_spec.name,
2100                                 struct_spec.fields,
2101                                 struct_spec.n_fields,
2102                                 struct_spec.varbit);
2103                         if (status) {
2104                                 if (err_line)
2105                                         *err_line = n_lines;
2106                                 if (err_msg)
2107                                         *err_msg = "Struct registration error.";
2108                                 goto error;
2109                         }
2110
2111                         struct_spec_free(&struct_spec);
2112
2113                         continue;
2114                 }
2115
2116                 /* action block. */
2117                 if (block_mask & (1 << ACTION_BLOCK)) {
2118                         status = action_block_parse(&action_spec,
2119                                                     &block_mask,
2120                                                     tokens,
2121                                                     n_tokens,
2122                                                     n_lines,
2123                                                     err_line,
2124                                                     err_msg);
2125                         if (status)
2126                                 goto error;
2127
2128                         if (block_mask & (1 << ACTION_BLOCK))
2129                                 continue;
2130
2131                         /* End of block. */
2132                         status = rte_swx_pipeline_action_config(p,
2133                                 action_spec.name,
2134                                 action_spec.args_struct_type_name,
2135                                 action_spec.instructions,
2136                                 action_spec.n_instructions);
2137                         if (status) {
2138                                 if (err_line)
2139                                         *err_line = n_lines;
2140                                 if (err_msg)
2141                                         *err_msg = "Action config error.";
2142                                 goto error;
2143                         }
2144
2145                         action_spec_free(&action_spec);
2146
2147                         continue;
2148                 }
2149
2150                 /* table block. */
2151                 if (block_mask & (1 << TABLE_BLOCK)) {
2152                         status = table_block_parse(&table_spec,
2153                                                    &block_mask,
2154                                                    tokens,
2155                                                    n_tokens,
2156                                                    n_lines,
2157                                                    err_line,
2158                                                    err_msg);
2159                         if (status)
2160                                 goto error;
2161
2162                         if (block_mask & (1 << TABLE_BLOCK))
2163                                 continue;
2164
2165                         /* End of block. */
2166                         status = rte_swx_pipeline_table_config(p,
2167                                 table_spec.name,
2168                                 &table_spec.params,
2169                                 table_spec.recommended_table_type_name,
2170                                 table_spec.args,
2171                                 table_spec.size);
2172                         if (status) {
2173                                 if (err_line)
2174                                         *err_line = n_lines;
2175                                 if (err_msg)
2176                                         *err_msg = "Table configuration error.";
2177                                 goto error;
2178                         }
2179
2180                         table_spec_free(&table_spec);
2181
2182                         continue;
2183                 }
2184
2185                 /* selector block. */
2186                 if (block_mask & (1 << SELECTOR_BLOCK)) {
2187                         status = selector_block_parse(&selector_spec,
2188                                                       &block_mask,
2189                                                       tokens,
2190                                                       n_tokens,
2191                                                       n_lines,
2192                                                       err_line,
2193                                                       err_msg);
2194                         if (status)
2195                                 goto error;
2196
2197                         if (block_mask & (1 << SELECTOR_BLOCK))
2198                                 continue;
2199
2200                         /* End of block. */
2201                         status = rte_swx_pipeline_selector_config(p,
2202                                 selector_spec.name,
2203                                 &selector_spec.params);
2204                         if (status) {
2205                                 if (err_line)
2206                                         *err_line = n_lines;
2207                                 if (err_msg)
2208                                         *err_msg = "Selector configuration error.";
2209                                 goto error;
2210                         }
2211
2212                         selector_spec_free(&selector_spec);
2213
2214                         continue;
2215                 }
2216
2217                 /* learner block. */
2218                 if (block_mask & (1 << LEARNER_BLOCK)) {
2219                         status = learner_block_parse(&learner_spec,
2220                                                      &block_mask,
2221                                                      tokens,
2222                                                      n_tokens,
2223                                                      n_lines,
2224                                                      err_line,
2225                                                      err_msg);
2226                         if (status)
2227                                 goto error;
2228
2229                         if (block_mask & (1 << LEARNER_BLOCK))
2230                                 continue;
2231
2232                         /* End of block. */
2233                         status = rte_swx_pipeline_learner_config(p,
2234                                 learner_spec.name,
2235                                 &learner_spec.params,
2236                                 learner_spec.size,
2237                                 learner_spec.timeout);
2238                         if (status) {
2239                                 if (err_line)
2240                                         *err_line = n_lines;
2241                                 if (err_msg)
2242                                         *err_msg = "Learner table configuration error.";
2243                                 goto error;
2244                         }
2245
2246                         learner_spec_free(&learner_spec);
2247
2248                         continue;
2249                 }
2250
2251                 /* apply block. */
2252                 if (block_mask & (1 << APPLY_BLOCK)) {
2253                         status = apply_block_parse(&apply_spec,
2254                                                    &block_mask,
2255                                                    tokens,
2256                                                    n_tokens,
2257                                                    n_lines,
2258                                                    err_line,
2259                                                    err_msg);
2260                         if (status)
2261                                 goto error;
2262
2263                         if (block_mask & (1 << APPLY_BLOCK))
2264                                 continue;
2265
2266                         /* End of block. */
2267                         status = rte_swx_pipeline_instructions_config(p,
2268                                 apply_spec.instructions,
2269                                 apply_spec.n_instructions);
2270                         if (status) {
2271                                 if (err_line)
2272                                         *err_line = n_lines;
2273                                 if (err_msg)
2274                                         *err_msg = "Pipeline instructions err.";
2275                                 goto error;
2276                         }
2277
2278                         apply_spec_free(&apply_spec);
2279
2280                         continue;
2281                 }
2282
2283                 /* extobj. */
2284                 if (!strcmp(tokens[0], "extobj")) {
2285                         status = extobj_statement_parse(&extobj_spec,
2286                                                         tokens,
2287                                                         n_tokens,
2288                                                         n_lines,
2289                                                         err_line,
2290                                                         err_msg);
2291                         if (status)
2292                                 goto error;
2293
2294                         status = rte_swx_pipeline_extern_object_config(p,
2295                                 extobj_spec.name,
2296                                 extobj_spec.extern_type_name,
2297                                 extobj_spec.pragma);
2298                         if (status) {
2299                                 if (err_line)
2300                                         *err_line = n_lines;
2301                                 if (err_msg)
2302                                         *err_msg = "Extern object config err.";
2303                                 goto error;
2304                         }
2305
2306                         extobj_spec_free(&extobj_spec);
2307
2308                         continue;
2309                 }
2310
2311                 /* struct. */
2312                 if (!strcmp(tokens[0], "struct")) {
2313                         status = struct_statement_parse(&struct_spec,
2314                                                         &block_mask,
2315                                                         tokens,
2316                                                         n_tokens,
2317                                                         n_lines,
2318                                                         err_line,
2319                                                         err_msg);
2320                         if (status)
2321                                 goto error;
2322
2323                         continue;
2324                 }
2325
2326                 /* header. */
2327                 if (!strcmp(tokens[0], "header")) {
2328                         status = header_statement_parse(&header_spec,
2329                                                         tokens,
2330                                                         n_tokens,
2331                                                         n_lines,
2332                                                         err_line,
2333                                                         err_msg);
2334                         if (status)
2335                                 goto error;
2336
2337                         status = rte_swx_pipeline_packet_header_register(p,
2338                                 header_spec.name,
2339                                 header_spec.struct_type_name);
2340                         if (status) {
2341                                 if (err_line)
2342                                         *err_line = n_lines;
2343                                 if (err_msg)
2344                                         *err_msg = "Header registration error.";
2345                                 goto error;
2346                         }
2347
2348                         header_spec_free(&header_spec);
2349
2350                         continue;
2351                 }
2352
2353                 /* metadata. */
2354                 if (!strcmp(tokens[0], "metadata")) {
2355                         status = metadata_statement_parse(&metadata_spec,
2356                                                           tokens,
2357                                                           n_tokens,
2358                                                           n_lines,
2359                                                           err_line,
2360                                                           err_msg);
2361                         if (status)
2362                                 goto error;
2363
2364                         status = rte_swx_pipeline_packet_metadata_register(p,
2365                                 metadata_spec.struct_type_name);
2366                         if (status) {
2367                                 if (err_line)
2368                                         *err_line = n_lines;
2369                                 if (err_msg)
2370                                         *err_msg = "Meta-data reg err.";
2371                                 goto error;
2372                         }
2373
2374                         metadata_spec_free(&metadata_spec);
2375
2376                         continue;
2377                 }
2378
2379                 /* action. */
2380                 if (!strcmp(tokens[0], "action")) {
2381                         status = action_statement_parse(&action_spec,
2382                                                         &block_mask,
2383                                                         tokens,
2384                                                         n_tokens,
2385                                                         n_lines,
2386                                                         err_line,
2387                                                         err_msg);
2388                         if (status)
2389                                 goto error;
2390
2391                         continue;
2392                 }
2393
2394                 /* table. */
2395                 if (!strcmp(tokens[0], "table")) {
2396                         status = table_statement_parse(&table_spec,
2397                                                        &block_mask,
2398                                                        tokens,
2399                                                        n_tokens,
2400                                                        n_lines,
2401                                                        err_line,
2402                                                        err_msg);
2403                         if (status)
2404                                 goto error;
2405
2406                         continue;
2407                 }
2408
2409                 /* selector. */
2410                 if (!strcmp(tokens[0], "selector")) {
2411                         status = selector_statement_parse(&selector_spec,
2412                                                           &block_mask,
2413                                                           tokens,
2414                                                           n_tokens,
2415                                                           n_lines,
2416                                                           err_line,
2417                                                           err_msg);
2418                         if (status)
2419                                 goto error;
2420
2421                         continue;
2422                 }
2423
2424                 /* learner. */
2425                 if (!strcmp(tokens[0], "learner")) {
2426                         status = learner_statement_parse(&learner_spec,
2427                                                          &block_mask,
2428                                                          tokens,
2429                                                          n_tokens,
2430                                                          n_lines,
2431                                                          err_line,
2432                                                          err_msg);
2433                         if (status)
2434                                 goto error;
2435
2436                         continue;
2437                 }
2438
2439                 /* regarray. */
2440                 if (!strcmp(tokens[0], "regarray")) {
2441                         status = regarray_statement_parse(&regarray_spec,
2442                                                           tokens,
2443                                                           n_tokens,
2444                                                           n_lines,
2445                                                           err_line,
2446                                                           err_msg);
2447                         if (status)
2448                                 goto error;
2449
2450                         status = rte_swx_pipeline_regarray_config(p,
2451                                 regarray_spec.name,
2452                                 regarray_spec.size,
2453                                 regarray_spec.init_val);
2454                         if (status) {
2455                                 if (err_line)
2456                                         *err_line = n_lines;
2457                                 if (err_msg)
2458                                         *err_msg = "Register array configuration error.";
2459                                 goto error;
2460                         }
2461
2462                         regarray_spec_free(&regarray_spec);
2463
2464                         continue;
2465                 }
2466
2467                 /* metarray. */
2468                 if (!strcmp(tokens[0], "metarray")) {
2469                         status = metarray_statement_parse(&metarray_spec,
2470                                                           tokens,
2471                                                           n_tokens,
2472                                                           n_lines,
2473                                                           err_line,
2474                                                           err_msg);
2475                         if (status)
2476                                 goto error;
2477
2478                         status = rte_swx_pipeline_metarray_config(p,
2479                                 metarray_spec.name,
2480                                 metarray_spec.size);
2481                         if (status) {
2482                                 if (err_line)
2483                                         *err_line = n_lines;
2484                                 if (err_msg)
2485                                         *err_msg = "Meter array configuration error.";
2486                                 goto error;
2487                         }
2488
2489                         metarray_spec_free(&metarray_spec);
2490
2491                         continue;
2492                 }
2493
2494                 /* apply. */
2495                 if (!strcmp(tokens[0], "apply")) {
2496                         status = apply_statement_parse(&block_mask,
2497                                                        tokens,
2498                                                        n_tokens,
2499                                                        n_lines,
2500                                                        err_line,
2501                                                        err_msg);
2502                         if (status)
2503                                 goto error;
2504
2505                         continue;
2506                 }
2507
2508                 /* Anything else. */
2509                 if (err_line)
2510                         *err_line = n_lines;
2511                 if (err_msg)
2512                         *err_msg = "Unknown statement.";
2513                 status = -EINVAL;
2514                 goto error;
2515         }
2516
2517         /* Handle unfinished block. */
2518         if (block_mask) {
2519                 if (err_line)
2520                         *err_line = n_lines;
2521                 if (err_msg)
2522                         *err_msg = "Missing }.";
2523                 status = -EINVAL;
2524                 goto error;
2525         }
2526
2527         /* Pipeline build. */
2528         status = rte_swx_pipeline_build(p);
2529         if (status) {
2530                 if (err_line)
2531                         *err_line = n_lines;
2532                 if (err_msg)
2533                         *err_msg = "Pipeline build error.";
2534                 goto error;
2535         }
2536
2537         return 0;
2538
2539 error:
2540         extobj_spec_free(&extobj_spec);
2541         struct_spec_free(&struct_spec);
2542         header_spec_free(&header_spec);
2543         metadata_spec_free(&metadata_spec);
2544         action_spec_free(&action_spec);
2545         table_spec_free(&table_spec);
2546         selector_spec_free(&selector_spec);
2547         learner_spec_free(&learner_spec);
2548         regarray_spec_free(&regarray_spec);
2549         metarray_spec_free(&metarray_spec);
2550         apply_spec_free(&apply_spec);
2551         return status;
2552 }