common/sfc_efx/base: add event queue module for Riverhead
[dpdk.git] / lib / librte_pipeline / rte_swx_pipeline_spec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
9
10 #include "rte_swx_pipeline.h"
11 #include "rte_swx_ctl.h"
12
13 #define MAX_LINE_LENGTH 256
14 #define MAX_TOKENS 16
15 #define MAX_INSTRUCTION_LENGTH 256
16
17 #define STRUCT_BLOCK 0
18 #define ACTION_BLOCK 1
19 #define TABLE_BLOCK 2
20 #define TABLE_KEY_BLOCK 3
21 #define TABLE_ACTIONS_BLOCK 4
22 #define APPLY_BLOCK 5
23
24 /*
25  * extobj.
26  *
27  * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
28  */
29 struct extobj_spec {
30         char *name;
31         char *extern_type_name;
32         char *pragma;
33 };
34
35 static void
36 extobj_spec_free(struct extobj_spec *s)
37 {
38         free(s->name);
39         free(s->extern_type_name);
40         free(s->pragma);
41 }
42
43 static int
44 extobj_statement_parse(struct extobj_spec *s,
45                        char **tokens,
46                        uint32_t n_tokens,
47                        uint32_t n_lines,
48                        uint32_t *err_line,
49                        const char **err_msg)
50 {
51         /* Check format. */
52         if (((n_tokens != 4) && (n_tokens != 6)) ||
53             ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
54             ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
55                                  strcmp(tokens[4], "pragma")))) {
56                 if (err_line)
57                         *err_line = n_lines;
58                 if (err_msg)
59                         *err_msg = "Invalid extobj statement.";
60                 return -EINVAL;
61         }
62
63         /* spec. */
64         s->name = strdup(tokens[1]);
65         s->extern_type_name = strdup(tokens[3]);
66         s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
67
68         if (!s->name ||
69             !s->extern_type_name ||
70             ((n_tokens == 6) && !s->pragma)) {
71                 free(s->name);
72                 free(s->extern_type_name);
73                 free(s->pragma);
74
75                 if (err_line)
76                         *err_line = n_lines;
77                 if (err_msg)
78                         *err_msg = "Memory allocation failed.";
79                 return -ENOMEM;
80         }
81
82         return 0;
83 }
84
85 /*
86  * struct.
87  *
88  * struct STRUCT_TYPE_NAME {
89  *      bit<SIZE> FIELD_NAME
90  *      ...
91  * }
92  */
93 struct struct_spec {
94         char *name;
95         struct rte_swx_field_params *fields;
96         uint32_t n_fields;
97 };
98
99 static void
100 struct_spec_free(struct struct_spec *s)
101 {
102         uint32_t i;
103
104         if (!s)
105                 return;
106
107         free(s->name);
108         s->name = NULL;
109
110         for (i = 0; i < s->n_fields; i++) {
111                 uintptr_t name = (uintptr_t)s->fields[i].name;
112
113                 free((void *)name);
114         }
115
116         free(s->fields);
117         s->fields = NULL;
118
119         s->n_fields = 0;
120 }
121
122 static int
123 struct_statement_parse(struct struct_spec *s,
124                        uint32_t *block_mask,
125                        char **tokens,
126                        uint32_t n_tokens,
127                        uint32_t n_lines,
128                        uint32_t *err_line,
129                        const char **err_msg)
130 {
131         /* Check format. */
132         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
133                 if (err_line)
134                         *err_line = n_lines;
135                 if (err_msg)
136                         *err_msg = "Invalid struct statement.";
137                 return -EINVAL;
138         }
139
140         /* spec. */
141         s->name = strdup(tokens[1]);
142         if (!s->name) {
143                 if (err_line)
144                         *err_line = n_lines;
145                 if (err_msg)
146                         *err_msg = "Memory allocation failed.";
147                 return -ENOMEM;
148         }
149
150         /* block_mask. */
151         *block_mask |= 1 << STRUCT_BLOCK;
152
153         return 0;
154 }
155
156 static int
157 struct_block_parse(struct struct_spec *s,
158                    uint32_t *block_mask,
159                    char **tokens,
160                    uint32_t n_tokens,
161                    uint32_t n_lines,
162                    uint32_t *err_line,
163                    const char **err_msg)
164 {
165         struct rte_swx_field_params *new_fields;
166         char *p = tokens[0], *name;
167         uint32_t n_bits;
168
169         /* Handle end of block. */
170         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
171                 *block_mask &= ~(1 << STRUCT_BLOCK);
172                 return 0;
173         }
174
175         /* Check format. */
176         if ((n_tokens != 2) ||
177             (strlen(p) < 6) ||
178             (p[0] != 'b') ||
179             (p[1] != 'i') ||
180             (p[2] != 't') ||
181             (p[3] != '<') ||
182             (p[strlen(p) - 1] != '>')) {
183                 if (err_line)
184                         *err_line = n_lines;
185                 if (err_msg)
186                         *err_msg = "Invalid struct field statement.";
187                 return -EINVAL;
188         }
189
190         /* Remove the "bit<" and ">". */
191         p[strlen(p) - 1] = 0;
192         p += 4;
193
194         n_bits = strtoul(p, &p, 0);
195         if ((p[0]) ||
196             !n_bits ||
197             (n_bits % 8) ||
198             (n_bits > 64)) {
199                 if (err_line)
200                         *err_line = n_lines;
201                 if (err_msg)
202                         *err_msg = "Invalid struct field size.";
203                 return -EINVAL;
204         }
205
206         /* spec. */
207         name = strdup(tokens[1]);
208         if (!name) {
209                 if (err_line)
210                         *err_line = n_lines;
211                 if (err_msg)
212                         *err_msg = "Memory allocation failed.";
213                 return -ENOMEM;
214         }
215
216         new_fields = reallocarray(s->fields,
217                                   s->n_fields + 1,
218                                   sizeof(struct rte_swx_field_params));
219         if (!new_fields) {
220                 free(name);
221
222                 if (err_line)
223                         *err_line = n_lines;
224                 if (err_msg)
225                         *err_msg = "Memory allocation failed.";
226                 return -ENOMEM;
227         }
228
229         s->fields = new_fields;
230         s->fields[s->n_fields].name = name;
231         s->fields[s->n_fields].n_bits = n_bits;
232         s->n_fields++;
233
234         return 0;
235 }
236
237 /*
238  * header.
239  *
240  * header HEADER_NAME instanceof STRUCT_TYPE_NAME
241  */
242 struct header_spec {
243         char *name;
244         char *struct_type_name;
245 };
246
247 static void
248 header_spec_free(struct header_spec *s)
249 {
250         free(s->name);
251         free(s->struct_type_name);
252 }
253
254 static int
255 header_statement_parse(struct header_spec *s,
256                        char **tokens,
257                        uint32_t n_tokens,
258                        uint32_t n_lines,
259                        uint32_t *err_line,
260                        const char **err_msg)
261 {
262         /* Check format. */
263         if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
264                 if (err_line)
265                         *err_line = n_lines;
266                 if (err_msg)
267                         *err_msg = "Invalid header statement.";
268                 return -EINVAL;
269         }
270
271         /* spec. */
272         s->name = strdup(tokens[1]);
273         s->struct_type_name = strdup(tokens[3]);
274
275         if (!s->name || !s->struct_type_name) {
276                 free(s->name);
277                 free(s->struct_type_name);
278
279                 if (err_line)
280                         *err_line = n_lines;
281                 if (err_msg)
282                         *err_msg = "Memory allocation failed.";
283                 return -ENOMEM;
284         }
285
286         return 0;
287 }
288
289 /*
290  * metadata.
291  *
292  * metadata instanceof STRUCT_TYPE_NAME
293  */
294 struct metadata_spec {
295         char *struct_type_name;
296 };
297
298 static void
299 metadata_spec_free(struct metadata_spec *s)
300 {
301         free(s->struct_type_name);
302 }
303
304 static int
305 metadata_statement_parse(struct metadata_spec *s,
306                          char **tokens,
307                          uint32_t n_tokens,
308                          uint32_t n_lines,
309                          uint32_t *err_line,
310                          const char **err_msg)
311 {
312         /* Check format. */
313         if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
314                 if (err_line)
315                         *err_line = n_lines;
316                 if (err_msg)
317                         *err_msg = "Invalid metadata statement.";
318                 return -EINVAL;
319         }
320
321         /* spec. */
322         s->struct_type_name = strdup(tokens[2]);
323         if (!s->struct_type_name) {
324                 if (err_line)
325                         *err_line = n_lines;
326                 if (err_msg)
327                         *err_msg = "Memory allocation failed.";
328                 return -ENOMEM;
329         }
330
331         return 0;
332 }
333
334 /*
335  * action.
336  *
337  * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
338  *      INSTRUCTION
339  *      ...
340  * }
341  */
342 struct action_spec {
343         char *name;
344         char *args_struct_type_name;
345         const char **instructions;
346         uint32_t n_instructions;
347 };
348
349 static void
350 action_spec_free(struct action_spec *s)
351 {
352         uint32_t i;
353
354         if (!s)
355                 return;
356
357         free(s->name);
358         s->name = NULL;
359
360         free(s->args_struct_type_name);
361         s->args_struct_type_name = NULL;
362
363         for (i = 0; i < s->n_instructions; i++) {
364                 uintptr_t instr = (uintptr_t)s->instructions[i];
365
366                 free((void *)instr);
367         }
368
369         free(s->instructions);
370         s->instructions = NULL;
371
372         s->n_instructions = 0;
373 }
374
375 static int
376 action_statement_parse(struct action_spec *s,
377                        uint32_t *block_mask,
378                        char **tokens,
379                        uint32_t n_tokens,
380                        uint32_t n_lines,
381                        uint32_t *err_line,
382                        const char **err_msg)
383 {
384         /* Check format. */
385         if (((n_tokens != 5) && (n_tokens != 6)) ||
386             ((n_tokens == 5) &&
387              (strcmp(tokens[2], "args") ||
388               strcmp(tokens[3], "none") ||
389               strcmp(tokens[4], "{"))) ||
390             ((n_tokens == 6) &&
391              (strcmp(tokens[2], "args") ||
392               strcmp(tokens[3], "instanceof") ||
393               strcmp(tokens[5], "{")))) {
394                 if (err_line)
395                         *err_line = n_lines;
396                 if (err_msg)
397                         *err_msg = "Invalid action statement.";
398                 return -EINVAL;
399         }
400
401         /* spec. */
402         s->name = strdup(tokens[1]);
403         s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
404
405         if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
406                 if (err_line)
407                         *err_line = n_lines;
408                 if (err_msg)
409                         *err_msg = "Memory allocation failed.";
410                 return -ENOMEM;
411         }
412
413         /* block_mask. */
414         *block_mask |= 1 << ACTION_BLOCK;
415
416         return 0;
417 }
418
419 static int
420 action_block_parse(struct action_spec *s,
421                    uint32_t *block_mask,
422                    char **tokens,
423                    uint32_t n_tokens,
424                    uint32_t n_lines,
425                    uint32_t *err_line,
426                    const char **err_msg)
427 {
428         char buffer[MAX_INSTRUCTION_LENGTH], *instr;
429         const char **new_instructions;
430         uint32_t i;
431
432         /* Handle end of block. */
433         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
434                 *block_mask &= ~(1 << ACTION_BLOCK);
435                 return 0;
436         }
437
438         /* spec. */
439         buffer[0] = 0;
440         for (i = 0; i < n_tokens; i++) {
441                 if (i)
442                         strcat(buffer, " ");
443                 strcat(buffer, tokens[i]);
444         }
445
446         instr = strdup(buffer);
447         if (!instr) {
448                 if (err_line)
449                         *err_line = n_lines;
450                 if (err_msg)
451                         *err_msg = "Memory allocation failed.";
452                 return -ENOMEM;
453         }
454
455         new_instructions = reallocarray(s->instructions,
456                                         s->n_instructions + 1,
457                                         sizeof(char *));
458         if (!new_instructions) {
459                 free(instr);
460
461                 if (err_line)
462                         *err_line = n_lines;
463                 if (err_msg)
464                         *err_msg = "Memory allocation failed.";
465                 return -ENOMEM;
466         }
467
468         s->instructions = new_instructions;
469         s->instructions[s->n_instructions] = instr;
470         s->n_instructions++;
471
472         return 0;
473 }
474
475 /*
476  * table.
477  *
478  * table {
479  *      key {
480  *              MATCH_FIELD_NAME exact | wildcard | lpm
481  *              ...
482  *      }
483  *      actions {
484  *              ACTION_NAME
485  *              ...
486  *      }
487  *      default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
488  *      instanceof TABLE_TYPE_NAME
489  *      pragma ARGS
490  *      size SIZE
491  * }
492  */
493 struct table_spec {
494         char *name;
495         struct rte_swx_pipeline_table_params params;
496         char *recommended_table_type_name;
497         char *args;
498         uint32_t size;
499 };
500
501 static void
502 table_spec_free(struct table_spec *s)
503 {
504         uintptr_t default_action_name;
505         uint32_t i;
506
507         if (!s)
508                 return;
509
510         free(s->name);
511         s->name = NULL;
512
513         for (i = 0; i < s->params.n_fields; i++) {
514                 uintptr_t name = (uintptr_t)s->params.fields[i].name;
515
516                 free((void *)name);
517         }
518
519         free(s->params.fields);
520         s->params.fields = NULL;
521
522         s->params.n_fields = 0;
523
524         for (i = 0; i < s->params.n_actions; i++) {
525                 uintptr_t name = (uintptr_t)s->params.action_names[i];
526
527                 free((void *)name);
528         }
529
530         free(s->params.action_names);
531         s->params.action_names = NULL;
532
533         s->params.n_actions = 0;
534
535         default_action_name = (uintptr_t)s->params.default_action_name;
536         free((void *)default_action_name);
537         s->params.default_action_name = NULL;
538
539         free(s->params.default_action_data);
540         s->params.default_action_data = NULL;
541
542         s->params.default_action_is_const = 0;
543
544         free(s->recommended_table_type_name);
545         s->recommended_table_type_name = NULL;
546
547         free(s->args);
548         s->args = NULL;
549
550         s->size = 0;
551 }
552
553 static int
554 table_key_statement_parse(uint32_t *block_mask,
555                           char **tokens,
556                           uint32_t n_tokens,
557                           uint32_t n_lines,
558                           uint32_t *err_line,
559                           const char **err_msg)
560 {
561         /* Check format. */
562         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
563                 if (err_line)
564                         *err_line = n_lines;
565                 if (err_msg)
566                         *err_msg = "Invalid key statement.";
567                 return -EINVAL;
568         }
569
570         /* block_mask. */
571         *block_mask |= 1 << TABLE_KEY_BLOCK;
572
573         return 0;
574 }
575
576 static int
577 table_key_block_parse(struct table_spec *s,
578                       uint32_t *block_mask,
579                       char **tokens,
580                       uint32_t n_tokens,
581                       uint32_t n_lines,
582                       uint32_t *err_line,
583                       const char **err_msg)
584 {
585         struct rte_swx_match_field_params *new_fields;
586         enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
587         char *name;
588
589         /* Handle end of block. */
590         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
591                 *block_mask &= ~(1 << TABLE_KEY_BLOCK);
592                 return 0;
593         }
594
595         /* Check input arguments. */
596         if ((n_tokens != 2) ||
597             (strcmp(tokens[1], "exact") &&
598              strcmp(tokens[1], "wildcard") &&
599              strcmp(tokens[1], "lpm"))) {
600                 if (err_line)
601                         *err_line = n_lines;
602                 if (err_msg)
603                         *err_msg = "Invalid match field statement.";
604                 return -EINVAL;
605         }
606
607         if (!strcmp(tokens[1], "wildcard"))
608                 match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
609         if (!strcmp(tokens[1], "lpm"))
610                 match_type = RTE_SWX_TABLE_MATCH_LPM;
611         if (!strcmp(tokens[1], "exact"))
612                 match_type = RTE_SWX_TABLE_MATCH_EXACT;
613
614         name = strdup(tokens[0]);
615         if (!name) {
616                 if (err_line)
617                         *err_line = n_lines;
618                 if (err_msg)
619                         *err_msg = "Memory allocation failed.";
620                 return -ENOMEM;
621         }
622
623         new_fields = reallocarray(s->params.fields,
624                                   s->params.n_fields + 1,
625                                   sizeof(struct rte_swx_match_field_params));
626         if (!new_fields) {
627                 free(name);
628
629                 if (err_line)
630                         *err_line = n_lines;
631                 if (err_msg)
632                         *err_msg = "Memory allocation failed.";
633                 return -ENOMEM;
634         }
635
636         s->params.fields = new_fields;
637         s->params.fields[s->params.n_fields].name = name;
638         s->params.fields[s->params.n_fields].match_type = match_type;
639         s->params.n_fields++;
640
641         return 0;
642 }
643
644 static int
645 table_actions_statement_parse(uint32_t *block_mask,
646                               char **tokens,
647                               uint32_t n_tokens,
648                               uint32_t n_lines,
649                               uint32_t *err_line,
650                               const char **err_msg)
651 {
652         /* Check format. */
653         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
654                 if (err_line)
655                         *err_line = n_lines;
656                 if (err_msg)
657                         *err_msg = "Invalid actions statement.";
658                 return -EINVAL;
659         }
660
661         /* block_mask. */
662         *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
663
664         return 0;
665 }
666
667 static int
668 table_actions_block_parse(struct table_spec *s,
669                           uint32_t *block_mask,
670                           char **tokens,
671                           uint32_t n_tokens,
672                           uint32_t n_lines,
673                           uint32_t *err_line,
674                           const char **err_msg)
675 {
676         const char **new_action_names;
677         char *name;
678
679         /* Handle end of block. */
680         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
681                 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
682                 return 0;
683         }
684
685         /* Check input arguments. */
686         if (n_tokens != 1) {
687                 if (err_line)
688                         *err_line = n_lines;
689                 if (err_msg)
690                         *err_msg = "Invalid action name statement.";
691                 return -EINVAL;
692         }
693
694         name = strdup(tokens[0]);
695         if (!name) {
696                 if (err_line)
697                         *err_line = n_lines;
698                 if (err_msg)
699                         *err_msg = "Memory allocation failed.";
700                 return -ENOMEM;
701         }
702
703         new_action_names = reallocarray(s->params.action_names,
704                                         s->params.n_actions + 1,
705                                         sizeof(char *));
706         if (!new_action_names) {
707                 free(name);
708
709                 if (err_line)
710                         *err_line = n_lines;
711                 if (err_msg)
712                         *err_msg = "Memory allocation failed.";
713                 return -ENOMEM;
714         }
715
716         s->params.action_names = new_action_names;
717         s->params.action_names[s->params.n_actions] = name;
718         s->params.n_actions++;
719
720         return 0;
721 }
722
723 static int
724 table_statement_parse(struct table_spec *s,
725                       uint32_t *block_mask,
726                       char **tokens,
727                       uint32_t n_tokens,
728                       uint32_t n_lines,
729                       uint32_t *err_line,
730                       const char **err_msg)
731 {
732         /* Check format. */
733         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
734                 if (err_line)
735                         *err_line = n_lines;
736                 if (err_msg)
737                         *err_msg = "Invalid table statement.";
738                 return -EINVAL;
739         }
740
741         /* spec. */
742         s->name = strdup(tokens[1]);
743         if (!s->name) {
744                 if (err_line)
745                         *err_line = n_lines;
746                 if (err_msg)
747                         *err_msg = "Memory allocation failed.";
748                 return -ENOMEM;
749         }
750
751         /* block_mask. */
752         *block_mask |= 1 << TABLE_BLOCK;
753
754         return 0;
755 }
756
757 static int
758 table_block_parse(struct table_spec *s,
759                   uint32_t *block_mask,
760                   char **tokens,
761                   uint32_t n_tokens,
762                   uint32_t n_lines,
763                   uint32_t *err_line,
764                   const char **err_msg)
765 {
766         if (*block_mask & (1 << TABLE_KEY_BLOCK))
767                 return table_key_block_parse(s,
768                                              block_mask,
769                                              tokens,
770                                              n_tokens,
771                                              n_lines,
772                                              err_line,
773                                              err_msg);
774
775         if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
776                 return table_actions_block_parse(s,
777                                                  block_mask,
778                                                  tokens,
779                                                  n_tokens,
780                                                  n_lines,
781                                                  err_line,
782                                                  err_msg);
783
784         /* Handle end of block. */
785         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
786                 *block_mask &= ~(1 << TABLE_BLOCK);
787                 return 0;
788         }
789
790         if (!strcmp(tokens[0], "key"))
791                 return table_key_statement_parse(block_mask,
792                                                  tokens,
793                                                  n_tokens,
794                                                  n_lines,
795                                                  err_line,
796                                                  err_msg);
797
798         if (!strcmp(tokens[0], "actions"))
799                 return table_actions_statement_parse(block_mask,
800                                                      tokens,
801                                                      n_tokens,
802                                                      n_lines,
803                                                      err_line,
804                                                      err_msg);
805
806         if (!strcmp(tokens[0], "default_action")) {
807                 if (((n_tokens != 4) && (n_tokens != 5)) ||
808                     strcmp(tokens[2], "args") ||
809                     strcmp(tokens[3], "none") ||
810                     ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
811                         if (err_line)
812                                 *err_line = n_lines;
813                         if (err_msg)
814                                 *err_msg = "Invalid default_action statement.";
815                         return -EINVAL;
816                 }
817
818                 if (s->params.default_action_name) {
819                         if (err_line)
820                                 *err_line = n_lines;
821                         if (err_msg)
822                                 *err_msg = "Duplicate default_action stmt.";
823                         return -EINVAL;
824                 }
825
826                 s->params.default_action_name = strdup(tokens[1]);
827                 if (!s->params.default_action_name) {
828                         if (err_line)
829                                 *err_line = n_lines;
830                         if (err_msg)
831                                 *err_msg = "Memory allocation failed.";
832                         return -ENOMEM;
833                 }
834
835                 if (n_tokens == 5)
836                         s->params.default_action_is_const = 1;
837
838                 return 0;
839         }
840
841         if (!strcmp(tokens[0], "instanceof")) {
842                 if (n_tokens != 2) {
843                         if (err_line)
844                                 *err_line = n_lines;
845                         if (err_msg)
846                                 *err_msg = "Invalid instanceof statement.";
847                         return -EINVAL;
848                 }
849
850                 if (s->recommended_table_type_name) {
851                         if (err_line)
852                                 *err_line = n_lines;
853                         if (err_msg)
854                                 *err_msg = "Duplicate instanceof statement.";
855                         return -EINVAL;
856                 }
857
858                 s->recommended_table_type_name = strdup(tokens[1]);
859                 if (!s->recommended_table_type_name) {
860                         if (err_line)
861                                 *err_line = n_lines;
862                         if (err_msg)
863                                 *err_msg = "Memory allocation failed.";
864                         return -ENOMEM;
865                 }
866
867                 return 0;
868         }
869
870         if (!strcmp(tokens[0], "pragma")) {
871                 if (n_tokens != 2) {
872                         if (err_line)
873                                 *err_line = n_lines;
874                         if (err_msg)
875                                 *err_msg = "Invalid pragma statement.";
876                         return -EINVAL;
877                 }
878
879                 if (s->args) {
880                         if (err_line)
881                                 *err_line = n_lines;
882                         if (err_msg)
883                                 *err_msg = "Duplicate pragma statement.";
884                         return -EINVAL;
885                 }
886
887                 s->args = strdup(tokens[1]);
888                 if (!s->args) {
889                         if (err_line)
890                                 *err_line = n_lines;
891                         if (err_msg)
892                                 *err_msg = "Memory allocation failed.";
893                         return -ENOMEM;
894                 }
895
896                 return 0;
897         }
898
899         if (!strcmp(tokens[0], "size")) {
900                 char *p = tokens[1];
901
902                 if (n_tokens != 2) {
903                         if (err_line)
904                                 *err_line = n_lines;
905                         if (err_msg)
906                                 *err_msg = "Invalid pragma statement.";
907                         return -EINVAL;
908                 }
909
910                 s->size = strtoul(p, &p, 0);
911                 if (p[0]) {
912                         if (err_line)
913                                 *err_line = n_lines;
914                         if (err_msg)
915                                 *err_msg = "Invalid size argument.";
916                         return -EINVAL;
917                 }
918
919                 return 0;
920         }
921
922         /* Anything else. */
923         if (err_line)
924                 *err_line = n_lines;
925         if (err_msg)
926                 *err_msg = "Invalid statement.";
927         return -EINVAL;
928 }
929
930 /*
931  * apply.
932  *
933  * apply {
934  *      INSTRUCTION
935  *      ...
936  * }
937  */
938 struct apply_spec {
939         const char **instructions;
940         uint32_t n_instructions;
941 };
942
943 static void
944 apply_spec_free(struct apply_spec *s)
945 {
946         uint32_t i;
947
948         if (!s)
949                 return;
950
951         for (i = 0; i < s->n_instructions; i++) {
952                 uintptr_t instr = (uintptr_t)s->instructions[i];
953
954                 free((void *)instr);
955         }
956
957         free(s->instructions);
958         s->instructions = NULL;
959
960         s->n_instructions = 0;
961 }
962
963 static int
964 apply_statement_parse(uint32_t *block_mask,
965                       char **tokens,
966                       uint32_t n_tokens,
967                       uint32_t n_lines,
968                       uint32_t *err_line,
969                       const char **err_msg)
970 {
971         /* Check format. */
972         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
973                 if (err_line)
974                         *err_line = n_lines;
975                 if (err_msg)
976                         *err_msg = "Invalid apply statement.";
977                 return -EINVAL;
978         }
979
980         /* block_mask. */
981         *block_mask |= 1 << APPLY_BLOCK;
982
983         return 0;
984 }
985
986 static int
987 apply_block_parse(struct apply_spec *s,
988                   uint32_t *block_mask,
989                   char **tokens,
990                   uint32_t n_tokens,
991                   uint32_t n_lines,
992                   uint32_t *err_line,
993                   const char **err_msg)
994 {
995         char buffer[MAX_INSTRUCTION_LENGTH], *instr;
996         const char **new_instructions;
997         uint32_t i;
998
999         /* Handle end of block. */
1000         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1001                 *block_mask &= ~(1 << APPLY_BLOCK);
1002                 return 0;
1003         }
1004
1005         /* spec. */
1006         buffer[0] = 0;
1007         for (i = 0; i < n_tokens; i++) {
1008                 if (i)
1009                         strcat(buffer, " ");
1010                 strcat(buffer, tokens[i]);
1011         }
1012
1013         instr = strdup(buffer);
1014         if (!instr) {
1015                 if (err_line)
1016                         *err_line = n_lines;
1017                 if (err_msg)
1018                         *err_msg = "Memory allocation failed.";
1019                 return -ENOMEM;
1020         }
1021
1022         new_instructions = reallocarray(s->instructions,
1023                                         s->n_instructions + 1,
1024                                         sizeof(char *));
1025         if (!new_instructions) {
1026                 free(instr);
1027
1028                 if (err_line)
1029                         *err_line = n_lines;
1030                 if (err_msg)
1031                         *err_msg = "Memory allocation failed.";
1032                 return -ENOMEM;
1033         }
1034
1035         s->instructions = new_instructions;
1036         s->instructions[s->n_instructions] = instr;
1037         s->n_instructions++;
1038
1039         return 0;
1040 }
1041
1042 /*
1043  * Pipeline.
1044  */
1045 int
1046 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1047                                  FILE *spec,
1048                                  uint32_t *err_line,
1049                                  const char **err_msg)
1050 {
1051         struct extobj_spec extobj_spec = {0};
1052         struct struct_spec struct_spec = {0};
1053         struct header_spec header_spec = {0};
1054         struct metadata_spec metadata_spec = {0};
1055         struct action_spec action_spec = {0};
1056         struct table_spec table_spec = {0};
1057         struct apply_spec apply_spec = {0};
1058         uint32_t n_lines;
1059         uint32_t block_mask = 0;
1060         int status;
1061
1062         /* Check the input arguments. */
1063         if (!p) {
1064                 if (err_line)
1065                         *err_line = 0;
1066                 if (err_msg)
1067                         *err_msg = "Null pipeline arument.";
1068                 status = -EINVAL;
1069                 goto error;
1070         }
1071
1072         if (!p) {
1073                 if (err_line)
1074                         *err_line = 0;
1075                 if (err_msg)
1076                         *err_msg = "Null specification file argument.";
1077                 status = -EINVAL;
1078                 goto error;
1079         }
1080
1081         for (n_lines = 1; ; n_lines++) {
1082                 char line[MAX_LINE_LENGTH];
1083                 char *tokens[MAX_TOKENS], *ptr = line;
1084                 uint32_t n_tokens = 0;
1085
1086                 /* Read next line. */
1087                 if (!fgets(line, sizeof(line), spec))
1088                         break;
1089
1090                 /* Parse the line into tokens. */
1091                 for ( ; ; ) {
1092                         char *token;
1093
1094                         /* Get token. */
1095                         token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1096                         if (!token)
1097                                 break;
1098
1099                         /* Handle comments. */
1100                         if ((token[0] == '#') ||
1101                             (token[0] == ';') ||
1102                             ((token[0] == '/') && (token[1] == '/'))) {
1103                                 break;
1104                         }
1105
1106                         /* Handle excessively long lines. */
1107                         if (n_tokens >= MAX_TOKENS) {
1108                                 if (err_line)
1109                                         *err_line = n_lines;
1110                                 if (err_msg)
1111                                         *err_msg = "Too many tokens.";
1112                                 status = -EINVAL;
1113                                 goto error;
1114                         }
1115
1116                         /* Save token. */
1117                         tokens[n_tokens] = token;
1118                         n_tokens++;
1119                 }
1120
1121                 /* Handle empty lines. */
1122                 if (!n_tokens)
1123                         continue;
1124
1125                 /* struct block. */
1126                 if (block_mask & (1 << STRUCT_BLOCK)) {
1127                         status = struct_block_parse(&struct_spec,
1128                                                     &block_mask,
1129                                                     tokens,
1130                                                     n_tokens,
1131                                                     n_lines,
1132                                                     err_line,
1133                                                     err_msg);
1134                         if (status)
1135                                 goto error;
1136
1137                         if (block_mask & (1 << STRUCT_BLOCK))
1138                                 continue;
1139
1140                         /* End of block. */
1141                         status = rte_swx_pipeline_struct_type_register(p,
1142                                 struct_spec.name,
1143                                 struct_spec.fields,
1144                                 struct_spec.n_fields);
1145                         if (status) {
1146                                 if (err_line)
1147                                         *err_line = n_lines;
1148                                 if (err_msg)
1149                                         *err_msg = "Struct registration error.";
1150                                 goto error;
1151                         }
1152
1153                         struct_spec_free(&struct_spec);
1154
1155                         continue;
1156                 }
1157
1158                 /* action block. */
1159                 if (block_mask & (1 << ACTION_BLOCK)) {
1160                         status = action_block_parse(&action_spec,
1161                                                     &block_mask,
1162                                                     tokens,
1163                                                     n_tokens,
1164                                                     n_lines,
1165                                                     err_line,
1166                                                     err_msg);
1167                         if (status)
1168                                 goto error;
1169
1170                         if (block_mask & (1 << ACTION_BLOCK))
1171                                 continue;
1172
1173                         /* End of block. */
1174                         status = rte_swx_pipeline_action_config(p,
1175                                 action_spec.name,
1176                                 action_spec.args_struct_type_name,
1177                                 action_spec.instructions,
1178                                 action_spec.n_instructions);
1179                         if (status) {
1180                                 if (err_line)
1181                                         *err_line = n_lines;
1182                                 if (err_msg)
1183                                         *err_msg = "Action config error.";
1184                                 goto error;
1185                         }
1186
1187                         action_spec_free(&action_spec);
1188
1189                         continue;
1190                 }
1191
1192                 /* table block. */
1193                 if (block_mask & (1 << TABLE_BLOCK)) {
1194                         status = table_block_parse(&table_spec,
1195                                                    &block_mask,
1196                                                    tokens,
1197                                                    n_tokens,
1198                                                    n_lines,
1199                                                    err_line,
1200                                                    err_msg);
1201                         if (status)
1202                                 goto error;
1203
1204                         if (block_mask & (1 << TABLE_BLOCK))
1205                                 continue;
1206
1207                         /* End of block. */
1208                         status = rte_swx_pipeline_table_config(p,
1209                                 table_spec.name,
1210                                 &table_spec.params,
1211                                 table_spec.recommended_table_type_name,
1212                                 table_spec.args,
1213                                 table_spec.size);
1214                         if (status) {
1215                                 if (err_line)
1216                                         *err_line = n_lines;
1217                                 if (err_msg)
1218                                         *err_msg = "Table configuration error.";
1219                                 goto error;
1220                         }
1221
1222                         table_spec_free(&table_spec);
1223
1224                         continue;
1225                 }
1226
1227                 /* apply block. */
1228                 if (block_mask & (1 << APPLY_BLOCK)) {
1229                         status = apply_block_parse(&apply_spec,
1230                                                    &block_mask,
1231                                                    tokens,
1232                                                    n_tokens,
1233                                                    n_lines,
1234                                                    err_line,
1235                                                    err_msg);
1236                         if (status)
1237                                 goto error;
1238
1239                         if (block_mask & (1 << APPLY_BLOCK))
1240                                 continue;
1241
1242                         /* End of block. */
1243                         status = rte_swx_pipeline_instructions_config(p,
1244                                 apply_spec.instructions,
1245                                 apply_spec.n_instructions);
1246                         if (status) {
1247                                 if (err_line)
1248                                         *err_line = n_lines;
1249                                 if (err_msg)
1250                                         *err_msg = "Pipeline instructions err.";
1251                                 goto error;
1252                         }
1253
1254                         apply_spec_free(&apply_spec);
1255
1256                         continue;
1257                 }
1258
1259                 /* extobj. */
1260                 if (!strcmp(tokens[0], "extobj")) {
1261                         status = extobj_statement_parse(&extobj_spec,
1262                                                         tokens,
1263                                                         n_tokens,
1264                                                         n_lines,
1265                                                         err_line,
1266                                                         err_msg);
1267                         if (status)
1268                                 goto error;
1269
1270                         status = rte_swx_pipeline_extern_object_config(p,
1271                                 extobj_spec.name,
1272                                 extobj_spec.extern_type_name,
1273                                 extobj_spec.pragma);
1274                         if (status) {
1275                                 if (err_line)
1276                                         *err_line = n_lines;
1277                                 if (err_msg)
1278                                         *err_msg = "Extern object config err.";
1279                                 goto error;
1280                         }
1281
1282                         extobj_spec_free(&extobj_spec);
1283
1284                         continue;
1285                 }
1286
1287                 /* struct. */
1288                 if (!strcmp(tokens[0], "struct")) {
1289                         status = struct_statement_parse(&struct_spec,
1290                                                         &block_mask,
1291                                                         tokens,
1292                                                         n_tokens,
1293                                                         n_lines,
1294                                                         err_line,
1295                                                         err_msg);
1296                         if (status)
1297                                 goto error;
1298
1299                         continue;
1300                 }
1301
1302                 /* header. */
1303                 if (!strcmp(tokens[0], "header")) {
1304                         status = header_statement_parse(&header_spec,
1305                                                         tokens,
1306                                                         n_tokens,
1307                                                         n_lines,
1308                                                         err_line,
1309                                                         err_msg);
1310                         if (status)
1311                                 goto error;
1312
1313                         status = rte_swx_pipeline_packet_header_register(p,
1314                                 header_spec.name,
1315                                 header_spec.struct_type_name);
1316                         if (status) {
1317                                 if (err_line)
1318                                         *err_line = n_lines;
1319                                 if (err_msg)
1320                                         *err_msg = "Header registration error.";
1321                                 goto error;
1322                         }
1323
1324                         header_spec_free(&header_spec);
1325
1326                         continue;
1327                 }
1328
1329                 /* metadata. */
1330                 if (!strcmp(tokens[0], "metadata")) {
1331                         status = metadata_statement_parse(&metadata_spec,
1332                                                           tokens,
1333                                                           n_tokens,
1334                                                           n_lines,
1335                                                           err_line,
1336                                                           err_msg);
1337                         if (status)
1338                                 goto error;
1339
1340                         status = rte_swx_pipeline_packet_metadata_register(p,
1341                                 metadata_spec.struct_type_name);
1342                         if (status) {
1343                                 if (err_line)
1344                                         *err_line = n_lines;
1345                                 if (err_msg)
1346                                         *err_msg = "Meta-data reg err.";
1347                                 goto error;
1348                         }
1349
1350                         metadata_spec_free(&metadata_spec);
1351
1352                         continue;
1353                 }
1354
1355                 /* action. */
1356                 if (!strcmp(tokens[0], "action")) {
1357                         status = action_statement_parse(&action_spec,
1358                                                         &block_mask,
1359                                                         tokens,
1360                                                         n_tokens,
1361                                                         n_lines,
1362                                                         err_line,
1363                                                         err_msg);
1364                         if (status)
1365                                 goto error;
1366
1367                         continue;
1368                 }
1369
1370                 /* table. */
1371                 if (!strcmp(tokens[0], "table")) {
1372                         status = table_statement_parse(&table_spec,
1373                                                        &block_mask,
1374                                                        tokens,
1375                                                        n_tokens,
1376                                                        n_lines,
1377                                                        err_line,
1378                                                        err_msg);
1379                         if (status)
1380                                 goto error;
1381
1382                         continue;
1383                 }
1384
1385                 /* apply. */
1386                 if (!strcmp(tokens[0], "apply")) {
1387                         status = apply_statement_parse(&block_mask,
1388                                                        tokens,
1389                                                        n_tokens,
1390                                                        n_lines,
1391                                                        err_line,
1392                                                        err_msg);
1393                         if (status)
1394                                 goto error;
1395
1396                         continue;
1397                 }
1398
1399                 /* Anything else. */
1400                 if (err_line)
1401                         *err_line = n_lines;
1402                 if (err_msg)
1403                         *err_msg = "Unknown statement.";
1404                 status = -EINVAL;
1405                 goto error;
1406         }
1407
1408         /* Handle unfinished block. */
1409         if (block_mask) {
1410                 if (err_line)
1411                         *err_line = n_lines;
1412                 if (err_msg)
1413                         *err_msg = "Missing }.";
1414                 status = -EINVAL;
1415                 goto error;
1416         }
1417
1418         /* Pipeline build. */
1419         status = rte_swx_pipeline_build(p);
1420         if (status) {
1421                 if (err_line)
1422                         *err_line = n_lines;
1423                 if (err_msg)
1424                         *err_msg = "Pipeline build error.";
1425                 goto error;
1426         }
1427
1428         return 0;
1429
1430 error:
1431         extobj_spec_free(&extobj_spec);
1432         struct_spec_free(&struct_spec);
1433         header_spec_free(&header_spec);
1434         metadata_spec_free(&metadata_spec);
1435         action_spec_free(&action_spec);
1436         table_spec_free(&table_spec);
1437         apply_spec_free(&apply_spec);
1438         return status;
1439 }