pipeline: fix string copy into fixed size buffer
[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  * apply.
945  *
946  * apply {
947  *      INSTRUCTION
948  *      ...
949  * }
950  */
951 struct apply_spec {
952         const char **instructions;
953         uint32_t n_instructions;
954 };
955
956 static void
957 apply_spec_free(struct apply_spec *s)
958 {
959         uint32_t i;
960
961         if (!s)
962                 return;
963
964         for (i = 0; i < s->n_instructions; i++) {
965                 uintptr_t instr = (uintptr_t)s->instructions[i];
966
967                 free((void *)instr);
968         }
969
970         free(s->instructions);
971         s->instructions = NULL;
972
973         s->n_instructions = 0;
974 }
975
976 static int
977 apply_statement_parse(uint32_t *block_mask,
978                       char **tokens,
979                       uint32_t n_tokens,
980                       uint32_t n_lines,
981                       uint32_t *err_line,
982                       const char **err_msg)
983 {
984         /* Check format. */
985         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
986                 if (err_line)
987                         *err_line = n_lines;
988                 if (err_msg)
989                         *err_msg = "Invalid apply statement.";
990                 return -EINVAL;
991         }
992
993         /* block_mask. */
994         *block_mask |= 1 << APPLY_BLOCK;
995
996         return 0;
997 }
998
999 static int
1000 apply_block_parse(struct apply_spec *s,
1001                   uint32_t *block_mask,
1002                   char **tokens,
1003                   uint32_t n_tokens,
1004                   uint32_t n_lines,
1005                   uint32_t *err_line,
1006                   const char **err_msg)
1007 {
1008         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1009         const char **new_instructions;
1010         uint32_t i;
1011
1012         /* Handle end of block. */
1013         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1014                 *block_mask &= ~(1 << APPLY_BLOCK);
1015                 return 0;
1016         }
1017
1018         /* spec. */
1019         buffer[0] = 0;
1020         for (i = 0; i < n_tokens; i++) {
1021                 if (i)
1022                         strcat(buffer, " ");
1023                 strcat(buffer, tokens[i]);
1024         }
1025
1026         instr = strdup(buffer);
1027         if (!instr) {
1028                 if (err_line)
1029                         *err_line = n_lines;
1030                 if (err_msg)
1031                         *err_msg = "Memory allocation failed.";
1032                 return -ENOMEM;
1033         }
1034
1035         new_instructions = realloc(s->instructions,
1036                                    (s->n_instructions + 1) * sizeof(char *));
1037         if (!new_instructions) {
1038                 free(instr);
1039
1040                 if (err_line)
1041                         *err_line = n_lines;
1042                 if (err_msg)
1043                         *err_msg = "Memory allocation failed.";
1044                 return -ENOMEM;
1045         }
1046
1047         s->instructions = new_instructions;
1048         s->instructions[s->n_instructions] = instr;
1049         s->n_instructions++;
1050
1051         return 0;
1052 }
1053
1054 /*
1055  * Pipeline.
1056  */
1057 int
1058 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1059                                  FILE *spec,
1060                                  uint32_t *err_line,
1061                                  const char **err_msg)
1062 {
1063         struct extobj_spec extobj_spec = {0};
1064         struct struct_spec struct_spec = {0};
1065         struct header_spec header_spec = {0};
1066         struct metadata_spec metadata_spec = {0};
1067         struct action_spec action_spec = {0};
1068         struct table_spec table_spec = {0};
1069         struct apply_spec apply_spec = {0};
1070         uint32_t n_lines;
1071         uint32_t block_mask = 0;
1072         int status;
1073
1074         /* Check the input arguments. */
1075         if (!p) {
1076                 if (err_line)
1077                         *err_line = 0;
1078                 if (err_msg)
1079                         *err_msg = "Null pipeline arument.";
1080                 status = -EINVAL;
1081                 goto error;
1082         }
1083
1084         if (!spec) {
1085                 if (err_line)
1086                         *err_line = 0;
1087                 if (err_msg)
1088                         *err_msg = "Null specification file argument.";
1089                 status = -EINVAL;
1090                 goto error;
1091         }
1092
1093         for (n_lines = 1; ; n_lines++) {
1094                 char line[MAX_LINE_LENGTH];
1095                 char *tokens[MAX_TOKENS], *ptr = line;
1096                 uint32_t n_tokens = 0;
1097
1098                 /* Read next line. */
1099                 if (!fgets(line, sizeof(line), spec))
1100                         break;
1101
1102                 /* Parse the line into tokens. */
1103                 for ( ; ; ) {
1104                         char *token;
1105
1106                         /* Get token. */
1107                         token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1108                         if (!token)
1109                                 break;
1110
1111                         /* Handle comments. */
1112                         if ((token[0] == '#') ||
1113                             (token[0] == ';') ||
1114                             ((token[0] == '/') && (token[1] == '/'))) {
1115                                 break;
1116                         }
1117
1118                         /* Handle excessively long lines. */
1119                         if (n_tokens >= MAX_TOKENS) {
1120                                 if (err_line)
1121                                         *err_line = n_lines;
1122                                 if (err_msg)
1123                                         *err_msg = "Too many tokens.";
1124                                 status = -EINVAL;
1125                                 goto error;
1126                         }
1127
1128                         /* Handle excessively long tokens. */
1129                         if (strnlen(token, RTE_SWX_NAME_SIZE) >=
1130                             RTE_SWX_NAME_SIZE) {
1131                                 if (err_line)
1132                                         *err_line = n_lines;
1133                                 if (err_msg)
1134                                         *err_msg = "Token too big.";
1135                                 status = -EINVAL;
1136                                 goto error;
1137                         }
1138
1139                         /* Save token. */
1140                         tokens[n_tokens] = token;
1141                         n_tokens++;
1142                 }
1143
1144                 /* Handle empty lines. */
1145                 if (!n_tokens)
1146                         continue;
1147
1148                 /* struct block. */
1149                 if (block_mask & (1 << STRUCT_BLOCK)) {
1150                         status = struct_block_parse(&struct_spec,
1151                                                     &block_mask,
1152                                                     tokens,
1153                                                     n_tokens,
1154                                                     n_lines,
1155                                                     err_line,
1156                                                     err_msg);
1157                         if (status)
1158                                 goto error;
1159
1160                         if (block_mask & (1 << STRUCT_BLOCK))
1161                                 continue;
1162
1163                         /* End of block. */
1164                         status = rte_swx_pipeline_struct_type_register(p,
1165                                 struct_spec.name,
1166                                 struct_spec.fields,
1167                                 struct_spec.n_fields);
1168                         if (status) {
1169                                 if (err_line)
1170                                         *err_line = n_lines;
1171                                 if (err_msg)
1172                                         *err_msg = "Struct registration error.";
1173                                 goto error;
1174                         }
1175
1176                         struct_spec_free(&struct_spec);
1177
1178                         continue;
1179                 }
1180
1181                 /* action block. */
1182                 if (block_mask & (1 << ACTION_BLOCK)) {
1183                         status = action_block_parse(&action_spec,
1184                                                     &block_mask,
1185                                                     tokens,
1186                                                     n_tokens,
1187                                                     n_lines,
1188                                                     err_line,
1189                                                     err_msg);
1190                         if (status)
1191                                 goto error;
1192
1193                         if (block_mask & (1 << ACTION_BLOCK))
1194                                 continue;
1195
1196                         /* End of block. */
1197                         status = rte_swx_pipeline_action_config(p,
1198                                 action_spec.name,
1199                                 action_spec.args_struct_type_name,
1200                                 action_spec.instructions,
1201                                 action_spec.n_instructions);
1202                         if (status) {
1203                                 if (err_line)
1204                                         *err_line = n_lines;
1205                                 if (err_msg)
1206                                         *err_msg = "Action config error.";
1207                                 goto error;
1208                         }
1209
1210                         action_spec_free(&action_spec);
1211
1212                         continue;
1213                 }
1214
1215                 /* table block. */
1216                 if (block_mask & (1 << TABLE_BLOCK)) {
1217                         status = table_block_parse(&table_spec,
1218                                                    &block_mask,
1219                                                    tokens,
1220                                                    n_tokens,
1221                                                    n_lines,
1222                                                    err_line,
1223                                                    err_msg);
1224                         if (status)
1225                                 goto error;
1226
1227                         if (block_mask & (1 << TABLE_BLOCK))
1228                                 continue;
1229
1230                         /* End of block. */
1231                         status = rte_swx_pipeline_table_config(p,
1232                                 table_spec.name,
1233                                 &table_spec.params,
1234                                 table_spec.recommended_table_type_name,
1235                                 table_spec.args,
1236                                 table_spec.size);
1237                         if (status) {
1238                                 if (err_line)
1239                                         *err_line = n_lines;
1240                                 if (err_msg)
1241                                         *err_msg = "Table configuration error.";
1242                                 goto error;
1243                         }
1244
1245                         table_spec_free(&table_spec);
1246
1247                         continue;
1248                 }
1249
1250                 /* apply block. */
1251                 if (block_mask & (1 << APPLY_BLOCK)) {
1252                         status = apply_block_parse(&apply_spec,
1253                                                    &block_mask,
1254                                                    tokens,
1255                                                    n_tokens,
1256                                                    n_lines,
1257                                                    err_line,
1258                                                    err_msg);
1259                         if (status)
1260                                 goto error;
1261
1262                         if (block_mask & (1 << APPLY_BLOCK))
1263                                 continue;
1264
1265                         /* End of block. */
1266                         status = rte_swx_pipeline_instructions_config(p,
1267                                 apply_spec.instructions,
1268                                 apply_spec.n_instructions);
1269                         if (status) {
1270                                 if (err_line)
1271                                         *err_line = n_lines;
1272                                 if (err_msg)
1273                                         *err_msg = "Pipeline instructions err.";
1274                                 goto error;
1275                         }
1276
1277                         apply_spec_free(&apply_spec);
1278
1279                         continue;
1280                 }
1281
1282                 /* extobj. */
1283                 if (!strcmp(tokens[0], "extobj")) {
1284                         status = extobj_statement_parse(&extobj_spec,
1285                                                         tokens,
1286                                                         n_tokens,
1287                                                         n_lines,
1288                                                         err_line,
1289                                                         err_msg);
1290                         if (status)
1291                                 goto error;
1292
1293                         status = rte_swx_pipeline_extern_object_config(p,
1294                                 extobj_spec.name,
1295                                 extobj_spec.extern_type_name,
1296                                 extobj_spec.pragma);
1297                         if (status) {
1298                                 if (err_line)
1299                                         *err_line = n_lines;
1300                                 if (err_msg)
1301                                         *err_msg = "Extern object config err.";
1302                                 goto error;
1303                         }
1304
1305                         extobj_spec_free(&extobj_spec);
1306
1307                         continue;
1308                 }
1309
1310                 /* struct. */
1311                 if (!strcmp(tokens[0], "struct")) {
1312                         status = struct_statement_parse(&struct_spec,
1313                                                         &block_mask,
1314                                                         tokens,
1315                                                         n_tokens,
1316                                                         n_lines,
1317                                                         err_line,
1318                                                         err_msg);
1319                         if (status)
1320                                 goto error;
1321
1322                         continue;
1323                 }
1324
1325                 /* header. */
1326                 if (!strcmp(tokens[0], "header")) {
1327                         status = header_statement_parse(&header_spec,
1328                                                         tokens,
1329                                                         n_tokens,
1330                                                         n_lines,
1331                                                         err_line,
1332                                                         err_msg);
1333                         if (status)
1334                                 goto error;
1335
1336                         status = rte_swx_pipeline_packet_header_register(p,
1337                                 header_spec.name,
1338                                 header_spec.struct_type_name);
1339                         if (status) {
1340                                 if (err_line)
1341                                         *err_line = n_lines;
1342                                 if (err_msg)
1343                                         *err_msg = "Header registration error.";
1344                                 goto error;
1345                         }
1346
1347                         header_spec_free(&header_spec);
1348
1349                         continue;
1350                 }
1351
1352                 /* metadata. */
1353                 if (!strcmp(tokens[0], "metadata")) {
1354                         status = metadata_statement_parse(&metadata_spec,
1355                                                           tokens,
1356                                                           n_tokens,
1357                                                           n_lines,
1358                                                           err_line,
1359                                                           err_msg);
1360                         if (status)
1361                                 goto error;
1362
1363                         status = rte_swx_pipeline_packet_metadata_register(p,
1364                                 metadata_spec.struct_type_name);
1365                         if (status) {
1366                                 if (err_line)
1367                                         *err_line = n_lines;
1368                                 if (err_msg)
1369                                         *err_msg = "Meta-data reg err.";
1370                                 goto error;
1371                         }
1372
1373                         metadata_spec_free(&metadata_spec);
1374
1375                         continue;
1376                 }
1377
1378                 /* action. */
1379                 if (!strcmp(tokens[0], "action")) {
1380                         status = action_statement_parse(&action_spec,
1381                                                         &block_mask,
1382                                                         tokens,
1383                                                         n_tokens,
1384                                                         n_lines,
1385                                                         err_line,
1386                                                         err_msg);
1387                         if (status)
1388                                 goto error;
1389
1390                         continue;
1391                 }
1392
1393                 /* table. */
1394                 if (!strcmp(tokens[0], "table")) {
1395                         status = table_statement_parse(&table_spec,
1396                                                        &block_mask,
1397                                                        tokens,
1398                                                        n_tokens,
1399                                                        n_lines,
1400                                                        err_line,
1401                                                        err_msg);
1402                         if (status)
1403                                 goto error;
1404
1405                         continue;
1406                 }
1407
1408                 /* apply. */
1409                 if (!strcmp(tokens[0], "apply")) {
1410                         status = apply_statement_parse(&block_mask,
1411                                                        tokens,
1412                                                        n_tokens,
1413                                                        n_lines,
1414                                                        err_line,
1415                                                        err_msg);
1416                         if (status)
1417                                 goto error;
1418
1419                         continue;
1420                 }
1421
1422                 /* Anything else. */
1423                 if (err_line)
1424                         *err_line = n_lines;
1425                 if (err_msg)
1426                         *err_msg = "Unknown statement.";
1427                 status = -EINVAL;
1428                 goto error;
1429         }
1430
1431         /* Handle unfinished block. */
1432         if (block_mask) {
1433                 if (err_line)
1434                         *err_line = n_lines;
1435                 if (err_msg)
1436                         *err_msg = "Missing }.";
1437                 status = -EINVAL;
1438                 goto error;
1439         }
1440
1441         /* Pipeline build. */
1442         status = rte_swx_pipeline_build(p);
1443         if (status) {
1444                 if (err_line)
1445                         *err_line = n_lines;
1446                 if (err_msg)
1447                         *err_msg = "Pipeline build error.";
1448                 goto error;
1449         }
1450
1451         return 0;
1452
1453 error:
1454         extobj_spec_free(&extobj_spec);
1455         struct_spec_free(&struct_spec);
1456         header_spec_free(&header_spec);
1457         metadata_spec_free(&metadata_spec);
1458         action_spec_free(&action_spec);
1459         table_spec_free(&table_spec);
1460         apply_spec_free(&apply_spec);
1461         return status;
1462 }