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