pipeline: add register array to SWX
[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  * apply.
1020  *
1021  * apply {
1022  *      INSTRUCTION
1023  *      ...
1024  * }
1025  */
1026 struct apply_spec {
1027         const char **instructions;
1028         uint32_t n_instructions;
1029 };
1030
1031 static void
1032 apply_spec_free(struct apply_spec *s)
1033 {
1034         uint32_t i;
1035
1036         if (!s)
1037                 return;
1038
1039         for (i = 0; i < s->n_instructions; i++) {
1040                 uintptr_t instr = (uintptr_t)s->instructions[i];
1041
1042                 free((void *)instr);
1043         }
1044
1045         free(s->instructions);
1046         s->instructions = NULL;
1047
1048         s->n_instructions = 0;
1049 }
1050
1051 static int
1052 apply_statement_parse(uint32_t *block_mask,
1053                       char **tokens,
1054                       uint32_t n_tokens,
1055                       uint32_t n_lines,
1056                       uint32_t *err_line,
1057                       const char **err_msg)
1058 {
1059         /* Check format. */
1060         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1061                 if (err_line)
1062                         *err_line = n_lines;
1063                 if (err_msg)
1064                         *err_msg = "Invalid apply statement.";
1065                 return -EINVAL;
1066         }
1067
1068         /* block_mask. */
1069         *block_mask |= 1 << APPLY_BLOCK;
1070
1071         return 0;
1072 }
1073
1074 static int
1075 apply_block_parse(struct apply_spec *s,
1076                   uint32_t *block_mask,
1077                   char **tokens,
1078                   uint32_t n_tokens,
1079                   uint32_t n_lines,
1080                   uint32_t *err_line,
1081                   const char **err_msg)
1082 {
1083         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1084         const char **new_instructions;
1085         uint32_t i;
1086
1087         /* Handle end of block. */
1088         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1089                 *block_mask &= ~(1 << APPLY_BLOCK);
1090                 return 0;
1091         }
1092
1093         /* spec. */
1094         buffer[0] = 0;
1095         for (i = 0; i < n_tokens; i++) {
1096                 if (i)
1097                         strcat(buffer, " ");
1098                 strcat(buffer, tokens[i]);
1099         }
1100
1101         instr = strdup(buffer);
1102         if (!instr) {
1103                 if (err_line)
1104                         *err_line = n_lines;
1105                 if (err_msg)
1106                         *err_msg = "Memory allocation failed.";
1107                 return -ENOMEM;
1108         }
1109
1110         new_instructions = realloc(s->instructions,
1111                                    (s->n_instructions + 1) * sizeof(char *));
1112         if (!new_instructions) {
1113                 free(instr);
1114
1115                 if (err_line)
1116                         *err_line = n_lines;
1117                 if (err_msg)
1118                         *err_msg = "Memory allocation failed.";
1119                 return -ENOMEM;
1120         }
1121
1122         s->instructions = new_instructions;
1123         s->instructions[s->n_instructions] = instr;
1124         s->n_instructions++;
1125
1126         return 0;
1127 }
1128
1129 /*
1130  * Pipeline.
1131  */
1132 int
1133 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1134                                  FILE *spec,
1135                                  uint32_t *err_line,
1136                                  const char **err_msg)
1137 {
1138         struct extobj_spec extobj_spec = {0};
1139         struct struct_spec struct_spec = {0};
1140         struct header_spec header_spec = {0};
1141         struct metadata_spec metadata_spec = {0};
1142         struct action_spec action_spec = {0};
1143         struct table_spec table_spec = {0};
1144         struct regarray_spec regarray_spec = {0};
1145         struct apply_spec apply_spec = {0};
1146         uint32_t n_lines;
1147         uint32_t block_mask = 0;
1148         int status;
1149
1150         /* Check the input arguments. */
1151         if (!p) {
1152                 if (err_line)
1153                         *err_line = 0;
1154                 if (err_msg)
1155                         *err_msg = "Null pipeline arument.";
1156                 status = -EINVAL;
1157                 goto error;
1158         }
1159
1160         if (!spec) {
1161                 if (err_line)
1162                         *err_line = 0;
1163                 if (err_msg)
1164                         *err_msg = "Null specification file argument.";
1165                 status = -EINVAL;
1166                 goto error;
1167         }
1168
1169         for (n_lines = 1; ; n_lines++) {
1170                 char line[MAX_LINE_LENGTH];
1171                 char *tokens[MAX_TOKENS], *ptr = line;
1172                 uint32_t n_tokens = 0;
1173
1174                 /* Read next line. */
1175                 if (!fgets(line, sizeof(line), spec))
1176                         break;
1177
1178                 /* Parse the line into tokens. */
1179                 for ( ; ; ) {
1180                         char *token;
1181
1182                         /* Get token. */
1183                         token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1184                         if (!token)
1185                                 break;
1186
1187                         /* Handle comments. */
1188                         if ((token[0] == '#') ||
1189                             (token[0] == ';') ||
1190                             ((token[0] == '/') && (token[1] == '/'))) {
1191                                 break;
1192                         }
1193
1194                         /* Handle excessively long lines. */
1195                         if (n_tokens >= MAX_TOKENS) {
1196                                 if (err_line)
1197                                         *err_line = n_lines;
1198                                 if (err_msg)
1199                                         *err_msg = "Too many tokens.";
1200                                 status = -EINVAL;
1201                                 goto error;
1202                         }
1203
1204                         /* Handle excessively long tokens. */
1205                         if (strnlen(token, RTE_SWX_NAME_SIZE) >=
1206                             RTE_SWX_NAME_SIZE) {
1207                                 if (err_line)
1208                                         *err_line = n_lines;
1209                                 if (err_msg)
1210                                         *err_msg = "Token too big.";
1211                                 status = -EINVAL;
1212                                 goto error;
1213                         }
1214
1215                         /* Save token. */
1216                         tokens[n_tokens] = token;
1217                         n_tokens++;
1218                 }
1219
1220                 /* Handle empty lines. */
1221                 if (!n_tokens)
1222                         continue;
1223
1224                 /* struct block. */
1225                 if (block_mask & (1 << STRUCT_BLOCK)) {
1226                         status = struct_block_parse(&struct_spec,
1227                                                     &block_mask,
1228                                                     tokens,
1229                                                     n_tokens,
1230                                                     n_lines,
1231                                                     err_line,
1232                                                     err_msg);
1233                         if (status)
1234                                 goto error;
1235
1236                         if (block_mask & (1 << STRUCT_BLOCK))
1237                                 continue;
1238
1239                         /* End of block. */
1240                         status = rte_swx_pipeline_struct_type_register(p,
1241                                 struct_spec.name,
1242                                 struct_spec.fields,
1243                                 struct_spec.n_fields);
1244                         if (status) {
1245                                 if (err_line)
1246                                         *err_line = n_lines;
1247                                 if (err_msg)
1248                                         *err_msg = "Struct registration error.";
1249                                 goto error;
1250                         }
1251
1252                         struct_spec_free(&struct_spec);
1253
1254                         continue;
1255                 }
1256
1257                 /* action block. */
1258                 if (block_mask & (1 << ACTION_BLOCK)) {
1259                         status = action_block_parse(&action_spec,
1260                                                     &block_mask,
1261                                                     tokens,
1262                                                     n_tokens,
1263                                                     n_lines,
1264                                                     err_line,
1265                                                     err_msg);
1266                         if (status)
1267                                 goto error;
1268
1269                         if (block_mask & (1 << ACTION_BLOCK))
1270                                 continue;
1271
1272                         /* End of block. */
1273                         status = rte_swx_pipeline_action_config(p,
1274                                 action_spec.name,
1275                                 action_spec.args_struct_type_name,
1276                                 action_spec.instructions,
1277                                 action_spec.n_instructions);
1278                         if (status) {
1279                                 if (err_line)
1280                                         *err_line = n_lines;
1281                                 if (err_msg)
1282                                         *err_msg = "Action config error.";
1283                                 goto error;
1284                         }
1285
1286                         action_spec_free(&action_spec);
1287
1288                         continue;
1289                 }
1290
1291                 /* table block. */
1292                 if (block_mask & (1 << TABLE_BLOCK)) {
1293                         status = table_block_parse(&table_spec,
1294                                                    &block_mask,
1295                                                    tokens,
1296                                                    n_tokens,
1297                                                    n_lines,
1298                                                    err_line,
1299                                                    err_msg);
1300                         if (status)
1301                                 goto error;
1302
1303                         if (block_mask & (1 << TABLE_BLOCK))
1304                                 continue;
1305
1306                         /* End of block. */
1307                         status = rte_swx_pipeline_table_config(p,
1308                                 table_spec.name,
1309                                 &table_spec.params,
1310                                 table_spec.recommended_table_type_name,
1311                                 table_spec.args,
1312                                 table_spec.size);
1313                         if (status) {
1314                                 if (err_line)
1315                                         *err_line = n_lines;
1316                                 if (err_msg)
1317                                         *err_msg = "Table configuration error.";
1318                                 goto error;
1319                         }
1320
1321                         table_spec_free(&table_spec);
1322
1323                         continue;
1324                 }
1325
1326                 /* apply block. */
1327                 if (block_mask & (1 << APPLY_BLOCK)) {
1328                         status = apply_block_parse(&apply_spec,
1329                                                    &block_mask,
1330                                                    tokens,
1331                                                    n_tokens,
1332                                                    n_lines,
1333                                                    err_line,
1334                                                    err_msg);
1335                         if (status)
1336                                 goto error;
1337
1338                         if (block_mask & (1 << APPLY_BLOCK))
1339                                 continue;
1340
1341                         /* End of block. */
1342                         status = rte_swx_pipeline_instructions_config(p,
1343                                 apply_spec.instructions,
1344                                 apply_spec.n_instructions);
1345                         if (status) {
1346                                 if (err_line)
1347                                         *err_line = n_lines;
1348                                 if (err_msg)
1349                                         *err_msg = "Pipeline instructions err.";
1350                                 goto error;
1351                         }
1352
1353                         apply_spec_free(&apply_spec);
1354
1355                         continue;
1356                 }
1357
1358                 /* extobj. */
1359                 if (!strcmp(tokens[0], "extobj")) {
1360                         status = extobj_statement_parse(&extobj_spec,
1361                                                         tokens,
1362                                                         n_tokens,
1363                                                         n_lines,
1364                                                         err_line,
1365                                                         err_msg);
1366                         if (status)
1367                                 goto error;
1368
1369                         status = rte_swx_pipeline_extern_object_config(p,
1370                                 extobj_spec.name,
1371                                 extobj_spec.extern_type_name,
1372                                 extobj_spec.pragma);
1373                         if (status) {
1374                                 if (err_line)
1375                                         *err_line = n_lines;
1376                                 if (err_msg)
1377                                         *err_msg = "Extern object config err.";
1378                                 goto error;
1379                         }
1380
1381                         extobj_spec_free(&extobj_spec);
1382
1383                         continue;
1384                 }
1385
1386                 /* struct. */
1387                 if (!strcmp(tokens[0], "struct")) {
1388                         status = struct_statement_parse(&struct_spec,
1389                                                         &block_mask,
1390                                                         tokens,
1391                                                         n_tokens,
1392                                                         n_lines,
1393                                                         err_line,
1394                                                         err_msg);
1395                         if (status)
1396                                 goto error;
1397
1398                         continue;
1399                 }
1400
1401                 /* header. */
1402                 if (!strcmp(tokens[0], "header")) {
1403                         status = header_statement_parse(&header_spec,
1404                                                         tokens,
1405                                                         n_tokens,
1406                                                         n_lines,
1407                                                         err_line,
1408                                                         err_msg);
1409                         if (status)
1410                                 goto error;
1411
1412                         status = rte_swx_pipeline_packet_header_register(p,
1413                                 header_spec.name,
1414                                 header_spec.struct_type_name);
1415                         if (status) {
1416                                 if (err_line)
1417                                         *err_line = n_lines;
1418                                 if (err_msg)
1419                                         *err_msg = "Header registration error.";
1420                                 goto error;
1421                         }
1422
1423                         header_spec_free(&header_spec);
1424
1425                         continue;
1426                 }
1427
1428                 /* metadata. */
1429                 if (!strcmp(tokens[0], "metadata")) {
1430                         status = metadata_statement_parse(&metadata_spec,
1431                                                           tokens,
1432                                                           n_tokens,
1433                                                           n_lines,
1434                                                           err_line,
1435                                                           err_msg);
1436                         if (status)
1437                                 goto error;
1438
1439                         status = rte_swx_pipeline_packet_metadata_register(p,
1440                                 metadata_spec.struct_type_name);
1441                         if (status) {
1442                                 if (err_line)
1443                                         *err_line = n_lines;
1444                                 if (err_msg)
1445                                         *err_msg = "Meta-data reg err.";
1446                                 goto error;
1447                         }
1448
1449                         metadata_spec_free(&metadata_spec);
1450
1451                         continue;
1452                 }
1453
1454                 /* action. */
1455                 if (!strcmp(tokens[0], "action")) {
1456                         status = action_statement_parse(&action_spec,
1457                                                         &block_mask,
1458                                                         tokens,
1459                                                         n_tokens,
1460                                                         n_lines,
1461                                                         err_line,
1462                                                         err_msg);
1463                         if (status)
1464                                 goto error;
1465
1466                         continue;
1467                 }
1468
1469                 /* table. */
1470                 if (!strcmp(tokens[0], "table")) {
1471                         status = table_statement_parse(&table_spec,
1472                                                        &block_mask,
1473                                                        tokens,
1474                                                        n_tokens,
1475                                                        n_lines,
1476                                                        err_line,
1477                                                        err_msg);
1478                         if (status)
1479                                 goto error;
1480
1481                         continue;
1482                 }
1483
1484                 /* regarray. */
1485                 if (!strcmp(tokens[0], "regarray")) {
1486                         status = regarray_statement_parse(&regarray_spec,
1487                                                           tokens,
1488                                                           n_tokens,
1489                                                           n_lines,
1490                                                           err_line,
1491                                                           err_msg);
1492                         if (status)
1493                                 goto error;
1494
1495                         status = rte_swx_pipeline_regarray_config(p,
1496                                 regarray_spec.name,
1497                                 regarray_spec.size,
1498                                 regarray_spec.init_val);
1499                         if (status) {
1500                                 if (err_line)
1501                                         *err_line = n_lines;
1502                                 if (err_msg)
1503                                         *err_msg = "Register array configuration error.";
1504                                 goto error;
1505                         }
1506
1507                         regarray_spec_free(&regarray_spec);
1508
1509                         continue;
1510                 }
1511
1512                 /* apply. */
1513                 if (!strcmp(tokens[0], "apply")) {
1514                         status = apply_statement_parse(&block_mask,
1515                                                        tokens,
1516                                                        n_tokens,
1517                                                        n_lines,
1518                                                        err_line,
1519                                                        err_msg);
1520                         if (status)
1521                                 goto error;
1522
1523                         continue;
1524                 }
1525
1526                 /* Anything else. */
1527                 if (err_line)
1528                         *err_line = n_lines;
1529                 if (err_msg)
1530                         *err_msg = "Unknown statement.";
1531                 status = -EINVAL;
1532                 goto error;
1533         }
1534
1535         /* Handle unfinished block. */
1536         if (block_mask) {
1537                 if (err_line)
1538                         *err_line = n_lines;
1539                 if (err_msg)
1540                         *err_msg = "Missing }.";
1541                 status = -EINVAL;
1542                 goto error;
1543         }
1544
1545         /* Pipeline build. */
1546         status = rte_swx_pipeline_build(p);
1547         if (status) {
1548                 if (err_line)
1549                         *err_line = n_lines;
1550                 if (err_msg)
1551                         *err_msg = "Pipeline build error.";
1552                 goto error;
1553         }
1554
1555         return 0;
1556
1557 error:
1558         extobj_spec_free(&extobj_spec);
1559         struct_spec_free(&struct_spec);
1560         header_spec_free(&header_spec);
1561         metadata_spec_free(&metadata_spec);
1562         action_spec_free(&action_spec);
1563         table_spec_free(&table_spec);
1564         regarray_spec_free(&regarray_spec);
1565         apply_spec_free(&apply_spec);
1566         return status;
1567 }