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