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