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