d9cd1d05956ed2b123b956f28714fde3083e2d5a
[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 args METADATA_FIELD_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         for (i = 0; i < s->params.n_actions; i++) {
1344                 uintptr_t name = (uintptr_t)s->params.action_field_names[i];
1345
1346                 free((void *)name);
1347         }
1348
1349         free(s->params.action_field_names);
1350         s->params.action_field_names = NULL;
1351
1352         s->params.n_actions = 0;
1353
1354         default_action_name = (uintptr_t)s->params.default_action_name;
1355         free((void *)default_action_name);
1356         s->params.default_action_name = NULL;
1357
1358         free(s->params.default_action_data);
1359         s->params.default_action_data = NULL;
1360
1361         s->params.default_action_is_const = 0;
1362
1363         s->size = 0;
1364
1365         s->timeout = 0;
1366 }
1367
1368 static int
1369 learner_key_statement_parse(uint32_t *block_mask,
1370                             char **tokens,
1371                             uint32_t n_tokens,
1372                             uint32_t n_lines,
1373                             uint32_t *err_line,
1374                             const char **err_msg)
1375 {
1376         /* Check format. */
1377         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1378                 if (err_line)
1379                         *err_line = n_lines;
1380                 if (err_msg)
1381                         *err_msg = "Invalid key statement.";
1382                 return -EINVAL;
1383         }
1384
1385         /* block_mask. */
1386         *block_mask |= 1 << LEARNER_KEY_BLOCK;
1387
1388         return 0;
1389 }
1390
1391 static int
1392 learner_key_block_parse(struct learner_spec *s,
1393                         uint32_t *block_mask,
1394                         char **tokens,
1395                         uint32_t n_tokens,
1396                         uint32_t n_lines,
1397                         uint32_t *err_line,
1398                         const char **err_msg)
1399 {
1400         const char **new_field_names = NULL;
1401         char *field_name = NULL;
1402
1403         /* Handle end of block. */
1404         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1405                 *block_mask &= ~(1 << LEARNER_KEY_BLOCK);
1406                 return 0;
1407         }
1408
1409         /* Check input arguments. */
1410         if (n_tokens != 1) {
1411                 if (err_line)
1412                         *err_line = n_lines;
1413                 if (err_msg)
1414                         *err_msg = "Invalid match field statement.";
1415                 return -EINVAL;
1416         }
1417
1418         field_name = strdup(tokens[0]);
1419         new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
1420         if (!field_name || !new_field_names) {
1421                 free(field_name);
1422                 free(new_field_names);
1423
1424                 if (err_line)
1425                         *err_line = n_lines;
1426                 if (err_msg)
1427                         *err_msg = "Memory allocation failed.";
1428                 return -ENOMEM;
1429         }
1430
1431         s->params.field_names = new_field_names;
1432         s->params.field_names[s->params.n_fields] = field_name;
1433         s->params.n_fields++;
1434
1435         return 0;
1436 }
1437
1438 static int
1439 learner_actions_statement_parse(uint32_t *block_mask,
1440                                 char **tokens,
1441                                 uint32_t n_tokens,
1442                                 uint32_t n_lines,
1443                                 uint32_t *err_line,
1444                                 const char **err_msg)
1445 {
1446         /* Check format. */
1447         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1448                 if (err_line)
1449                         *err_line = n_lines;
1450                 if (err_msg)
1451                         *err_msg = "Invalid actions statement.";
1452                 return -EINVAL;
1453         }
1454
1455         /* block_mask. */
1456         *block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
1457
1458         return 0;
1459 }
1460
1461 static int
1462 learner_actions_block_parse(struct learner_spec *s,
1463                             uint32_t *block_mask,
1464                             char **tokens,
1465                             uint32_t n_tokens,
1466                             uint32_t n_lines,
1467                             uint32_t *err_line,
1468                             const char **err_msg)
1469 {
1470         const char **new_action_names = NULL;
1471         const char **new_action_field_names = NULL;
1472         char *action_name = NULL, *action_field_name = NULL;
1473         int has_args = 1;
1474
1475         /* Handle end of block. */
1476         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1477                 *block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
1478                 return 0;
1479         }
1480
1481         /* Check input arguments. */
1482         if ((n_tokens != 3) || strcmp(tokens[1], "args")) {
1483                 if (err_line)
1484                         *err_line = n_lines;
1485                 if (err_msg)
1486                         *err_msg = "Invalid action name statement.";
1487                 return -EINVAL;
1488         }
1489
1490         if (!strcmp(tokens[2], "none"))
1491                 has_args = 0;
1492
1493         action_name = strdup(tokens[0]);
1494
1495         if (has_args)
1496                 action_field_name = strdup(tokens[2]);
1497
1498         new_action_names = realloc(s->params.action_names,
1499                                    (s->params.n_actions + 1) * sizeof(char *));
1500
1501         new_action_field_names = realloc(s->params.action_field_names,
1502                                          (s->params.n_actions + 1) * sizeof(char *));
1503
1504         if (!action_name ||
1505             (has_args && !action_field_name) ||
1506             !new_action_names ||
1507             !new_action_field_names) {
1508                 free(action_name);
1509                 free(action_field_name);
1510                 free(new_action_names);
1511                 free(new_action_field_names);
1512
1513                 if (err_line)
1514                         *err_line = n_lines;
1515                 if (err_msg)
1516                         *err_msg = "Memory allocation failed.";
1517                 return -ENOMEM;
1518         }
1519
1520         s->params.action_names = new_action_names;
1521         s->params.action_names[s->params.n_actions] = action_name;
1522         s->params.action_field_names = new_action_field_names;
1523         s->params.action_field_names[s->params.n_actions] = action_field_name;
1524         s->params.n_actions++;
1525
1526         return 0;
1527 }
1528
1529 static int
1530 learner_statement_parse(struct learner_spec *s,
1531                       uint32_t *block_mask,
1532                       char **tokens,
1533                       uint32_t n_tokens,
1534                       uint32_t n_lines,
1535                       uint32_t *err_line,
1536                       const char **err_msg)
1537 {
1538         /* Check format. */
1539         if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1540                 if (err_line)
1541                         *err_line = n_lines;
1542                 if (err_msg)
1543                         *err_msg = "Invalid learner statement.";
1544                 return -EINVAL;
1545         }
1546
1547         /* spec. */
1548         s->name = strdup(tokens[1]);
1549         if (!s->name) {
1550                 if (err_line)
1551                         *err_line = n_lines;
1552                 if (err_msg)
1553                         *err_msg = "Memory allocation failed.";
1554                 return -ENOMEM;
1555         }
1556
1557         /* block_mask. */
1558         *block_mask |= 1 << LEARNER_BLOCK;
1559
1560         return 0;
1561 }
1562
1563 static int
1564 learner_block_parse(struct learner_spec *s,
1565                     uint32_t *block_mask,
1566                     char **tokens,
1567                     uint32_t n_tokens,
1568                     uint32_t n_lines,
1569                     uint32_t *err_line,
1570                     const char **err_msg)
1571 {
1572         if (*block_mask & (1 << LEARNER_KEY_BLOCK))
1573                 return learner_key_block_parse(s,
1574                                                block_mask,
1575                                                tokens,
1576                                                n_tokens,
1577                                                n_lines,
1578                                                err_line,
1579                                                err_msg);
1580
1581         if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
1582                 return learner_actions_block_parse(s,
1583                                                    block_mask,
1584                                                    tokens,
1585                                                    n_tokens,
1586                                                    n_lines,
1587                                                    err_line,
1588                                                    err_msg);
1589
1590         /* Handle end of block. */
1591         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1592                 *block_mask &= ~(1 << LEARNER_BLOCK);
1593                 return 0;
1594         }
1595
1596         if (!strcmp(tokens[0], "key"))
1597                 return learner_key_statement_parse(block_mask,
1598                                                    tokens,
1599                                                    n_tokens,
1600                                                    n_lines,
1601                                                    err_line,
1602                                                    err_msg);
1603
1604         if (!strcmp(tokens[0], "actions"))
1605                 return learner_actions_statement_parse(block_mask,
1606                                                        tokens,
1607                                                        n_tokens,
1608                                                        n_lines,
1609                                                        err_line,
1610                                                        err_msg);
1611
1612         if (!strcmp(tokens[0], "default_action")) {
1613                 if (((n_tokens != 4) && (n_tokens != 5)) ||
1614                     strcmp(tokens[2], "args") ||
1615                     strcmp(tokens[3], "none") ||
1616                     ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
1617                         if (err_line)
1618                                 *err_line = n_lines;
1619                         if (err_msg)
1620                                 *err_msg = "Invalid default_action statement.";
1621                         return -EINVAL;
1622                 }
1623
1624                 if (s->params.default_action_name) {
1625                         if (err_line)
1626                                 *err_line = n_lines;
1627                         if (err_msg)
1628                                 *err_msg = "Duplicate default_action stmt.";
1629                         return -EINVAL;
1630                 }
1631
1632                 s->params.default_action_name = strdup(tokens[1]);
1633                 if (!s->params.default_action_name) {
1634                         if (err_line)
1635                                 *err_line = n_lines;
1636                         if (err_msg)
1637                                 *err_msg = "Memory allocation failed.";
1638                         return -ENOMEM;
1639                 }
1640
1641                 if (n_tokens == 5)
1642                         s->params.default_action_is_const = 1;
1643
1644                 return 0;
1645         }
1646
1647         if (!strcmp(tokens[0], "size")) {
1648                 char *p = tokens[1];
1649
1650                 if (n_tokens != 2) {
1651                         if (err_line)
1652                                 *err_line = n_lines;
1653                         if (err_msg)
1654                                 *err_msg = "Invalid size statement.";
1655                         return -EINVAL;
1656                 }
1657
1658                 s->size = strtoul(p, &p, 0);
1659                 if (p[0]) {
1660                         if (err_line)
1661                                 *err_line = n_lines;
1662                         if (err_msg)
1663                                 *err_msg = "Invalid size argument.";
1664                         return -EINVAL;
1665                 }
1666
1667                 return 0;
1668         }
1669
1670         if (!strcmp(tokens[0], "timeout")) {
1671                 char *p = tokens[1];
1672
1673                 if (n_tokens != 2) {
1674                         if (err_line)
1675                                 *err_line = n_lines;
1676                         if (err_msg)
1677                                 *err_msg = "Invalid timeout statement.";
1678                         return -EINVAL;
1679                 }
1680
1681                 s->timeout = strtoul(p, &p, 0);
1682                 if (p[0]) {
1683                         if (err_line)
1684                                 *err_line = n_lines;
1685                         if (err_msg)
1686                                 *err_msg = "Invalid timeout argument.";
1687                         return -EINVAL;
1688                 }
1689
1690                 return 0;
1691         }
1692
1693         /* Anything else. */
1694         if (err_line)
1695                 *err_line = n_lines;
1696         if (err_msg)
1697                 *err_msg = "Invalid statement.";
1698         return -EINVAL;
1699 }
1700
1701 /*
1702  * regarray.
1703  *
1704  * regarray NAME size SIZE initval INITVAL
1705  */
1706 struct regarray_spec {
1707         char *name;
1708         uint64_t init_val;
1709         uint32_t size;
1710 };
1711
1712 static void
1713 regarray_spec_free(struct regarray_spec *s)
1714 {
1715         if (!s)
1716                 return;
1717
1718         free(s->name);
1719         s->name = NULL;
1720 }
1721
1722 static int
1723 regarray_statement_parse(struct regarray_spec *s,
1724                          char **tokens,
1725                          uint32_t n_tokens,
1726                          uint32_t n_lines,
1727                          uint32_t *err_line,
1728                          const char **err_msg)
1729 {
1730         char *p;
1731
1732         /* Check format. */
1733         if ((n_tokens != 6) ||
1734              strcmp(tokens[2], "size") ||
1735              strcmp(tokens[4], "initval")) {
1736                 if (err_line)
1737                         *err_line = n_lines;
1738                 if (err_msg)
1739                         *err_msg = "Invalid regarray statement.";
1740                 return -EINVAL;
1741         }
1742
1743         /* spec. */
1744         s->name = strdup(tokens[1]);
1745         if (!s->name) {
1746                 if (err_line)
1747                         *err_line = n_lines;
1748                 if (err_msg)
1749                         *err_msg = "Memory allocation failed.";
1750                 return -ENOMEM;
1751         }
1752
1753         p = tokens[3];
1754         s->size = strtoul(p, &p, 0);
1755         if (p[0] || !s->size) {
1756                 if (err_line)
1757                         *err_line = n_lines;
1758                 if (err_msg)
1759                         *err_msg = "Invalid size argument.";
1760                 return -EINVAL;
1761         }
1762
1763         p = tokens[5];
1764         s->init_val = strtoull(p, &p, 0);
1765         if (p[0]) {
1766                 if (err_line)
1767                         *err_line = n_lines;
1768                 if (err_msg)
1769                         *err_msg = "Invalid initval argument.";
1770                 return -EINVAL;
1771         }
1772
1773         return 0;
1774 }
1775
1776 /*
1777  * metarray.
1778  *
1779  * metarray NAME size SIZE
1780  */
1781 struct metarray_spec {
1782         char *name;
1783         uint32_t size;
1784 };
1785
1786 static void
1787 metarray_spec_free(struct metarray_spec *s)
1788 {
1789         if (!s)
1790                 return;
1791
1792         free(s->name);
1793         s->name = NULL;
1794 }
1795
1796 static int
1797 metarray_statement_parse(struct metarray_spec *s,
1798                          char **tokens,
1799                          uint32_t n_tokens,
1800                          uint32_t n_lines,
1801                          uint32_t *err_line,
1802                          const char **err_msg)
1803 {
1804         char *p;
1805
1806         /* Check format. */
1807         if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
1808                 if (err_line)
1809                         *err_line = n_lines;
1810                 if (err_msg)
1811                         *err_msg = "Invalid metarray statement.";
1812                 return -EINVAL;
1813         }
1814
1815         /* spec. */
1816         s->name = strdup(tokens[1]);
1817         if (!s->name) {
1818                 if (err_line)
1819                         *err_line = n_lines;
1820                 if (err_msg)
1821                         *err_msg = "Memory allocation failed.";
1822                 return -ENOMEM;
1823         }
1824
1825         p = tokens[3];
1826         s->size = strtoul(p, &p, 0);
1827         if (p[0] || !s->size) {
1828                 if (err_line)
1829                         *err_line = n_lines;
1830                 if (err_msg)
1831                         *err_msg = "Invalid size argument.";
1832                 return -EINVAL;
1833         }
1834
1835         return 0;
1836 }
1837
1838 /*
1839  * apply.
1840  *
1841  * apply {
1842  *      INSTRUCTION
1843  *      ...
1844  * }
1845  */
1846 struct apply_spec {
1847         const char **instructions;
1848         uint32_t n_instructions;
1849 };
1850
1851 static void
1852 apply_spec_free(struct apply_spec *s)
1853 {
1854         uint32_t i;
1855
1856         if (!s)
1857                 return;
1858
1859         for (i = 0; i < s->n_instructions; i++) {
1860                 uintptr_t instr = (uintptr_t)s->instructions[i];
1861
1862                 free((void *)instr);
1863         }
1864
1865         free(s->instructions);
1866         s->instructions = NULL;
1867
1868         s->n_instructions = 0;
1869 }
1870
1871 static int
1872 apply_statement_parse(uint32_t *block_mask,
1873                       char **tokens,
1874                       uint32_t n_tokens,
1875                       uint32_t n_lines,
1876                       uint32_t *err_line,
1877                       const char **err_msg)
1878 {
1879         /* Check format. */
1880         if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1881                 if (err_line)
1882                         *err_line = n_lines;
1883                 if (err_msg)
1884                         *err_msg = "Invalid apply statement.";
1885                 return -EINVAL;
1886         }
1887
1888         /* block_mask. */
1889         *block_mask |= 1 << APPLY_BLOCK;
1890
1891         return 0;
1892 }
1893
1894 static int
1895 apply_block_parse(struct apply_spec *s,
1896                   uint32_t *block_mask,
1897                   char **tokens,
1898                   uint32_t n_tokens,
1899                   uint32_t n_lines,
1900                   uint32_t *err_line,
1901                   const char **err_msg)
1902 {
1903         char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1904         const char **new_instructions;
1905         uint32_t i;
1906
1907         /* Handle end of block. */
1908         if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1909                 *block_mask &= ~(1 << APPLY_BLOCK);
1910                 return 0;
1911         }
1912
1913         /* spec. */
1914         buffer[0] = 0;
1915         for (i = 0; i < n_tokens; i++) {
1916                 if (i)
1917                         strcat(buffer, " ");
1918                 strcat(buffer, tokens[i]);
1919         }
1920
1921         instr = strdup(buffer);
1922         if (!instr) {
1923                 if (err_line)
1924                         *err_line = n_lines;
1925                 if (err_msg)
1926                         *err_msg = "Memory allocation failed.";
1927                 return -ENOMEM;
1928         }
1929
1930         new_instructions = realloc(s->instructions,
1931                                    (s->n_instructions + 1) * sizeof(char *));
1932         if (!new_instructions) {
1933                 free(instr);
1934
1935                 if (err_line)
1936                         *err_line = n_lines;
1937                 if (err_msg)
1938                         *err_msg = "Memory allocation failed.";
1939                 return -ENOMEM;
1940         }
1941
1942         s->instructions = new_instructions;
1943         s->instructions[s->n_instructions] = instr;
1944         s->n_instructions++;
1945
1946         return 0;
1947 }
1948
1949 /*
1950  * Pipeline.
1951  */
1952 int
1953 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1954                                  FILE *spec,
1955                                  uint32_t *err_line,
1956                                  const char **err_msg)
1957 {
1958         struct extobj_spec extobj_spec = {0};
1959         struct struct_spec struct_spec = {0};
1960         struct header_spec header_spec = {0};
1961         struct metadata_spec metadata_spec = {0};
1962         struct action_spec action_spec = {0};
1963         struct table_spec table_spec = {0};
1964         struct selector_spec selector_spec = {0};
1965         struct learner_spec learner_spec = {0};
1966         struct regarray_spec regarray_spec = {0};
1967         struct metarray_spec metarray_spec = {0};
1968         struct apply_spec apply_spec = {0};
1969         uint32_t n_lines;
1970         uint32_t block_mask = 0;
1971         int status;
1972
1973         /* Check the input arguments. */
1974         if (!p) {
1975                 if (err_line)
1976                         *err_line = 0;
1977                 if (err_msg)
1978                         *err_msg = "Null pipeline arument.";
1979                 status = -EINVAL;
1980                 goto error;
1981         }
1982
1983         if (!spec) {
1984                 if (err_line)
1985                         *err_line = 0;
1986                 if (err_msg)
1987                         *err_msg = "Null specification file argument.";
1988                 status = -EINVAL;
1989                 goto error;
1990         }
1991
1992         for (n_lines = 1; ; n_lines++) {
1993                 char line[MAX_LINE_LENGTH];
1994                 char *tokens[MAX_TOKENS], *ptr = line;
1995                 uint32_t n_tokens = 0;
1996
1997                 /* Read next line. */
1998                 if (!fgets(line, sizeof(line), spec))
1999                         break;
2000
2001                 /* Parse the line into tokens. */
2002                 for ( ; ; ) {
2003                         char *token;
2004
2005                         /* Get token. */
2006                         token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
2007                         if (!token)
2008                                 break;
2009
2010                         /* Handle comments. */
2011                         if ((token[0] == '#') ||
2012                             (token[0] == ';') ||
2013                             ((token[0] == '/') && (token[1] == '/'))) {
2014                                 break;
2015                         }
2016
2017                         /* Handle excessively long lines. */
2018                         if (n_tokens >= MAX_TOKENS) {
2019                                 if (err_line)
2020                                         *err_line = n_lines;
2021                                 if (err_msg)
2022                                         *err_msg = "Too many tokens.";
2023                                 status = -EINVAL;
2024                                 goto error;
2025                         }
2026
2027                         /* Handle excessively long tokens. */
2028                         if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2029                             RTE_SWX_NAME_SIZE) {
2030                                 if (err_line)
2031                                         *err_line = n_lines;
2032                                 if (err_msg)
2033                                         *err_msg = "Token too big.";
2034                                 status = -EINVAL;
2035                                 goto error;
2036                         }
2037
2038                         /* Save token. */
2039                         tokens[n_tokens] = token;
2040                         n_tokens++;
2041                 }
2042
2043                 /* Handle empty lines. */
2044                 if (!n_tokens)
2045                         continue;
2046
2047                 /* struct block. */
2048                 if (block_mask & (1 << STRUCT_BLOCK)) {
2049                         status = struct_block_parse(&struct_spec,
2050                                                     &block_mask,
2051                                                     tokens,
2052                                                     n_tokens,
2053                                                     n_lines,
2054                                                     err_line,
2055                                                     err_msg);
2056                         if (status)
2057                                 goto error;
2058
2059                         if (block_mask & (1 << STRUCT_BLOCK))
2060                                 continue;
2061
2062                         /* End of block. */
2063                         status = rte_swx_pipeline_struct_type_register(p,
2064                                 struct_spec.name,
2065                                 struct_spec.fields,
2066                                 struct_spec.n_fields,
2067                                 struct_spec.varbit);
2068                         if (status) {
2069                                 if (err_line)
2070                                         *err_line = n_lines;
2071                                 if (err_msg)
2072                                         *err_msg = "Struct registration error.";
2073                                 goto error;
2074                         }
2075
2076                         struct_spec_free(&struct_spec);
2077
2078                         continue;
2079                 }
2080
2081                 /* action block. */
2082                 if (block_mask & (1 << ACTION_BLOCK)) {
2083                         status = action_block_parse(&action_spec,
2084                                                     &block_mask,
2085                                                     tokens,
2086                                                     n_tokens,
2087                                                     n_lines,
2088                                                     err_line,
2089                                                     err_msg);
2090                         if (status)
2091                                 goto error;
2092
2093                         if (block_mask & (1 << ACTION_BLOCK))
2094                                 continue;
2095
2096                         /* End of block. */
2097                         status = rte_swx_pipeline_action_config(p,
2098                                 action_spec.name,
2099                                 action_spec.args_struct_type_name,
2100                                 action_spec.instructions,
2101                                 action_spec.n_instructions);
2102                         if (status) {
2103                                 if (err_line)
2104                                         *err_line = n_lines;
2105                                 if (err_msg)
2106                                         *err_msg = "Action config error.";
2107                                 goto error;
2108                         }
2109
2110                         action_spec_free(&action_spec);
2111
2112                         continue;
2113                 }
2114
2115                 /* table block. */
2116                 if (block_mask & (1 << TABLE_BLOCK)) {
2117                         status = table_block_parse(&table_spec,
2118                                                    &block_mask,
2119                                                    tokens,
2120                                                    n_tokens,
2121                                                    n_lines,
2122                                                    err_line,
2123                                                    err_msg);
2124                         if (status)
2125                                 goto error;
2126
2127                         if (block_mask & (1 << TABLE_BLOCK))
2128                                 continue;
2129
2130                         /* End of block. */
2131                         status = rte_swx_pipeline_table_config(p,
2132                                 table_spec.name,
2133                                 &table_spec.params,
2134                                 table_spec.recommended_table_type_name,
2135                                 table_spec.args,
2136                                 table_spec.size);
2137                         if (status) {
2138                                 if (err_line)
2139                                         *err_line = n_lines;
2140                                 if (err_msg)
2141                                         *err_msg = "Table configuration error.";
2142                                 goto error;
2143                         }
2144
2145                         table_spec_free(&table_spec);
2146
2147                         continue;
2148                 }
2149
2150                 /* selector block. */
2151                 if (block_mask & (1 << SELECTOR_BLOCK)) {
2152                         status = selector_block_parse(&selector_spec,
2153                                                       &block_mask,
2154                                                       tokens,
2155                                                       n_tokens,
2156                                                       n_lines,
2157                                                       err_line,
2158                                                       err_msg);
2159                         if (status)
2160                                 goto error;
2161
2162                         if (block_mask & (1 << SELECTOR_BLOCK))
2163                                 continue;
2164
2165                         /* End of block. */
2166                         status = rte_swx_pipeline_selector_config(p,
2167                                 selector_spec.name,
2168                                 &selector_spec.params);
2169                         if (status) {
2170                                 if (err_line)
2171                                         *err_line = n_lines;
2172                                 if (err_msg)
2173                                         *err_msg = "Selector configuration error.";
2174                                 goto error;
2175                         }
2176
2177                         selector_spec_free(&selector_spec);
2178
2179                         continue;
2180                 }
2181
2182                 /* learner block. */
2183                 if (block_mask & (1 << LEARNER_BLOCK)) {
2184                         status = learner_block_parse(&learner_spec,
2185                                                      &block_mask,
2186                                                      tokens,
2187                                                      n_tokens,
2188                                                      n_lines,
2189                                                      err_line,
2190                                                      err_msg);
2191                         if (status)
2192                                 goto error;
2193
2194                         if (block_mask & (1 << LEARNER_BLOCK))
2195                                 continue;
2196
2197                         /* End of block. */
2198                         status = rte_swx_pipeline_learner_config(p,
2199                                 learner_spec.name,
2200                                 &learner_spec.params,
2201                                 learner_spec.size,
2202                                 learner_spec.timeout);
2203                         if (status) {
2204                                 if (err_line)
2205                                         *err_line = n_lines;
2206                                 if (err_msg)
2207                                         *err_msg = "Learner table configuration error.";
2208                                 goto error;
2209                         }
2210
2211                         learner_spec_free(&learner_spec);
2212
2213                         continue;
2214                 }
2215
2216                 /* apply block. */
2217                 if (block_mask & (1 << APPLY_BLOCK)) {
2218                         status = apply_block_parse(&apply_spec,
2219                                                    &block_mask,
2220                                                    tokens,
2221                                                    n_tokens,
2222                                                    n_lines,
2223                                                    err_line,
2224                                                    err_msg);
2225                         if (status)
2226                                 goto error;
2227
2228                         if (block_mask & (1 << APPLY_BLOCK))
2229                                 continue;
2230
2231                         /* End of block. */
2232                         status = rte_swx_pipeline_instructions_config(p,
2233                                 apply_spec.instructions,
2234                                 apply_spec.n_instructions);
2235                         if (status) {
2236                                 if (err_line)
2237                                         *err_line = n_lines;
2238                                 if (err_msg)
2239                                         *err_msg = "Pipeline instructions err.";
2240                                 goto error;
2241                         }
2242
2243                         apply_spec_free(&apply_spec);
2244
2245                         continue;
2246                 }
2247
2248                 /* extobj. */
2249                 if (!strcmp(tokens[0], "extobj")) {
2250                         status = extobj_statement_parse(&extobj_spec,
2251                                                         tokens,
2252                                                         n_tokens,
2253                                                         n_lines,
2254                                                         err_line,
2255                                                         err_msg);
2256                         if (status)
2257                                 goto error;
2258
2259                         status = rte_swx_pipeline_extern_object_config(p,
2260                                 extobj_spec.name,
2261                                 extobj_spec.extern_type_name,
2262                                 extobj_spec.pragma);
2263                         if (status) {
2264                                 if (err_line)
2265                                         *err_line = n_lines;
2266                                 if (err_msg)
2267                                         *err_msg = "Extern object config err.";
2268                                 goto error;
2269                         }
2270
2271                         extobj_spec_free(&extobj_spec);
2272
2273                         continue;
2274                 }
2275
2276                 /* struct. */
2277                 if (!strcmp(tokens[0], "struct")) {
2278                         status = struct_statement_parse(&struct_spec,
2279                                                         &block_mask,
2280                                                         tokens,
2281                                                         n_tokens,
2282                                                         n_lines,
2283                                                         err_line,
2284                                                         err_msg);
2285                         if (status)
2286                                 goto error;
2287
2288                         continue;
2289                 }
2290
2291                 /* header. */
2292                 if (!strcmp(tokens[0], "header")) {
2293                         status = header_statement_parse(&header_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_header_register(p,
2303                                 header_spec.name,
2304                                 header_spec.struct_type_name);
2305                         if (status) {
2306                                 if (err_line)
2307                                         *err_line = n_lines;
2308                                 if (err_msg)
2309                                         *err_msg = "Header registration error.";
2310                                 goto error;
2311                         }
2312
2313                         header_spec_free(&header_spec);
2314
2315                         continue;
2316                 }
2317
2318                 /* metadata. */
2319                 if (!strcmp(tokens[0], "metadata")) {
2320                         status = metadata_statement_parse(&metadata_spec,
2321                                                           tokens,
2322                                                           n_tokens,
2323                                                           n_lines,
2324                                                           err_line,
2325                                                           err_msg);
2326                         if (status)
2327                                 goto error;
2328
2329                         status = rte_swx_pipeline_packet_metadata_register(p,
2330                                 metadata_spec.struct_type_name);
2331                         if (status) {
2332                                 if (err_line)
2333                                         *err_line = n_lines;
2334                                 if (err_msg)
2335                                         *err_msg = "Meta-data reg err.";
2336                                 goto error;
2337                         }
2338
2339                         metadata_spec_free(&metadata_spec);
2340
2341                         continue;
2342                 }
2343
2344                 /* action. */
2345                 if (!strcmp(tokens[0], "action")) {
2346                         status = action_statement_parse(&action_spec,
2347                                                         &block_mask,
2348                                                         tokens,
2349                                                         n_tokens,
2350                                                         n_lines,
2351                                                         err_line,
2352                                                         err_msg);
2353                         if (status)
2354                                 goto error;
2355
2356                         continue;
2357                 }
2358
2359                 /* table. */
2360                 if (!strcmp(tokens[0], "table")) {
2361                         status = table_statement_parse(&table_spec,
2362                                                        &block_mask,
2363                                                        tokens,
2364                                                        n_tokens,
2365                                                        n_lines,
2366                                                        err_line,
2367                                                        err_msg);
2368                         if (status)
2369                                 goto error;
2370
2371                         continue;
2372                 }
2373
2374                 /* selector. */
2375                 if (!strcmp(tokens[0], "selector")) {
2376                         status = selector_statement_parse(&selector_spec,
2377                                                           &block_mask,
2378                                                           tokens,
2379                                                           n_tokens,
2380                                                           n_lines,
2381                                                           err_line,
2382                                                           err_msg);
2383                         if (status)
2384                                 goto error;
2385
2386                         continue;
2387                 }
2388
2389                 /* learner. */
2390                 if (!strcmp(tokens[0], "learner")) {
2391                         status = learner_statement_parse(&learner_spec,
2392                                                          &block_mask,
2393                                                          tokens,
2394                                                          n_tokens,
2395                                                          n_lines,
2396                                                          err_line,
2397                                                          err_msg);
2398                         if (status)
2399                                 goto error;
2400
2401                         continue;
2402                 }
2403
2404                 /* regarray. */
2405                 if (!strcmp(tokens[0], "regarray")) {
2406                         status = regarray_statement_parse(&regarray_spec,
2407                                                           tokens,
2408                                                           n_tokens,
2409                                                           n_lines,
2410                                                           err_line,
2411                                                           err_msg);
2412                         if (status)
2413                                 goto error;
2414
2415                         status = rte_swx_pipeline_regarray_config(p,
2416                                 regarray_spec.name,
2417                                 regarray_spec.size,
2418                                 regarray_spec.init_val);
2419                         if (status) {
2420                                 if (err_line)
2421                                         *err_line = n_lines;
2422                                 if (err_msg)
2423                                         *err_msg = "Register array configuration error.";
2424                                 goto error;
2425                         }
2426
2427                         regarray_spec_free(&regarray_spec);
2428
2429                         continue;
2430                 }
2431
2432                 /* metarray. */
2433                 if (!strcmp(tokens[0], "metarray")) {
2434                         status = metarray_statement_parse(&metarray_spec,
2435                                                           tokens,
2436                                                           n_tokens,
2437                                                           n_lines,
2438                                                           err_line,
2439                                                           err_msg);
2440                         if (status)
2441                                 goto error;
2442
2443                         status = rte_swx_pipeline_metarray_config(p,
2444                                 metarray_spec.name,
2445                                 metarray_spec.size);
2446                         if (status) {
2447                                 if (err_line)
2448                                         *err_line = n_lines;
2449                                 if (err_msg)
2450                                         *err_msg = "Meter array configuration error.";
2451                                 goto error;
2452                         }
2453
2454                         metarray_spec_free(&metarray_spec);
2455
2456                         continue;
2457                 }
2458
2459                 /* apply. */
2460                 if (!strcmp(tokens[0], "apply")) {
2461                         status = apply_statement_parse(&block_mask,
2462                                                        tokens,
2463                                                        n_tokens,
2464                                                        n_lines,
2465                                                        err_line,
2466                                                        err_msg);
2467                         if (status)
2468                                 goto error;
2469
2470                         continue;
2471                 }
2472
2473                 /* Anything else. */
2474                 if (err_line)
2475                         *err_line = n_lines;
2476                 if (err_msg)
2477                         *err_msg = "Unknown statement.";
2478                 status = -EINVAL;
2479                 goto error;
2480         }
2481
2482         /* Handle unfinished block. */
2483         if (block_mask) {
2484                 if (err_line)
2485                         *err_line = n_lines;
2486                 if (err_msg)
2487                         *err_msg = "Missing }.";
2488                 status = -EINVAL;
2489                 goto error;
2490         }
2491
2492         /* Pipeline build. */
2493         status = rte_swx_pipeline_build(p);
2494         if (status) {
2495                 if (err_line)
2496                         *err_line = n_lines;
2497                 if (err_msg)
2498                         *err_msg = "Pipeline build error.";
2499                 goto error;
2500         }
2501
2502         return 0;
2503
2504 error:
2505         extobj_spec_free(&extobj_spec);
2506         struct_spec_free(&struct_spec);
2507         header_spec_free(&header_spec);
2508         metadata_spec_free(&metadata_spec);
2509         action_spec_free(&action_spec);
2510         table_spec_free(&table_spec);
2511         selector_spec_free(&selector_spec);
2512         learner_spec_free(&learner_spec);
2513         regarray_spec_free(&regarray_spec);
2514         metarray_spec_free(&metarray_spec);
2515         apply_spec_free(&apply_spec);
2516         return status;
2517 }