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