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