net/ice: enable Rx timestamp on flex descriptor
[dpdk.git] / lib / 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 SELECTOR_BLOCK 5
22 #define SELECTOR_SELECTOR_BLOCK 6
23 #define LEARNER_BLOCK 7
24 #define LEARNER_KEY_BLOCK 8
25 #define LEARNER_ACTIONS_BLOCK 9
26 #define APPLY_BLOCK 10
27
28 /*
29  * extobj.
30  *
31  * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
32  */
33 struct extobj_spec {
34         char *name;
35         char *extern_type_name;
36         char *pragma;
37 };
38
39 static void
40 extobj_spec_free(struct extobj_spec *s)
41 {
42         if (!s)
43                 return;
44
45         free(s->name);
46         s->name = NULL;
47
48         free(s->extern_type_name);
49         s->extern_type_name = NULL;
50
51         free(s->pragma);
52         s->pragma = NULL;
53 }
54
55 static int
56 extobj_statement_parse(struct extobj_spec *s,
57                        char **tokens,
58                        uint32_t n_tokens,
59                        uint32_t n_lines,
60                        uint32_t *err_line,
61                        const char **err_msg)
62 {
63         /* Check format. */
64         if (((n_tokens != 4) && (n_tokens != 6)) ||
65             ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
66             ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
67                                  strcmp(tokens[4], "pragma")))) {
68                 if (err_line)
69                         *err_line = n_lines;
70                 if (err_msg)
71                         *err_msg = "Invalid extobj statement.";
72                 return -EINVAL;
73         }
74
75         /* spec. */
76         s->name = strdup(tokens[1]);
77         s->extern_type_name = strdup(tokens[3]);
78         s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
79
80         if (!s->name ||
81             !s->extern_type_name ||
82             ((n_tokens == 6) && !s->pragma)) {
83                 free(s->name);
84                 free(s->extern_type_name);
85                 free(s->pragma);
86
87                 if (err_line)
88                         *err_line = n_lines;
89                 if (err_msg)
90                         *err_msg = "Memory allocation failed.";
91                 return -ENOMEM;
92         }
93
94         return 0;
95 }
96
97 /*
98  * struct.
99  *
100  * struct STRUCT_TYPE_NAME {
101  *      bit<SIZE> | varbit<SIZE> FIELD_NAME
102  *      ...
103  * }
104  */
105 struct struct_spec {
106         char *name;
107         struct rte_swx_field_params *fields;
108         uint32_t n_fields;
109         int varbit;
110 };
111
112 static void
113 struct_spec_free(struct struct_spec *s)
114 {
115         uint32_t i;
116
117         if (!s)
118                 return;
119
120         free(s->name);
121         s->name = NULL;
122
123         for (i = 0; i < s->n_fields; i++) {
124                 uintptr_t name = (uintptr_t)s->fields[i].name;
125
126                 free((void *)name);
127         }
128
129         free(s->fields);
130         s->fields = NULL;
131
132         s->n_fields = 0;
133
134         s->varbit = 0;
135 }
136
137 static int
138 struct_statement_parse(struct struct_spec *s,
139                        uint32_t *block_mask,
140                        char **tokens,
141                        uint32_t n_tokens,
142                        uint32_t n_lines,
143                        uint32_t *err_line,
144                        const char **err_msg)
145 {
146         /* Check format. */
147         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
148                 if (err_line)
149                         *err_line = n_lines;
150                 if (err_msg)
151                         *err_msg = "Invalid struct statement.";
152                 return -EINVAL;
153         }
154
155         /* spec. */
156         s->name = strdup(tokens[1]);
157         if (!s->name) {
158                 if (err_line)
159                         *err_line = n_lines;
160                 if (err_msg)
161                         *err_msg = "Memory allocation failed.";
162                 return -ENOMEM;
163         }
164
165         /* block_mask. */
166         *block_mask |= 1 << STRUCT_BLOCK;
167
168         return 0;
169 }
170
171 static int
172 struct_block_parse(struct struct_spec *s,
173                    uint32_t *block_mask,
174                    char **tokens,
175                    uint32_t n_tokens,
176                    uint32_t n_lines,
177                    uint32_t *err_line,
178                    const char **err_msg)
179 {
180         struct rte_swx_field_params *new_fields;
181         char *p = tokens[0], *name = NULL;
182         uint32_t n_bits;
183         int varbit = 0, error = 0, error_size_invalid = 0, error_varbit_not_last = 0;
184
185         /* Handle end of block. */
186         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
187                 *block_mask &= ~(1 << STRUCT_BLOCK);
188                 return 0;
189         }
190
191         /* Check format. */
192         if (n_tokens != 2) {
193                 error = -EINVAL;
194                 goto error;
195         }
196
197         if (s->varbit) {
198                 error = -EINVAL;
199                 error_varbit_not_last = 1;
200                 goto error;
201         }
202
203         if (!strncmp(p, "bit<", strlen("bit<"))) {
204                 size_t len = strlen(p);
205
206                 if ((len < strlen("bit< >")) || (p[len - 1] != '>')) {
207                         error = -EINVAL;
208                         goto error;
209                 }
210
211                 /* Remove the "bit<" and ">". */
212                 p[strlen(p) - 1] = 0;
213                 p += strlen("bit<");
214         } else if (!strncmp(p, "varbit<", strlen("varbit<"))) {
215                 size_t len = strlen(p);
216
217                 if ((len < strlen("varbit< >")) || (p[len - 1] != '>')) {
218                         error = -EINVAL;
219                         goto error;
220                 }
221
222                 /* Remove the "varbit<" and ">". */
223                 p[strlen(p) - 1] = 0;
224                 p += strlen("varbit<");
225
226                 /* Set the varbit flag. */
227                 varbit = 1;
228         } else {
229                 error = -EINVAL;
230                 goto error;
231         }
232
233         n_bits = strtoul(p, &p, 0);
234         if ((p[0]) ||
235             !n_bits ||
236             (n_bits % 8) ||
237             ((n_bits > 64) && !varbit)) {
238                 error = -EINVAL;
239                 error_size_invalid = 1;
240                 goto error;
241         }
242
243         /* spec. */
244         name = strdup(tokens[1]);
245         if (!name) {
246                 error = -ENOMEM;
247                 goto error;
248         }
249
250         new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
251         if (!new_fields) {
252                 error = -ENOMEM;
253                 goto error;
254         }
255
256         s->fields = new_fields;
257         s->fields[s->n_fields].name = name;
258         s->fields[s->n_fields].n_bits = n_bits;
259         s->n_fields++;
260         s->varbit = varbit;
261
262         return 0;
263
264 error:
265         free(name);
266
267         if (err_line)
268                 *err_line = n_lines;
269
270         if (err_msg) {
271                 *err_msg = "Invalid struct field statement.";
272
273                 if ((error == -EINVAL) && error_varbit_not_last)
274                         *err_msg = "Varbit field is not the last struct field.";
275
276                 if ((error == -EINVAL) && error_size_invalid)
277                         *err_msg = "Invalid struct field size.";
278
279                 if (error == -ENOMEM)
280                         *err_msg = "Memory allocation failed.";
281         }
282
283         return error;
284 }
285
286 /*
287  * header.
288  *
289  * header HEADER_NAME instanceof STRUCT_TYPE_NAME
290  */
291 struct header_spec {
292         char *name;
293         char *struct_type_name;
294 };
295
296 static void
297 header_spec_free(struct header_spec *s)
298 {
299         if (!s)
300                 return;
301
302         free(s->name);
303         s->name = NULL;
304
305         free(s->struct_type_name);
306         s->struct_type_name = NULL;
307 }
308
309 static int
310 header_statement_parse(struct header_spec *s,
311                        char **tokens,
312                        uint32_t n_tokens,
313                        uint32_t n_lines,
314                        uint32_t *err_line,
315                        const char **err_msg)
316 {
317         /* Check format. */
318         if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
319                 if (err_line)
320                         *err_line = n_lines;
321                 if (err_msg)
322                         *err_msg = "Invalid header statement.";
323                 return -EINVAL;
324         }
325
326         /* spec. */
327         s->name = strdup(tokens[1]);
328         s->struct_type_name = strdup(tokens[3]);
329
330         if (!s->name || !s->struct_type_name) {
331                 free(s->name);
332                 free(s->struct_type_name);
333
334                 if (err_line)
335                         *err_line = n_lines;
336                 if (err_msg)
337                         *err_msg = "Memory allocation failed.";
338                 return -ENOMEM;
339         }
340
341         return 0;
342 }
343
344 /*
345  * metadata.
346  *
347  * metadata instanceof STRUCT_TYPE_NAME
348  */
349 struct metadata_spec {
350         char *struct_type_name;
351 };
352
353 static void
354 metadata_spec_free(struct metadata_spec *s)
355 {
356         if (!s)
357                 return;
358
359         free(s->struct_type_name);
360         s->struct_type_name = NULL;
361 }
362
363 static int
364 metadata_statement_parse(struct metadata_spec *s,
365                          char **tokens,
366                          uint32_t n_tokens,
367                          uint32_t n_lines,
368                          uint32_t *err_line,
369                          const char **err_msg)
370 {
371         /* Check format. */
372         if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
373                 if (err_line)
374                         *err_line = n_lines;
375                 if (err_msg)
376                         *err_msg = "Invalid metadata statement.";
377                 return -EINVAL;
378         }
379
380         /* spec. */
381         s->struct_type_name = strdup(tokens[2]);
382         if (!s->struct_type_name) {
383                 if (err_line)
384                         *err_line = n_lines;
385                 if (err_msg)
386                         *err_msg = "Memory allocation failed.";
387                 return -ENOMEM;
388         }
389
390         return 0;
391 }
392
393 /*
394  * action.
395  *
396  * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
397  *      INSTRUCTION
398  *      ...
399  * }
400  */
401 struct action_spec {
402         char *name;
403         char *args_struct_type_name;
404         const char **instructions;
405         uint32_t n_instructions;
406 };
407
408 static void
409 action_spec_free(struct action_spec *s)
410 {
411         uint32_t i;
412
413         if (!s)
414                 return;
415
416         free(s->name);
417         s->name = NULL;
418
419         free(s->args_struct_type_name);
420         s->args_struct_type_name = NULL;
421
422         for (i = 0; i < s->n_instructions; i++) {
423                 uintptr_t instr = (uintptr_t)s->instructions[i];
424
425                 free((void *)instr);
426         }
427
428         free(s->instructions);
429         s->instructions = NULL;
430
431         s->n_instructions = 0;
432 }
433
434 static int
435 action_statement_parse(struct action_spec *s,
436                        uint32_t *block_mask,
437                        char **tokens,
438                        uint32_t n_tokens,
439                        uint32_t n_lines,
440                        uint32_t *err_line,
441                        const char **err_msg)
442 {
443         /* Check format. */
444         if (((n_tokens != 5) && (n_tokens != 6)) ||
445             ((n_tokens == 5) &&
446              (strcmp(tokens[2], "args") ||
447               strcmp(tokens[3], "none") ||
448               strcmp(tokens[4], "{"))) ||
449             ((n_tokens == 6) &&
450              (strcmp(tokens[2], "args") ||
451               strcmp(tokens[3], "instanceof") ||
452               strcmp(tokens[5], "{")))) {
453                 if (err_line)
454                         *err_line = n_lines;
455                 if (err_msg)
456                         *err_msg = "Invalid action statement.";
457                 return -EINVAL;
458         }
459
460         /* spec. */
461         s->name = strdup(tokens[1]);
462         s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
463
464         if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
465                 if (err_line)
466                         *err_line = n_lines;
467                 if (err_msg)
468                         *err_msg = "Memory allocation failed.";
469                 return -ENOMEM;
470         }
471
472         /* block_mask. */
473         *block_mask |= 1 << ACTION_BLOCK;
474
475         return 0;
476 }
477
478 static int
479 action_block_parse(struct action_spec *s,
480                    uint32_t *block_mask,
481                    char **tokens,
482                    uint32_t n_tokens,
483                    uint32_t n_lines,
484                    uint32_t *err_line,
485                    const char **err_msg)
486 {
487         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
488         const char **new_instructions;
489         uint32_t i;
490
491         /* Handle end of block. */
492         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
493                 *block_mask &= ~(1 << ACTION_BLOCK);
494                 return 0;
495         }
496
497         /* spec. */
498         buffer[0] = 0;
499         for (i = 0; i < n_tokens; i++) {
500                 if (i)
501                         strcat(buffer, " ");
502                 strcat(buffer, tokens[i]);
503         }
504
505         instr = strdup(buffer);
506         if (!instr) {
507                 if (err_line)
508                         *err_line = n_lines;
509                 if (err_msg)
510                         *err_msg = "Memory allocation failed.";
511                 return -ENOMEM;
512         }
513
514         new_instructions = realloc(s->instructions,
515                                    (s->n_instructions + 1) * sizeof(char *));
516         if (!new_instructions) {
517                 free(instr);
518
519                 if (err_line)
520                         *err_line = n_lines;
521                 if (err_msg)
522                         *err_msg = "Memory allocation failed.";
523                 return -ENOMEM;
524         }
525
526         s->instructions = new_instructions;
527         s->instructions[s->n_instructions] = instr;
528         s->n_instructions++;
529
530         return 0;
531 }
532
533 /*
534  * table.
535  *
536  * table {
537  *      key {
538  *              MATCH_FIELD_NAME exact | wildcard | lpm
539  *              ...
540  *      }
541  *      actions {
542  *              ACTION_NAME
543  *              ...
544  *      }
545  *      default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
546  *      instanceof TABLE_TYPE_NAME
547  *      pragma ARGS
548  *      size SIZE
549  * }
550  */
551 struct table_spec {
552         char *name;
553         struct rte_swx_pipeline_table_params params;
554         char *recommended_table_type_name;
555         char *args;
556         uint32_t size;
557 };
558
559 static void
560 table_spec_free(struct table_spec *s)
561 {
562         uintptr_t default_action_name;
563         uint32_t i;
564
565         if (!s)
566                 return;
567
568         free(s->name);
569         s->name = NULL;
570
571         for (i = 0; i < s->params.n_fields; i++) {
572                 uintptr_t name = (uintptr_t)s->params.fields[i].name;
573
574                 free((void *)name);
575         }
576
577         free(s->params.fields);
578         s->params.fields = NULL;
579
580         s->params.n_fields = 0;
581
582         for (i = 0; i < s->params.n_actions; i++) {
583                 uintptr_t name = (uintptr_t)s->params.action_names[i];
584
585                 free((void *)name);
586         }
587
588         free(s->params.action_names);
589         s->params.action_names = NULL;
590
591         s->params.n_actions = 0;
592
593         default_action_name = (uintptr_t)s->params.default_action_name;
594         free((void *)default_action_name);
595         s->params.default_action_name = NULL;
596
597         free(s->params.default_action_data);
598         s->params.default_action_data = NULL;
599
600         s->params.default_action_is_const = 0;
601
602         free(s->recommended_table_type_name);
603         s->recommended_table_type_name = NULL;
604
605         free(s->args);
606         s->args = NULL;
607
608         s->size = 0;
609 }
610
611 static int
612 table_key_statement_parse(uint32_t *block_mask,
613                           char **tokens,
614                           uint32_t n_tokens,
615                           uint32_t n_lines,
616                           uint32_t *err_line,
617                           const char **err_msg)
618 {
619         /* Check format. */
620         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
621                 if (err_line)
622                         *err_line = n_lines;
623                 if (err_msg)
624                         *err_msg = "Invalid key statement.";
625                 return -EINVAL;
626         }
627
628         /* block_mask. */
629         *block_mask |= 1 << TABLE_KEY_BLOCK;
630
631         return 0;
632 }
633
634 static int
635 table_key_block_parse(struct table_spec *s,
636                       uint32_t *block_mask,
637                       char **tokens,
638                       uint32_t n_tokens,
639                       uint32_t n_lines,
640                       uint32_t *err_line,
641                       const char **err_msg)
642 {
643         struct rte_swx_match_field_params *new_fields;
644         enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
645         char *name;
646
647         /* Handle end of block. */
648         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
649                 *block_mask &= ~(1 << TABLE_KEY_BLOCK);
650                 return 0;
651         }
652
653         /* Check input arguments. */
654         if ((n_tokens != 2) ||
655             (strcmp(tokens[1], "exact") &&
656              strcmp(tokens[1], "wildcard") &&
657              strcmp(tokens[1], "lpm"))) {
658                 if (err_line)
659                         *err_line = n_lines;
660                 if (err_msg)
661                         *err_msg = "Invalid match field statement.";
662                 return -EINVAL;
663         }
664
665         if (!strcmp(tokens[1], "wildcard"))
666                 match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
667         if (!strcmp(tokens[1], "lpm"))
668                 match_type = RTE_SWX_TABLE_MATCH_LPM;
669         if (!strcmp(tokens[1], "exact"))
670                 match_type = RTE_SWX_TABLE_MATCH_EXACT;
671
672         name = strdup(tokens[0]);
673         if (!name) {
674                 if (err_line)
675                         *err_line = n_lines;
676                 if (err_msg)
677                         *err_msg = "Memory allocation failed.";
678                 return -ENOMEM;
679         }
680
681         new_fields = realloc(s->params.fields,
682                              (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
683         if (!new_fields) {
684                 free(name);
685
686                 if (err_line)
687                         *err_line = n_lines;
688                 if (err_msg)
689                         *err_msg = "Memory allocation failed.";
690                 return -ENOMEM;
691         }
692
693         s->params.fields = new_fields;
694         s->params.fields[s->params.n_fields].name = name;
695         s->params.fields[s->params.n_fields].match_type = match_type;
696         s->params.n_fields++;
697
698         return 0;
699 }
700
701 static int
702 table_actions_statement_parse(uint32_t *block_mask,
703                               char **tokens,
704                               uint32_t n_tokens,
705                               uint32_t n_lines,
706                               uint32_t *err_line,
707                               const char **err_msg)
708 {
709         /* Check format. */
710         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
711                 if (err_line)
712                         *err_line = n_lines;
713                 if (err_msg)
714                         *err_msg = "Invalid actions statement.";
715                 return -EINVAL;
716         }
717
718         /* block_mask. */
719         *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
720
721         return 0;
722 }
723
724 static int
725 table_actions_block_parse(struct table_spec *s,
726                           uint32_t *block_mask,
727                           char **tokens,
728                           uint32_t n_tokens,
729                           uint32_t n_lines,
730                           uint32_t *err_line,
731                           const char **err_msg)
732 {
733         const char **new_action_names;
734         char *name;
735
736         /* Handle end of block. */
737         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
738                 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
739                 return 0;
740         }
741
742         /* Check input arguments. */
743         if (n_tokens != 1) {
744                 if (err_line)
745                         *err_line = n_lines;
746                 if (err_msg)
747                         *err_msg = "Invalid action name statement.";
748                 return -EINVAL;
749         }
750
751         name = strdup(tokens[0]);
752         if (!name) {
753                 if (err_line)
754                         *err_line = n_lines;
755                 if (err_msg)
756                         *err_msg = "Memory allocation failed.";
757                 return -ENOMEM;
758         }
759
760         new_action_names = realloc(s->params.action_names,
761                                    (s->params.n_actions + 1) * sizeof(char *));
762         if (!new_action_names) {
763                 free(name);
764
765                 if (err_line)
766                         *err_line = n_lines;
767                 if (err_msg)
768                         *err_msg = "Memory allocation failed.";
769                 return -ENOMEM;
770         }
771
772         s->params.action_names = new_action_names;
773         s->params.action_names[s->params.n_actions] = name;
774         s->params.n_actions++;
775
776         return 0;
777 }
778
779 static int
780 table_statement_parse(struct table_spec *s,
781                       uint32_t *block_mask,
782                       char **tokens,
783                       uint32_t n_tokens,
784                       uint32_t n_lines,
785                       uint32_t *err_line,
786                       const char **err_msg)
787 {
788         /* Check format. */
789         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
790                 if (err_line)
791                         *err_line = n_lines;
792                 if (err_msg)
793                         *err_msg = "Invalid table statement.";
794                 return -EINVAL;
795         }
796
797         /* spec. */
798         s->name = strdup(tokens[1]);
799         if (!s->name) {
800                 if (err_line)
801                         *err_line = n_lines;
802                 if (err_msg)
803                         *err_msg = "Memory allocation failed.";
804                 return -ENOMEM;
805         }
806
807         /* block_mask. */
808         *block_mask |= 1 << TABLE_BLOCK;
809
810         return 0;
811 }
812
813 static int
814 table_block_parse(struct table_spec *s,
815                   uint32_t *block_mask,
816                   char **tokens,
817                   uint32_t n_tokens,
818                   uint32_t n_lines,
819                   uint32_t *err_line,
820                   const char **err_msg)
821 {
822         if (*block_mask & (1 << TABLE_KEY_BLOCK))
823                 return table_key_block_parse(s,
824                                              block_mask,
825                                              tokens,
826                                              n_tokens,
827                                              n_lines,
828                                              err_line,
829                                              err_msg);
830
831         if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
832                 return table_actions_block_parse(s,
833                                                  block_mask,
834                                                  tokens,
835                                                  n_tokens,
836                                                  n_lines,
837                                                  err_line,
838                                                  err_msg);
839
840         /* Handle end of block. */
841         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
842                 *block_mask &= ~(1 << TABLE_BLOCK);
843                 return 0;
844         }
845
846         if (!strcmp(tokens[0], "key"))
847                 return table_key_statement_parse(block_mask,
848                                                  tokens,
849                                                  n_tokens,
850                                                  n_lines,
851                                                  err_line,
852                                                  err_msg);
853
854         if (!strcmp(tokens[0], "actions"))
855                 return table_actions_statement_parse(block_mask,
856                                                      tokens,
857                                                      n_tokens,
858                                                      n_lines,
859                                                      err_line,
860                                                      err_msg);
861
862         if (!strcmp(tokens[0], "default_action")) {
863                 if (((n_tokens != 4) && (n_tokens != 5)) ||
864                     strcmp(tokens[2], "args") ||
865                     strcmp(tokens[3], "none") ||
866                     ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
867                         if (err_line)
868                                 *err_line = n_lines;
869                         if (err_msg)
870                                 *err_msg = "Invalid default_action statement.";
871                         return -EINVAL;
872                 }
873
874                 if (s->params.default_action_name) {
875                         if (err_line)
876                                 *err_line = n_lines;
877                         if (err_msg)
878                                 *err_msg = "Duplicate default_action stmt.";
879                         return -EINVAL;
880                 }
881
882                 s->params.default_action_name = strdup(tokens[1]);
883                 if (!s->params.default_action_name) {
884                         if (err_line)
885                                 *err_line = n_lines;
886                         if (err_msg)
887                                 *err_msg = "Memory allocation failed.";
888                         return -ENOMEM;
889                 }
890
891                 if (n_tokens == 5)
892                         s->params.default_action_is_const = 1;
893
894                 return 0;
895         }
896
897         if (!strcmp(tokens[0], "instanceof")) {
898                 if (n_tokens != 2) {
899                         if (err_line)
900                                 *err_line = n_lines;
901                         if (err_msg)
902                                 *err_msg = "Invalid instanceof statement.";
903                         return -EINVAL;
904                 }
905
906                 if (s->recommended_table_type_name) {
907                         if (err_line)
908                                 *err_line = n_lines;
909                         if (err_msg)
910                                 *err_msg = "Duplicate instanceof statement.";
911                         return -EINVAL;
912                 }
913
914                 s->recommended_table_type_name = strdup(tokens[1]);
915                 if (!s->recommended_table_type_name) {
916                         if (err_line)
917                                 *err_line = n_lines;
918                         if (err_msg)
919                                 *err_msg = "Memory allocation failed.";
920                         return -ENOMEM;
921                 }
922
923                 return 0;
924         }
925
926         if (!strcmp(tokens[0], "pragma")) {
927                 if (n_tokens != 2) {
928                         if (err_line)
929                                 *err_line = n_lines;
930                         if (err_msg)
931                                 *err_msg = "Invalid pragma statement.";
932                         return -EINVAL;
933                 }
934
935                 if (s->args) {
936                         if (err_line)
937                                 *err_line = n_lines;
938                         if (err_msg)
939                                 *err_msg = "Duplicate pragma statement.";
940                         return -EINVAL;
941                 }
942
943                 s->args = strdup(tokens[1]);
944                 if (!s->args) {
945                         if (err_line)
946                                 *err_line = n_lines;
947                         if (err_msg)
948                                 *err_msg = "Memory allocation failed.";
949                         return -ENOMEM;
950                 }
951
952                 return 0;
953         }
954
955         if (!strcmp(tokens[0], "size")) {
956                 char *p = tokens[1];
957
958                 if (n_tokens != 2) {
959                         if (err_line)
960                                 *err_line = n_lines;
961                         if (err_msg)
962                                 *err_msg = "Invalid pragma statement.";
963                         return -EINVAL;
964                 }
965
966                 s->size = strtoul(p, &p, 0);
967                 if (p[0]) {
968                         if (err_line)
969                                 *err_line = n_lines;
970                         if (err_msg)
971                                 *err_msg = "Invalid size argument.";
972                         return -EINVAL;
973                 }
974
975                 return 0;
976         }
977
978         /* Anything else. */
979         if (err_line)
980                 *err_line = n_lines;
981         if (err_msg)
982                 *err_msg = "Invalid statement.";
983         return -EINVAL;
984 }
985
986 /*
987  * selector.
988  *
989  * selector SELECTOR_NAME {
990  *      group_id FIELD_NAME
991  *      selector {
992  *              FIELD_NAME
993  *              ...
994  *      }
995  *      member_id FIELD_NAME
996  *      n_groups N_GROUPS
997  *      n_members_per_group N_MEMBERS_PER_GROUP
998  * }
999  */
1000 struct selector_spec {
1001         char *name;
1002         struct rte_swx_pipeline_selector_params params;
1003 };
1004
1005 static void
1006 selector_spec_free(struct selector_spec *s)
1007 {
1008         uintptr_t field_name;
1009         uint32_t i;
1010
1011         if (!s)
1012                 return;
1013
1014         /* name. */
1015         free(s->name);
1016         s->name = NULL;
1017
1018         /* params->group_id_field_name. */
1019         field_name = (uintptr_t)s->params.group_id_field_name;
1020         free((void *)field_name);
1021         s->params.group_id_field_name = NULL;
1022
1023         /* params->selector_field_names. */
1024         for (i = 0; i < s->params.n_selector_fields; i++) {
1025                 field_name = (uintptr_t)s->params.selector_field_names[i];
1026
1027                 free((void *)field_name);
1028         }
1029
1030         free(s->params.selector_field_names);
1031         s->params.selector_field_names = NULL;
1032
1033         s->params.n_selector_fields = 0;
1034
1035         /* params->member_id_field_name. */
1036         field_name = (uintptr_t)s->params.member_id_field_name;
1037         free((void *)field_name);
1038         s->params.member_id_field_name = NULL;
1039
1040         /* params->n_groups_max. */
1041         s->params.n_groups_max = 0;
1042
1043         /* params->n_members_per_group_max. */
1044         s->params.n_members_per_group_max = 0;
1045 }
1046
1047 static int
1048 selector_statement_parse(struct selector_spec *s,
1049                          uint32_t *block_mask,
1050                          char **tokens,
1051                          uint32_t n_tokens,
1052                          uint32_t n_lines,
1053                          uint32_t *err_line,
1054                          const char **err_msg)
1055 {
1056         /* Check format. */
1057         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1058                 if (err_line)
1059                         *err_line = n_lines;
1060                 if (err_msg)
1061                         *err_msg = "Invalid selector statement.";
1062                 return -EINVAL;
1063         }
1064
1065         /* spec. */
1066         s->name = strdup(tokens[1]);
1067         if (!s->name) {
1068                 if (err_line)
1069                         *err_line = n_lines;
1070                 if (err_msg)
1071                         *err_msg = "Memory allocation failed.";
1072                 return -ENOMEM;
1073         }
1074
1075         /* block_mask. */
1076         *block_mask |= 1 << SELECTOR_BLOCK;
1077
1078         return 0;
1079 }
1080
1081 static int
1082 selector_selector_statement_parse(uint32_t *block_mask,
1083                                   char **tokens,
1084                                   uint32_t n_tokens,
1085                                   uint32_t n_lines,
1086                                   uint32_t *err_line,
1087                                   const char **err_msg)
1088 {
1089         /* Check format. */
1090         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1091                 if (err_line)
1092                         *err_line = n_lines;
1093                 if (err_msg)
1094                         *err_msg = "Invalid selector statement.";
1095                 return -EINVAL;
1096         }
1097
1098         /* block_mask. */
1099         *block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
1100
1101         return 0;
1102 }
1103
1104 static int
1105 selector_selector_block_parse(struct selector_spec *s,
1106                               uint32_t *block_mask,
1107                               char **tokens,
1108                               uint32_t n_tokens,
1109                               uint32_t n_lines,
1110                               uint32_t *err_line,
1111                               const char **err_msg)
1112 {
1113         const char **new_fields;
1114         char *name;
1115
1116         /* Handle end of block. */
1117         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1118                 *block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
1119                 return 0;
1120         }
1121
1122         /* Check input arguments. */
1123         if (n_tokens != 1) {
1124                 if (err_line)
1125                         *err_line = n_lines;
1126                 if (err_msg)
1127                         *err_msg = "Invalid selector field statement.";
1128                 return -EINVAL;
1129         }
1130
1131         name = strdup(tokens[0]);
1132         if (!name) {
1133                 if (err_line)
1134                         *err_line = n_lines;
1135                 if (err_msg)
1136                         *err_msg = "Memory allocation failed.";
1137                 return -ENOMEM;
1138         }
1139
1140         new_fields = realloc(s->params.selector_field_names,
1141                              (s->params.n_selector_fields + 1) * sizeof(char *));
1142         if (!new_fields) {
1143                 free(name);
1144
1145                 if (err_line)
1146                         *err_line = n_lines;
1147                 if (err_msg)
1148                         *err_msg = "Memory allocation failed.";
1149                 return -ENOMEM;
1150         }
1151
1152         s->params.selector_field_names = new_fields;
1153         s->params.selector_field_names[s->params.n_selector_fields] = name;
1154         s->params.n_selector_fields++;
1155
1156         return 0;
1157 }
1158
1159 static int
1160 selector_block_parse(struct selector_spec *s,
1161                      uint32_t *block_mask,
1162                      char **tokens,
1163                      uint32_t n_tokens,
1164                      uint32_t n_lines,
1165                      uint32_t *err_line,
1166                      const char **err_msg)
1167 {
1168         if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK))
1169                 return selector_selector_block_parse(s,
1170                                                      block_mask,
1171                                                      tokens,
1172                                                      n_tokens,
1173                                                      n_lines,
1174                                                      err_line,
1175                                                      err_msg);
1176
1177         /* Handle end of block. */
1178         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1179                 *block_mask &= ~(1 << SELECTOR_BLOCK);
1180                 return 0;
1181         }
1182
1183         if (!strcmp(tokens[0], "group_id")) {
1184                 if (n_tokens != 2) {
1185                         if (err_line)
1186                                 *err_line = n_lines;
1187                         if (err_msg)
1188                                 *err_msg = "Invalid group_id statement.";
1189                         return -EINVAL;
1190                 }
1191
1192                 s->params.group_id_field_name = strdup(tokens[1]);
1193                 if (!s->params.group_id_field_name) {
1194                         if (err_line)
1195                                 *err_line = n_lines;
1196                         if (err_msg)
1197                                 *err_msg = "Memory allocation failed.";
1198                         return -ENOMEM;
1199                 }
1200
1201                 return 0;
1202         }
1203
1204         if (!strcmp(tokens[0], "selector"))
1205                 return selector_selector_statement_parse(block_mask,
1206                                                          tokens,
1207                                                          n_tokens,
1208                                                          n_lines,
1209                                                          err_line,
1210                                                          err_msg);
1211
1212         if (!strcmp(tokens[0], "member_id")) {
1213                 if (n_tokens != 2) {
1214                         if (err_line)
1215                                 *err_line = n_lines;
1216                         if (err_msg)
1217                                 *err_msg = "Invalid member_id statement.";
1218                         return -EINVAL;
1219                 }
1220
1221                 s->params.member_id_field_name = strdup(tokens[1]);
1222                 if (!s->params.member_id_field_name) {
1223                         if (err_line)
1224                                 *err_line = n_lines;
1225                         if (err_msg)
1226                                 *err_msg = "Memory allocation failed.";
1227                         return -ENOMEM;
1228                 }
1229
1230                 return 0;
1231         }
1232
1233         if (!strcmp(tokens[0], "n_groups_max")) {
1234                 char *p = tokens[1];
1235
1236                 if (n_tokens != 2) {
1237                         if (err_line)
1238                                 *err_line = n_lines;
1239                         if (err_msg)
1240                                 *err_msg = "Invalid n_groups statement.";
1241                         return -EINVAL;
1242                 }
1243
1244                 s->params.n_groups_max = strtoul(p, &p, 0);
1245                 if (p[0]) {
1246                         if (err_line)
1247                                 *err_line = n_lines;
1248                         if (err_msg)
1249                                 *err_msg = "Invalid n_groups argument.";
1250                         return -EINVAL;
1251                 }
1252
1253                 return 0;
1254         }
1255
1256         if (!strcmp(tokens[0], "n_members_per_group_max")) {
1257                 char *p = tokens[1];
1258
1259                 if (n_tokens != 2) {
1260                         if (err_line)
1261                                 *err_line = n_lines;
1262                         if (err_msg)
1263                                 *err_msg = "Invalid n_members_per_group statement.";
1264                         return -EINVAL;
1265                 }
1266
1267                 s->params.n_members_per_group_max = strtoul(p, &p, 0);
1268                 if (p[0]) {
1269                         if (err_line)
1270                                 *err_line = n_lines;
1271                         if (err_msg)
1272                                 *err_msg = "Invalid n_members_per_group argument.";
1273                         return -EINVAL;
1274                 }
1275
1276                 return 0;
1277         }
1278
1279         /* Anything else. */
1280         if (err_line)
1281                 *err_line = n_lines;
1282         if (err_msg)
1283                 *err_msg = "Invalid statement.";
1284         return -EINVAL;
1285 }
1286
1287 /*
1288  * learner.
1289  *
1290  * learner {
1291  *      key {
1292  *              MATCH_FIELD_NAME
1293  *              ...
1294  *      }
1295  *      actions {
1296  *              ACTION_NAME
1297  *              ...
1298  *      }
1299  *      default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
1300  *      size SIZE
1301  *      timeout TIMEOUT_IN_SECONDS
1302  * }
1303  */
1304 struct learner_spec {
1305         char *name;
1306         struct rte_swx_pipeline_learner_params params;
1307         uint32_t size;
1308         uint32_t timeout;
1309 };
1310
1311 static void
1312 learner_spec_free(struct learner_spec *s)
1313 {
1314         uintptr_t default_action_name;
1315         uint32_t i;
1316
1317         if (!s)
1318                 return;
1319
1320         free(s->name);
1321         s->name = NULL;
1322
1323         for (i = 0; i < s->params.n_fields; i++) {
1324                 uintptr_t name = (uintptr_t)s->params.field_names[i];
1325
1326                 free((void *)name);
1327         }
1328
1329         free(s->params.field_names);
1330         s->params.field_names = NULL;
1331
1332         s->params.n_fields = 0;
1333
1334         for (i = 0; i < s->params.n_actions; i++) {
1335                 uintptr_t name = (uintptr_t)s->params.action_names[i];
1336
1337                 free((void *)name);
1338         }
1339
1340         free(s->params.action_names);
1341         s->params.action_names = NULL;
1342
1343         s->params.n_actions = 0;
1344
1345         default_action_name = (uintptr_t)s->params.default_action_name;
1346         free((void *)default_action_name);
1347         s->params.default_action_name = NULL;
1348
1349         free(s->params.default_action_data);
1350         s->params.default_action_data = NULL;
1351
1352         s->params.default_action_is_const = 0;
1353
1354         s->size = 0;
1355
1356         s->timeout = 0;
1357 }
1358
1359 static int
1360 learner_key_statement_parse(uint32_t *block_mask,
1361                             char **tokens,
1362                             uint32_t n_tokens,
1363                             uint32_t n_lines,
1364                             uint32_t *err_line,
1365                             const char **err_msg)
1366 {
1367         /* Check format. */
1368         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1369                 if (err_line)
1370                         *err_line = n_lines;
1371                 if (err_msg)
1372                         *err_msg = "Invalid key statement.";
1373                 return -EINVAL;
1374         }
1375
1376         /* block_mask. */
1377         *block_mask |= 1 << LEARNER_KEY_BLOCK;
1378
1379         return 0;
1380 }
1381
1382 static int
1383 learner_key_block_parse(struct learner_spec *s,
1384                         uint32_t *block_mask,
1385                         char **tokens,
1386                         uint32_t n_tokens,
1387                         uint32_t n_lines,
1388                         uint32_t *err_line,
1389                         const char **err_msg)
1390 {
1391         const char **new_field_names = NULL;
1392         char *field_name = NULL;
1393
1394         /* Handle end of block. */
1395         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1396                 *block_mask &= ~(1 << LEARNER_KEY_BLOCK);
1397                 return 0;
1398         }
1399
1400         /* Check input arguments. */
1401         if (n_tokens != 1) {
1402                 if (err_line)
1403                         *err_line = n_lines;
1404                 if (err_msg)
1405                         *err_msg = "Invalid match field statement.";
1406                 return -EINVAL;
1407         }
1408
1409         field_name = strdup(tokens[0]);
1410         new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
1411         if (!field_name || !new_field_names) {
1412                 free(field_name);
1413                 free(new_field_names);
1414
1415                 if (err_line)
1416                         *err_line = n_lines;
1417                 if (err_msg)
1418                         *err_msg = "Memory allocation failed.";
1419                 return -ENOMEM;
1420         }
1421
1422         s->params.field_names = new_field_names;
1423         s->params.field_names[s->params.n_fields] = field_name;
1424         s->params.n_fields++;
1425
1426         return 0;
1427 }
1428
1429 static int
1430 learner_actions_statement_parse(uint32_t *block_mask,
1431                                 char **tokens,
1432                                 uint32_t n_tokens,
1433                                 uint32_t n_lines,
1434                                 uint32_t *err_line,
1435                                 const char **err_msg)
1436 {
1437         /* Check format. */
1438         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1439                 if (err_line)
1440                         *err_line = n_lines;
1441                 if (err_msg)
1442                         *err_msg = "Invalid actions statement.";
1443                 return -EINVAL;
1444         }
1445
1446         /* block_mask. */
1447         *block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
1448
1449         return 0;
1450 }
1451
1452 static int
1453 learner_actions_block_parse(struct learner_spec *s,
1454                             uint32_t *block_mask,
1455                             char **tokens,
1456                             uint32_t n_tokens,
1457                             uint32_t n_lines,
1458                             uint32_t *err_line,
1459                             const char **err_msg)
1460 {
1461         const char **new_action_names = NULL;
1462         char *action_name = NULL;
1463
1464         /* Handle end of block. */
1465         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1466                 *block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
1467                 return 0;
1468         }
1469
1470         /* Check input arguments. */
1471         if (n_tokens != 1) {
1472                 if (err_line)
1473                         *err_line = n_lines;
1474                 if (err_msg)
1475                         *err_msg = "Invalid action name statement.";
1476                 return -EINVAL;
1477         }
1478
1479         action_name = strdup(tokens[0]);
1480
1481         new_action_names = realloc(s->params.action_names,
1482                                    (s->params.n_actions + 1) * sizeof(char *));
1483
1484         if (!action_name || !new_action_names) {
1485                 free(action_name);
1486                 free(new_action_names);
1487
1488                 if (err_line)
1489                         *err_line = n_lines;
1490                 if (err_msg)
1491                         *err_msg = "Memory allocation failed.";
1492                 return -ENOMEM;
1493         }
1494
1495         s->params.action_names = new_action_names;
1496         s->params.action_names[s->params.n_actions] = action_name;
1497         s->params.n_actions++;
1498
1499         return 0;
1500 }
1501
1502 static int
1503 learner_statement_parse(struct learner_spec *s,
1504                       uint32_t *block_mask,
1505                       char **tokens,
1506                       uint32_t n_tokens,
1507                       uint32_t n_lines,
1508                       uint32_t *err_line,
1509                       const char **err_msg)
1510 {
1511         /* Check format. */
1512         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1513                 if (err_line)
1514                         *err_line = n_lines;
1515                 if (err_msg)
1516                         *err_msg = "Invalid learner statement.";
1517                 return -EINVAL;
1518         }
1519
1520         /* spec. */
1521         s->name = strdup(tokens[1]);
1522         if (!s->name) {
1523                 if (err_line)
1524                         *err_line = n_lines;
1525                 if (err_msg)
1526                         *err_msg = "Memory allocation failed.";
1527                 return -ENOMEM;
1528         }
1529
1530         /* block_mask. */
1531         *block_mask |= 1 << LEARNER_BLOCK;
1532
1533         return 0;
1534 }
1535
1536 static int
1537 learner_block_parse(struct learner_spec *s,
1538                     uint32_t *block_mask,
1539                     char **tokens,
1540                     uint32_t n_tokens,
1541                     uint32_t n_lines,
1542                     uint32_t *err_line,
1543                     const char **err_msg)
1544 {
1545         if (*block_mask & (1 << LEARNER_KEY_BLOCK))
1546                 return learner_key_block_parse(s,
1547                                                block_mask,
1548                                                tokens,
1549                                                n_tokens,
1550                                                n_lines,
1551                                                err_line,
1552                                                err_msg);
1553
1554         if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
1555                 return learner_actions_block_parse(s,
1556                                                    block_mask,
1557                                                    tokens,
1558                                                    n_tokens,
1559                                                    n_lines,
1560                                                    err_line,
1561                                                    err_msg);
1562
1563         /* Handle end of block. */
1564         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1565                 *block_mask &= ~(1 << LEARNER_BLOCK);
1566                 return 0;
1567         }
1568
1569         if (!strcmp(tokens[0], "key"))
1570                 return learner_key_statement_parse(block_mask,
1571                                                    tokens,
1572                                                    n_tokens,
1573                                                    n_lines,
1574                                                    err_line,
1575                                                    err_msg);
1576
1577         if (!strcmp(tokens[0], "actions"))
1578                 return learner_actions_statement_parse(block_mask,
1579                                                        tokens,
1580                                                        n_tokens,
1581                                                        n_lines,
1582                                                        err_line,
1583                                                        err_msg);
1584
1585         if (!strcmp(tokens[0], "default_action")) {
1586                 if (((n_tokens != 4) && (n_tokens != 5)) ||
1587                     strcmp(tokens[2], "args") ||
1588                     strcmp(tokens[3], "none") ||
1589                     ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
1590                         if (err_line)
1591                                 *err_line = n_lines;
1592                         if (err_msg)
1593                                 *err_msg = "Invalid default_action statement.";
1594                         return -EINVAL;
1595                 }
1596
1597                 if (s->params.default_action_name) {
1598                         if (err_line)
1599                                 *err_line = n_lines;
1600                         if (err_msg)
1601                                 *err_msg = "Duplicate default_action stmt.";
1602                         return -EINVAL;
1603                 }
1604
1605                 s->params.default_action_name = strdup(tokens[1]);
1606                 if (!s->params.default_action_name) {
1607                         if (err_line)
1608                                 *err_line = n_lines;
1609                         if (err_msg)
1610                                 *err_msg = "Memory allocation failed.";
1611                         return -ENOMEM;
1612                 }
1613
1614                 if (n_tokens == 5)
1615                         s->params.default_action_is_const = 1;
1616
1617                 return 0;
1618         }
1619
1620         if (!strcmp(tokens[0], "size")) {
1621                 char *p = tokens[1];
1622
1623                 if (n_tokens != 2) {
1624                         if (err_line)
1625                                 *err_line = n_lines;
1626                         if (err_msg)
1627                                 *err_msg = "Invalid size statement.";
1628                         return -EINVAL;
1629                 }
1630
1631                 s->size = strtoul(p, &p, 0);
1632                 if (p[0]) {
1633                         if (err_line)
1634                                 *err_line = n_lines;
1635                         if (err_msg)
1636                                 *err_msg = "Invalid size argument.";
1637                         return -EINVAL;
1638                 }
1639
1640                 return 0;
1641         }
1642
1643         if (!strcmp(tokens[0], "timeout")) {
1644                 char *p = tokens[1];
1645
1646                 if (n_tokens != 2) {
1647                         if (err_line)
1648                                 *err_line = n_lines;
1649                         if (err_msg)
1650                                 *err_msg = "Invalid timeout statement.";
1651                         return -EINVAL;
1652                 }
1653
1654                 s->timeout = strtoul(p, &p, 0);
1655                 if (p[0]) {
1656                         if (err_line)
1657                                 *err_line = n_lines;
1658                         if (err_msg)
1659                                 *err_msg = "Invalid timeout argument.";
1660                         return -EINVAL;
1661                 }
1662
1663                 return 0;
1664         }
1665
1666         /* Anything else. */
1667         if (err_line)
1668                 *err_line = n_lines;
1669         if (err_msg)
1670                 *err_msg = "Invalid statement.";
1671         return -EINVAL;
1672 }
1673
1674 /*
1675  * regarray.
1676  *
1677  * regarray NAME size SIZE initval INITVAL
1678  */
1679 struct regarray_spec {
1680         char *name;
1681         uint64_t init_val;
1682         uint32_t size;
1683 };
1684
1685 static void
1686 regarray_spec_free(struct regarray_spec *s)
1687 {
1688         if (!s)
1689                 return;
1690
1691         free(s->name);
1692         s->name = NULL;
1693 }
1694
1695 static int
1696 regarray_statement_parse(struct regarray_spec *s,
1697                          char **tokens,
1698                          uint32_t n_tokens,
1699                          uint32_t n_lines,
1700                          uint32_t *err_line,
1701                          const char **err_msg)
1702 {
1703         char *p;
1704
1705         /* Check format. */
1706         if ((n_tokens != 6) ||
1707              strcmp(tokens[2], "size") ||
1708              strcmp(tokens[4], "initval")) {
1709                 if (err_line)
1710                         *err_line = n_lines;
1711                 if (err_msg)
1712                         *err_msg = "Invalid regarray statement.";
1713                 return -EINVAL;
1714         }
1715
1716         /* spec. */
1717         s->name = strdup(tokens[1]);
1718         if (!s->name) {
1719                 if (err_line)
1720                         *err_line = n_lines;
1721                 if (err_msg)
1722                         *err_msg = "Memory allocation failed.";
1723                 return -ENOMEM;
1724         }
1725
1726         p = tokens[3];
1727         s->size = strtoul(p, &p, 0);
1728         if (p[0] || !s->size) {
1729                 if (err_line)
1730                         *err_line = n_lines;
1731                 if (err_msg)
1732                         *err_msg = "Invalid size argument.";
1733                 return -EINVAL;
1734         }
1735
1736         p = tokens[5];
1737         s->init_val = strtoull(p, &p, 0);
1738         if (p[0]) {
1739                 if (err_line)
1740                         *err_line = n_lines;
1741                 if (err_msg)
1742                         *err_msg = "Invalid initval argument.";
1743                 return -EINVAL;
1744         }
1745
1746         return 0;
1747 }
1748
1749 /*
1750  * metarray.
1751  *
1752  * metarray NAME size SIZE
1753  */
1754 struct metarray_spec {
1755         char *name;
1756         uint32_t size;
1757 };
1758
1759 static void
1760 metarray_spec_free(struct metarray_spec *s)
1761 {
1762         if (!s)
1763                 return;
1764
1765         free(s->name);
1766         s->name = NULL;
1767 }
1768
1769 static int
1770 metarray_statement_parse(struct metarray_spec *s,
1771                          char **tokens,
1772                          uint32_t n_tokens,
1773                          uint32_t n_lines,
1774                          uint32_t *err_line,
1775                          const char **err_msg)
1776 {
1777         char *p;
1778
1779         /* Check format. */
1780         if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
1781                 if (err_line)
1782                         *err_line = n_lines;
1783                 if (err_msg)
1784                         *err_msg = "Invalid metarray statement.";
1785                 return -EINVAL;
1786         }
1787
1788         /* spec. */
1789         s->name = strdup(tokens[1]);
1790         if (!s->name) {
1791                 if (err_line)
1792                         *err_line = n_lines;
1793                 if (err_msg)
1794                         *err_msg = "Memory allocation failed.";
1795                 return -ENOMEM;
1796         }
1797
1798         p = tokens[3];
1799         s->size = strtoul(p, &p, 0);
1800         if (p[0] || !s->size) {
1801                 if (err_line)
1802                         *err_line = n_lines;
1803                 if (err_msg)
1804                         *err_msg = "Invalid size argument.";
1805                 return -EINVAL;
1806         }
1807
1808         return 0;
1809 }
1810
1811 /*
1812  * apply.
1813  *
1814  * apply {
1815  *      INSTRUCTION
1816  *      ...
1817  * }
1818  */
1819 struct apply_spec {
1820         const char **instructions;
1821         uint32_t n_instructions;
1822 };
1823
1824 static void
1825 apply_spec_free(struct apply_spec *s)
1826 {
1827         uint32_t i;
1828
1829         if (!s)
1830                 return;
1831
1832         for (i = 0; i < s->n_instructions; i++) {
1833                 uintptr_t instr = (uintptr_t)s->instructions[i];
1834
1835                 free((void *)instr);
1836         }
1837
1838         free(s->instructions);
1839         s->instructions = NULL;
1840
1841         s->n_instructions = 0;
1842 }
1843
1844 static int
1845 apply_statement_parse(uint32_t *block_mask,
1846                       char **tokens,
1847                       uint32_t n_tokens,
1848                       uint32_t n_lines,
1849                       uint32_t *err_line,
1850                       const char **err_msg)
1851 {
1852         /* Check format. */
1853         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1854                 if (err_line)
1855                         *err_line = n_lines;
1856                 if (err_msg)
1857                         *err_msg = "Invalid apply statement.";
1858                 return -EINVAL;
1859         }
1860
1861         /* block_mask. */
1862         *block_mask |= 1 << APPLY_BLOCK;
1863
1864         return 0;
1865 }
1866
1867 static int
1868 apply_block_parse(struct apply_spec *s,
1869                   uint32_t *block_mask,
1870                   char **tokens,
1871                   uint32_t n_tokens,
1872                   uint32_t n_lines,
1873                   uint32_t *err_line,
1874                   const char **err_msg)
1875 {
1876         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1877         const char **new_instructions;
1878         uint32_t i;
1879
1880         /* Handle end of block. */
1881         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1882                 *block_mask &= ~(1 << APPLY_BLOCK);
1883                 return 0;
1884         }
1885
1886         /* spec. */
1887         buffer[0] = 0;
1888         for (i = 0; i < n_tokens; i++) {
1889                 if (i)
1890                         strcat(buffer, " ");
1891                 strcat(buffer, tokens[i]);
1892         }
1893
1894         instr = strdup(buffer);
1895         if (!instr) {
1896                 if (err_line)
1897                         *err_line = n_lines;
1898                 if (err_msg)
1899                         *err_msg = "Memory allocation failed.";
1900                 return -ENOMEM;
1901         }
1902
1903         new_instructions = realloc(s->instructions,
1904                                    (s->n_instructions + 1) * sizeof(char *));
1905         if (!new_instructions) {
1906                 free(instr);
1907
1908                 if (err_line)
1909                         *err_line = n_lines;
1910                 if (err_msg)
1911                         *err_msg = "Memory allocation failed.";
1912                 return -ENOMEM;
1913         }
1914
1915         s->instructions = new_instructions;
1916         s->instructions[s->n_instructions] = instr;
1917         s->n_instructions++;
1918
1919         return 0;
1920 }
1921
1922 /*
1923  * Pipeline.
1924  */
1925 int
1926 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1927                                  FILE *spec,
1928                                  uint32_t *err_line,
1929                                  const char **err_msg)
1930 {
1931         struct extobj_spec extobj_spec = {0};
1932         struct struct_spec struct_spec = {0};
1933         struct header_spec header_spec = {0};
1934         struct metadata_spec metadata_spec = {0};
1935         struct action_spec action_spec = {0};
1936         struct table_spec table_spec = {0};
1937         struct selector_spec selector_spec = {0};
1938         struct learner_spec learner_spec = {0};
1939         struct regarray_spec regarray_spec = {0};
1940         struct metarray_spec metarray_spec = {0};
1941         struct apply_spec apply_spec = {0};
1942         uint32_t n_lines;
1943         uint32_t block_mask = 0;
1944         int status;
1945
1946         /* Check the input arguments. */
1947         if (!p) {
1948                 if (err_line)
1949                         *err_line = 0;
1950                 if (err_msg)
1951                         *err_msg = "Null pipeline arument.";
1952                 status = -EINVAL;
1953                 goto error;
1954         }
1955
1956         if (!spec) {
1957                 if (err_line)
1958                         *err_line = 0;
1959                 if (err_msg)
1960                         *err_msg = "Null specification file argument.";
1961                 status = -EINVAL;
1962                 goto error;
1963         }
1964
1965         for (n_lines = 1; ; n_lines++) {
1966                 char line[MAX_LINE_LENGTH];
1967                 char *tokens[MAX_TOKENS], *ptr = line;
1968                 uint32_t n_tokens = 0;
1969
1970                 /* Read next line. */
1971                 if (!fgets(line, sizeof(line), spec))
1972                         break;
1973
1974                 /* Parse the line into tokens. */
1975                 for ( ; ; ) {
1976                         char *token;
1977
1978                         /* Get token. */
1979                         token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1980                         if (!token)
1981                                 break;
1982
1983                         /* Handle comments. */
1984                         if ((token[0] == '#') ||
1985                             (token[0] == ';') ||
1986                             ((token[0] == '/') && (token[1] == '/'))) {
1987                                 break;
1988                         }
1989
1990                         /* Handle excessively long lines. */
1991                         if (n_tokens >= MAX_TOKENS) {
1992                                 if (err_line)
1993                                         *err_line = n_lines;
1994                                 if (err_msg)
1995                                         *err_msg = "Too many tokens.";
1996                                 status = -EINVAL;
1997                                 goto error;
1998                         }
1999
2000                         /* Handle excessively long tokens. */
2001                         if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2002                             RTE_SWX_NAME_SIZE) {
2003                                 if (err_line)
2004                                         *err_line = n_lines;
2005                                 if (err_msg)
2006                                         *err_msg = "Token too big.";
2007                                 status = -EINVAL;
2008                                 goto error;
2009                         }
2010
2011                         /* Save token. */
2012                         tokens[n_tokens] = token;
2013                         n_tokens++;
2014                 }
2015
2016                 /* Handle empty lines. */
2017                 if (!n_tokens)
2018                         continue;
2019
2020                 /* struct block. */
2021                 if (block_mask & (1 << STRUCT_BLOCK)) {
2022                         status = struct_block_parse(&struct_spec,
2023                                                     &block_mask,
2024                                                     tokens,
2025                                                     n_tokens,
2026                                                     n_lines,
2027                                                     err_line,
2028                                                     err_msg);
2029                         if (status)
2030                                 goto error;
2031
2032                         if (block_mask & (1 << STRUCT_BLOCK))
2033                                 continue;
2034
2035                         /* End of block. */
2036                         status = rte_swx_pipeline_struct_type_register(p,
2037                                 struct_spec.name,
2038                                 struct_spec.fields,
2039                                 struct_spec.n_fields,
2040                                 struct_spec.varbit);
2041                         if (status) {
2042                                 if (err_line)
2043                                         *err_line = n_lines;
2044                                 if (err_msg)
2045                                         *err_msg = "Struct registration error.";
2046                                 goto error;
2047                         }
2048
2049                         struct_spec_free(&struct_spec);
2050
2051                         continue;
2052                 }
2053
2054                 /* action block. */
2055                 if (block_mask & (1 << ACTION_BLOCK)) {
2056                         status = action_block_parse(&action_spec,
2057                                                     &block_mask,
2058                                                     tokens,
2059                                                     n_tokens,
2060                                                     n_lines,
2061                                                     err_line,
2062                                                     err_msg);
2063                         if (status)
2064                                 goto error;
2065
2066                         if (block_mask & (1 << ACTION_BLOCK))
2067                                 continue;
2068
2069                         /* End of block. */
2070                         status = rte_swx_pipeline_action_config(p,
2071                                 action_spec.name,
2072                                 action_spec.args_struct_type_name,
2073                                 action_spec.instructions,
2074                                 action_spec.n_instructions);
2075                         if (status) {
2076                                 if (err_line)
2077                                         *err_line = n_lines;
2078                                 if (err_msg)
2079                                         *err_msg = "Action config error.";
2080                                 goto error;
2081                         }
2082
2083                         action_spec_free(&action_spec);
2084
2085                         continue;
2086                 }
2087
2088                 /* table block. */
2089                 if (block_mask & (1 << TABLE_BLOCK)) {
2090                         status = table_block_parse(&table_spec,
2091                                                    &block_mask,
2092                                                    tokens,
2093                                                    n_tokens,
2094                                                    n_lines,
2095                                                    err_line,
2096                                                    err_msg);
2097                         if (status)
2098                                 goto error;
2099
2100                         if (block_mask & (1 << TABLE_BLOCK))
2101                                 continue;
2102
2103                         /* End of block. */
2104                         status = rte_swx_pipeline_table_config(p,
2105                                 table_spec.name,
2106                                 &table_spec.params,
2107                                 table_spec.recommended_table_type_name,
2108                                 table_spec.args,
2109                                 table_spec.size);
2110                         if (status) {
2111                                 if (err_line)
2112                                         *err_line = n_lines;
2113                                 if (err_msg)
2114                                         *err_msg = "Table configuration error.";
2115                                 goto error;
2116                         }
2117
2118                         table_spec_free(&table_spec);
2119
2120                         continue;
2121                 }
2122
2123                 /* selector block. */
2124                 if (block_mask & (1 << SELECTOR_BLOCK)) {
2125                         status = selector_block_parse(&selector_spec,
2126                                                       &block_mask,
2127                                                       tokens,
2128                                                       n_tokens,
2129                                                       n_lines,
2130                                                       err_line,
2131                                                       err_msg);
2132                         if (status)
2133                                 goto error;
2134
2135                         if (block_mask & (1 << SELECTOR_BLOCK))
2136                                 continue;
2137
2138                         /* End of block. */
2139                         status = rte_swx_pipeline_selector_config(p,
2140                                 selector_spec.name,
2141                                 &selector_spec.params);
2142                         if (status) {
2143                                 if (err_line)
2144                                         *err_line = n_lines;
2145                                 if (err_msg)
2146                                         *err_msg = "Selector configuration error.";
2147                                 goto error;
2148                         }
2149
2150                         selector_spec_free(&selector_spec);
2151
2152                         continue;
2153                 }
2154
2155                 /* learner block. */
2156                 if (block_mask & (1 << LEARNER_BLOCK)) {
2157                         status = learner_block_parse(&learner_spec,
2158                                                      &block_mask,
2159                                                      tokens,
2160                                                      n_tokens,
2161                                                      n_lines,
2162                                                      err_line,
2163                                                      err_msg);
2164                         if (status)
2165                                 goto error;
2166
2167                         if (block_mask & (1 << LEARNER_BLOCK))
2168                                 continue;
2169
2170                         /* End of block. */
2171                         status = rte_swx_pipeline_learner_config(p,
2172                                 learner_spec.name,
2173                                 &learner_spec.params,
2174                                 learner_spec.size,
2175                                 learner_spec.timeout);
2176                         if (status) {
2177                                 if (err_line)
2178                                         *err_line = n_lines;
2179                                 if (err_msg)
2180                                         *err_msg = "Learner table configuration error.";
2181                                 goto error;
2182                         }
2183
2184                         learner_spec_free(&learner_spec);
2185
2186                         continue;
2187                 }
2188
2189                 /* apply block. */
2190                 if (block_mask & (1 << APPLY_BLOCK)) {
2191                         status = apply_block_parse(&apply_spec,
2192                                                    &block_mask,
2193                                                    tokens,
2194                                                    n_tokens,
2195                                                    n_lines,
2196                                                    err_line,
2197                                                    err_msg);
2198                         if (status)
2199                                 goto error;
2200
2201                         if (block_mask & (1 << APPLY_BLOCK))
2202                                 continue;
2203
2204                         /* End of block. */
2205                         status = rte_swx_pipeline_instructions_config(p,
2206                                 apply_spec.instructions,
2207                                 apply_spec.n_instructions);
2208                         if (status) {
2209                                 if (err_line)
2210                                         *err_line = n_lines;
2211                                 if (err_msg)
2212                                         *err_msg = "Pipeline instructions err.";
2213                                 goto error;
2214                         }
2215
2216                         apply_spec_free(&apply_spec);
2217
2218                         continue;
2219                 }
2220
2221                 /* extobj. */
2222                 if (!strcmp(tokens[0], "extobj")) {
2223                         status = extobj_statement_parse(&extobj_spec,
2224                                                         tokens,
2225                                                         n_tokens,
2226                                                         n_lines,
2227                                                         err_line,
2228                                                         err_msg);
2229                         if (status)
2230                                 goto error;
2231
2232                         status = rte_swx_pipeline_extern_object_config(p,
2233                                 extobj_spec.name,
2234                                 extobj_spec.extern_type_name,
2235                                 extobj_spec.pragma);
2236                         if (status) {
2237                                 if (err_line)
2238                                         *err_line = n_lines;
2239                                 if (err_msg)
2240                                         *err_msg = "Extern object config err.";
2241                                 goto error;
2242                         }
2243
2244                         extobj_spec_free(&extobj_spec);
2245
2246                         continue;
2247                 }
2248
2249                 /* struct. */
2250                 if (!strcmp(tokens[0], "struct")) {
2251                         status = struct_statement_parse(&struct_spec,
2252                                                         &block_mask,
2253                                                         tokens,
2254                                                         n_tokens,
2255                                                         n_lines,
2256                                                         err_line,
2257                                                         err_msg);
2258                         if (status)
2259                                 goto error;
2260
2261                         continue;
2262                 }
2263
2264                 /* header. */
2265                 if (!strcmp(tokens[0], "header")) {
2266                         status = header_statement_parse(&header_spec,
2267                                                         tokens,
2268                                                         n_tokens,
2269                                                         n_lines,
2270                                                         err_line,
2271                                                         err_msg);
2272                         if (status)
2273                                 goto error;
2274
2275                         status = rte_swx_pipeline_packet_header_register(p,
2276                                 header_spec.name,
2277                                 header_spec.struct_type_name);
2278                         if (status) {
2279                                 if (err_line)
2280                                         *err_line = n_lines;
2281                                 if (err_msg)
2282                                         *err_msg = "Header registration error.";
2283                                 goto error;
2284                         }
2285
2286                         header_spec_free(&header_spec);
2287
2288                         continue;
2289                 }
2290
2291                 /* metadata. */
2292                 if (!strcmp(tokens[0], "metadata")) {
2293                         status = metadata_statement_parse(&metadata_spec,
2294                                                           tokens,
2295                                                           n_tokens,
2296                                                           n_lines,
2297                                                           err_line,
2298                                                           err_msg);
2299                         if (status)
2300                                 goto error;
2301
2302                         status = rte_swx_pipeline_packet_metadata_register(p,
2303                                 metadata_spec.struct_type_name);
2304                         if (status) {
2305                                 if (err_line)
2306                                         *err_line = n_lines;
2307                                 if (err_msg)
2308                                         *err_msg = "Meta-data reg err.";
2309                                 goto error;
2310                         }
2311
2312                         metadata_spec_free(&metadata_spec);
2313
2314                         continue;
2315                 }
2316
2317                 /* action. */
2318                 if (!strcmp(tokens[0], "action")) {
2319                         status = action_statement_parse(&action_spec,
2320                                                         &block_mask,
2321                                                         tokens,
2322                                                         n_tokens,
2323                                                         n_lines,
2324                                                         err_line,
2325                                                         err_msg);
2326                         if (status)
2327                                 goto error;
2328
2329                         continue;
2330                 }
2331
2332                 /* table. */
2333                 if (!strcmp(tokens[0], "table")) {
2334                         status = table_statement_parse(&table_spec,
2335                                                        &block_mask,
2336                                                        tokens,
2337                                                        n_tokens,
2338                                                        n_lines,
2339                                                        err_line,
2340                                                        err_msg);
2341                         if (status)
2342                                 goto error;
2343
2344                         continue;
2345                 }
2346
2347                 /* selector. */
2348                 if (!strcmp(tokens[0], "selector")) {
2349                         status = selector_statement_parse(&selector_spec,
2350                                                           &block_mask,
2351                                                           tokens,
2352                                                           n_tokens,
2353                                                           n_lines,
2354                                                           err_line,
2355                                                           err_msg);
2356                         if (status)
2357                                 goto error;
2358
2359                         continue;
2360                 }
2361
2362                 /* learner. */
2363                 if (!strcmp(tokens[0], "learner")) {
2364                         status = learner_statement_parse(&learner_spec,
2365                                                          &block_mask,
2366                                                          tokens,
2367                                                          n_tokens,
2368                                                          n_lines,
2369                                                          err_line,
2370                                                          err_msg);
2371                         if (status)
2372                                 goto error;
2373
2374                         continue;
2375                 }
2376
2377                 /* regarray. */
2378                 if (!strcmp(tokens[0], "regarray")) {
2379                         status = regarray_statement_parse(&regarray_spec,
2380                                                           tokens,
2381                                                           n_tokens,
2382                                                           n_lines,
2383                                                           err_line,
2384                                                           err_msg);
2385                         if (status)
2386                                 goto error;
2387
2388                         status = rte_swx_pipeline_regarray_config(p,
2389                                 regarray_spec.name,
2390                                 regarray_spec.size,
2391                                 regarray_spec.init_val);
2392                         if (status) {
2393                                 if (err_line)
2394                                         *err_line = n_lines;
2395                                 if (err_msg)
2396                                         *err_msg = "Register array configuration error.";
2397                                 goto error;
2398                         }
2399
2400                         regarray_spec_free(&regarray_spec);
2401
2402                         continue;
2403                 }
2404
2405                 /* metarray. */
2406                 if (!strcmp(tokens[0], "metarray")) {
2407                         status = metarray_statement_parse(&metarray_spec,
2408                                                           tokens,
2409                                                           n_tokens,
2410                                                           n_lines,
2411                                                           err_line,
2412                                                           err_msg);
2413                         if (status)
2414                                 goto error;
2415
2416                         status = rte_swx_pipeline_metarray_config(p,
2417                                 metarray_spec.name,
2418                                 metarray_spec.size);
2419                         if (status) {
2420                                 if (err_line)
2421                                         *err_line = n_lines;
2422                                 if (err_msg)
2423                                         *err_msg = "Meter array configuration error.";
2424                                 goto error;
2425                         }
2426
2427                         metarray_spec_free(&metarray_spec);
2428
2429                         continue;
2430                 }
2431
2432                 /* apply. */
2433                 if (!strcmp(tokens[0], "apply")) {
2434                         status = apply_statement_parse(&block_mask,
2435                                                        tokens,
2436                                                        n_tokens,
2437                                                        n_lines,
2438                                                        err_line,
2439                                                        err_msg);
2440                         if (status)
2441                                 goto error;
2442
2443                         continue;
2444                 }
2445
2446                 /* Anything else. */
2447                 if (err_line)
2448                         *err_line = n_lines;
2449                 if (err_msg)
2450                         *err_msg = "Unknown statement.";
2451                 status = -EINVAL;
2452                 goto error;
2453         }
2454
2455         /* Handle unfinished block. */
2456         if (block_mask) {
2457                 if (err_line)
2458                         *err_line = n_lines;
2459                 if (err_msg)
2460                         *err_msg = "Missing }.";
2461                 status = -EINVAL;
2462                 goto error;
2463         }
2464
2465         /* Pipeline build. */
2466         status = rte_swx_pipeline_build(p);
2467         if (status) {
2468                 if (err_line)
2469                         *err_line = n_lines;
2470                 if (err_msg)
2471                         *err_msg = "Pipeline build error.";
2472                 goto error;
2473         }
2474
2475         return 0;
2476
2477 error:
2478         extobj_spec_free(&extobj_spec);
2479         struct_spec_free(&struct_spec);
2480         header_spec_free(&header_spec);
2481         metadata_spec_free(&metadata_spec);
2482         action_spec_free(&action_spec);
2483         table_spec_free(&table_spec);
2484         selector_spec_free(&selector_spec);
2485         learner_spec_free(&learner_spec);
2486         regarray_spec_free(&regarray_spec);
2487         metarray_spec_free(&metarray_spec);
2488         apply_spec_free(&apply_spec);
2489         return status;
2490 }