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