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