xref: /dpdk/lib/pipeline/rte_swx_pipeline_spec.c (revision 69f9d8aa357d2299e057b7e335f340e20a0c5e7e)
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 [ @tableonly | @defaultonly ]
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 	free(s->params.action_is_for_table_entries);
601 	s->params.action_is_for_table_entries = NULL;
602 
603 	free(s->params.action_is_for_default_entry);
604 	s->params.action_is_for_default_entry = NULL;
605 
606 	s->params.default_action_is_const = 0;
607 
608 	free(s->recommended_table_type_name);
609 	s->recommended_table_type_name = NULL;
610 
611 	free(s->args);
612 	s->args = NULL;
613 
614 	s->size = 0;
615 }
616 
617 static int
618 table_key_statement_parse(uint32_t *block_mask,
619 			  char **tokens,
620 			  uint32_t n_tokens,
621 			  uint32_t n_lines,
622 			  uint32_t *err_line,
623 			  const char **err_msg)
624 {
625 	/* Check format. */
626 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
627 		if (err_line)
628 			*err_line = n_lines;
629 		if (err_msg)
630 			*err_msg = "Invalid key statement.";
631 		return -EINVAL;
632 	}
633 
634 	/* block_mask. */
635 	*block_mask |= 1 << TABLE_KEY_BLOCK;
636 
637 	return 0;
638 }
639 
640 static int
641 table_key_block_parse(struct table_spec *s,
642 		      uint32_t *block_mask,
643 		      char **tokens,
644 		      uint32_t n_tokens,
645 		      uint32_t n_lines,
646 		      uint32_t *err_line,
647 		      const char **err_msg)
648 {
649 	struct rte_swx_match_field_params *new_fields;
650 	enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
651 	char *name;
652 
653 	/* Handle end of block. */
654 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
655 		*block_mask &= ~(1 << TABLE_KEY_BLOCK);
656 		return 0;
657 	}
658 
659 	/* Check input arguments. */
660 	if ((n_tokens != 2) ||
661 	    (strcmp(tokens[1], "exact") &&
662 	     strcmp(tokens[1], "wildcard") &&
663 	     strcmp(tokens[1], "lpm"))) {
664 		if (err_line)
665 			*err_line = n_lines;
666 		if (err_msg)
667 			*err_msg = "Invalid match field statement.";
668 		return -EINVAL;
669 	}
670 
671 	if (!strcmp(tokens[1], "wildcard"))
672 		match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
673 	if (!strcmp(tokens[1], "lpm"))
674 		match_type = RTE_SWX_TABLE_MATCH_LPM;
675 	if (!strcmp(tokens[1], "exact"))
676 		match_type = RTE_SWX_TABLE_MATCH_EXACT;
677 
678 	name = strdup(tokens[0]);
679 	if (!name) {
680 		if (err_line)
681 			*err_line = n_lines;
682 		if (err_msg)
683 			*err_msg = "Memory allocation failed.";
684 		return -ENOMEM;
685 	}
686 
687 	new_fields = realloc(s->params.fields,
688 			     (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
689 	if (!new_fields) {
690 		free(name);
691 
692 		if (err_line)
693 			*err_line = n_lines;
694 		if (err_msg)
695 			*err_msg = "Memory allocation failed.";
696 		return -ENOMEM;
697 	}
698 
699 	s->params.fields = new_fields;
700 	s->params.fields[s->params.n_fields].name = name;
701 	s->params.fields[s->params.n_fields].match_type = match_type;
702 	s->params.n_fields++;
703 
704 	return 0;
705 }
706 
707 static int
708 table_actions_statement_parse(uint32_t *block_mask,
709 			      char **tokens,
710 			      uint32_t n_tokens,
711 			      uint32_t n_lines,
712 			      uint32_t *err_line,
713 			      const char **err_msg)
714 {
715 	/* Check format. */
716 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
717 		if (err_line)
718 			*err_line = n_lines;
719 		if (err_msg)
720 			*err_msg = "Invalid actions statement.";
721 		return -EINVAL;
722 	}
723 
724 	/* block_mask. */
725 	*block_mask |= 1 << TABLE_ACTIONS_BLOCK;
726 
727 	return 0;
728 }
729 
730 static int
731 table_actions_block_parse(struct table_spec *s,
732 			  uint32_t *block_mask,
733 			  char **tokens,
734 			  uint32_t n_tokens,
735 			  uint32_t n_lines,
736 			  uint32_t *err_line,
737 			  const char **err_msg)
738 {
739 	const char **new_action_names = NULL;
740 	int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
741 	char *name = NULL;
742 	int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
743 
744 	/* Handle end of block. */
745 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
746 		*block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
747 		return 0;
748 	}
749 
750 	/* Check input arguments. */
751 	if ((n_tokens > 2) ||
752 	    ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
753 	      strcmp(tokens[1], "@defaultonly"))) {
754 		if (err_line)
755 			*err_line = n_lines;
756 		if (err_msg)
757 			*err_msg = "Invalid action name statement.";
758 		return -EINVAL;
759 	}
760 
761 	name = strdup(tokens[0]);
762 
763 	if (n_tokens == 2) {
764 		if (!strcmp(tokens[1], "@tableonly"))
765 			action_is_for_default_entry = 0;
766 
767 		if (!strcmp(tokens[1], "@defaultonly"))
768 			action_is_for_table_entries = 0;
769 	}
770 
771 	new_action_names = realloc(s->params.action_names,
772 				   (s->params.n_actions + 1) * sizeof(char *));
773 	new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
774 						  (s->params.n_actions + 1) * sizeof(int));
775 	new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
776 						  (s->params.n_actions + 1) * sizeof(int));
777 
778 	if (!name ||
779 	    !new_action_names ||
780 	    !new_action_is_for_table_entries ||
781 	    !new_action_is_for_default_entry) {
782 		free(name);
783 		free(new_action_names);
784 		free(new_action_is_for_table_entries);
785 		free(new_action_is_for_default_entry);
786 
787 		if (err_line)
788 			*err_line = n_lines;
789 		if (err_msg)
790 			*err_msg = "Memory allocation failed.";
791 		return -ENOMEM;
792 	}
793 
794 	s->params.action_names = new_action_names;
795 	s->params.action_names[s->params.n_actions] = name;
796 
797 	s->params.action_is_for_table_entries = new_action_is_for_table_entries;
798 	s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
799 
800 	s->params.action_is_for_default_entry = new_action_is_for_default_entry;
801 	s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
802 
803 	s->params.n_actions++;
804 
805 	return 0;
806 }
807 
808 static int
809 table_statement_parse(struct table_spec *s,
810 		      uint32_t *block_mask,
811 		      char **tokens,
812 		      uint32_t n_tokens,
813 		      uint32_t n_lines,
814 		      uint32_t *err_line,
815 		      const char **err_msg)
816 {
817 	/* Check format. */
818 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
819 		if (err_line)
820 			*err_line = n_lines;
821 		if (err_msg)
822 			*err_msg = "Invalid table statement.";
823 		return -EINVAL;
824 	}
825 
826 	/* spec. */
827 	s->name = strdup(tokens[1]);
828 	if (!s->name) {
829 		if (err_line)
830 			*err_line = n_lines;
831 		if (err_msg)
832 			*err_msg = "Memory allocation failed.";
833 		return -ENOMEM;
834 	}
835 
836 	/* block_mask. */
837 	*block_mask |= 1 << TABLE_BLOCK;
838 
839 	return 0;
840 }
841 
842 static int
843 table_block_parse(struct table_spec *s,
844 		  uint32_t *block_mask,
845 		  char **tokens,
846 		  uint32_t n_tokens,
847 		  uint32_t n_lines,
848 		  uint32_t *err_line,
849 		  const char **err_msg)
850 {
851 	if (*block_mask & (1 << TABLE_KEY_BLOCK))
852 		return table_key_block_parse(s,
853 					     block_mask,
854 					     tokens,
855 					     n_tokens,
856 					     n_lines,
857 					     err_line,
858 					     err_msg);
859 
860 	if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
861 		return table_actions_block_parse(s,
862 						 block_mask,
863 						 tokens,
864 						 n_tokens,
865 						 n_lines,
866 						 err_line,
867 						 err_msg);
868 
869 	/* Handle end of block. */
870 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
871 		*block_mask &= ~(1 << TABLE_BLOCK);
872 		return 0;
873 	}
874 
875 	if (!strcmp(tokens[0], "key"))
876 		return table_key_statement_parse(block_mask,
877 						 tokens,
878 						 n_tokens,
879 						 n_lines,
880 						 err_line,
881 						 err_msg);
882 
883 	if (!strcmp(tokens[0], "actions"))
884 		return table_actions_statement_parse(block_mask,
885 						     tokens,
886 						     n_tokens,
887 						     n_lines,
888 						     err_line,
889 						     err_msg);
890 
891 	if (!strcmp(tokens[0], "default_action")) {
892 		if (((n_tokens != 4) && (n_tokens != 5)) ||
893 		    strcmp(tokens[2], "args") ||
894 		    strcmp(tokens[3], "none") ||
895 		    ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
896 			if (err_line)
897 				*err_line = n_lines;
898 			if (err_msg)
899 				*err_msg = "Invalid default_action statement.";
900 			return -EINVAL;
901 		}
902 
903 		if (s->params.default_action_name) {
904 			if (err_line)
905 				*err_line = n_lines;
906 			if (err_msg)
907 				*err_msg = "Duplicate default_action stmt.";
908 			return -EINVAL;
909 		}
910 
911 		s->params.default_action_name = strdup(tokens[1]);
912 		if (!s->params.default_action_name) {
913 			if (err_line)
914 				*err_line = n_lines;
915 			if (err_msg)
916 				*err_msg = "Memory allocation failed.";
917 			return -ENOMEM;
918 		}
919 
920 		if (n_tokens == 5)
921 			s->params.default_action_is_const = 1;
922 
923 		return 0;
924 	}
925 
926 	if (!strcmp(tokens[0], "instanceof")) {
927 		if (n_tokens != 2) {
928 			if (err_line)
929 				*err_line = n_lines;
930 			if (err_msg)
931 				*err_msg = "Invalid instanceof statement.";
932 			return -EINVAL;
933 		}
934 
935 		if (s->recommended_table_type_name) {
936 			if (err_line)
937 				*err_line = n_lines;
938 			if (err_msg)
939 				*err_msg = "Duplicate instanceof statement.";
940 			return -EINVAL;
941 		}
942 
943 		s->recommended_table_type_name = strdup(tokens[1]);
944 		if (!s->recommended_table_type_name) {
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], "pragma")) {
956 		if (n_tokens != 2) {
957 			if (err_line)
958 				*err_line = n_lines;
959 			if (err_msg)
960 				*err_msg = "Invalid pragma statement.";
961 			return -EINVAL;
962 		}
963 
964 		if (s->args) {
965 			if (err_line)
966 				*err_line = n_lines;
967 			if (err_msg)
968 				*err_msg = "Duplicate pragma statement.";
969 			return -EINVAL;
970 		}
971 
972 		s->args = strdup(tokens[1]);
973 		if (!s->args) {
974 			if (err_line)
975 				*err_line = n_lines;
976 			if (err_msg)
977 				*err_msg = "Memory allocation failed.";
978 			return -ENOMEM;
979 		}
980 
981 		return 0;
982 	}
983 
984 	if (!strcmp(tokens[0], "size")) {
985 		char *p = tokens[1];
986 
987 		if (n_tokens != 2) {
988 			if (err_line)
989 				*err_line = n_lines;
990 			if (err_msg)
991 				*err_msg = "Invalid pragma statement.";
992 			return -EINVAL;
993 		}
994 
995 		s->size = strtoul(p, &p, 0);
996 		if (p[0]) {
997 			if (err_line)
998 				*err_line = n_lines;
999 			if (err_msg)
1000 				*err_msg = "Invalid size argument.";
1001 			return -EINVAL;
1002 		}
1003 
1004 		return 0;
1005 	}
1006 
1007 	/* Anything else. */
1008 	if (err_line)
1009 		*err_line = n_lines;
1010 	if (err_msg)
1011 		*err_msg = "Invalid statement.";
1012 	return -EINVAL;
1013 }
1014 
1015 /*
1016  * selector.
1017  *
1018  * selector SELECTOR_NAME {
1019  *	group_id FIELD_NAME
1020  *	selector {
1021  *		FIELD_NAME
1022  *		...
1023  *	}
1024  *	member_id FIELD_NAME
1025  *	n_groups N_GROUPS
1026  *	n_members_per_group N_MEMBERS_PER_GROUP
1027  * }
1028  */
1029 struct selector_spec {
1030 	char *name;
1031 	struct rte_swx_pipeline_selector_params params;
1032 };
1033 
1034 static void
1035 selector_spec_free(struct selector_spec *s)
1036 {
1037 	uintptr_t field_name;
1038 	uint32_t i;
1039 
1040 	if (!s)
1041 		return;
1042 
1043 	/* name. */
1044 	free(s->name);
1045 	s->name = NULL;
1046 
1047 	/* params->group_id_field_name. */
1048 	field_name = (uintptr_t)s->params.group_id_field_name;
1049 	free((void *)field_name);
1050 	s->params.group_id_field_name = NULL;
1051 
1052 	/* params->selector_field_names. */
1053 	for (i = 0; i < s->params.n_selector_fields; i++) {
1054 		field_name = (uintptr_t)s->params.selector_field_names[i];
1055 
1056 		free((void *)field_name);
1057 	}
1058 
1059 	free(s->params.selector_field_names);
1060 	s->params.selector_field_names = NULL;
1061 
1062 	s->params.n_selector_fields = 0;
1063 
1064 	/* params->member_id_field_name. */
1065 	field_name = (uintptr_t)s->params.member_id_field_name;
1066 	free((void *)field_name);
1067 	s->params.member_id_field_name = NULL;
1068 
1069 	/* params->n_groups_max. */
1070 	s->params.n_groups_max = 0;
1071 
1072 	/* params->n_members_per_group_max. */
1073 	s->params.n_members_per_group_max = 0;
1074 }
1075 
1076 static int
1077 selector_statement_parse(struct selector_spec *s,
1078 			 uint32_t *block_mask,
1079 			 char **tokens,
1080 			 uint32_t n_tokens,
1081 			 uint32_t n_lines,
1082 			 uint32_t *err_line,
1083 			 const char **err_msg)
1084 {
1085 	/* Check format. */
1086 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1087 		if (err_line)
1088 			*err_line = n_lines;
1089 		if (err_msg)
1090 			*err_msg = "Invalid selector statement.";
1091 		return -EINVAL;
1092 	}
1093 
1094 	/* spec. */
1095 	s->name = strdup(tokens[1]);
1096 	if (!s->name) {
1097 		if (err_line)
1098 			*err_line = n_lines;
1099 		if (err_msg)
1100 			*err_msg = "Memory allocation failed.";
1101 		return -ENOMEM;
1102 	}
1103 
1104 	/* block_mask. */
1105 	*block_mask |= 1 << SELECTOR_BLOCK;
1106 
1107 	return 0;
1108 }
1109 
1110 static int
1111 selector_selector_statement_parse(uint32_t *block_mask,
1112 				  char **tokens,
1113 				  uint32_t n_tokens,
1114 				  uint32_t n_lines,
1115 				  uint32_t *err_line,
1116 				  const char **err_msg)
1117 {
1118 	/* Check format. */
1119 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1120 		if (err_line)
1121 			*err_line = n_lines;
1122 		if (err_msg)
1123 			*err_msg = "Invalid selector statement.";
1124 		return -EINVAL;
1125 	}
1126 
1127 	/* block_mask. */
1128 	*block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
1129 
1130 	return 0;
1131 }
1132 
1133 static int
1134 selector_selector_block_parse(struct selector_spec *s,
1135 			      uint32_t *block_mask,
1136 			      char **tokens,
1137 			      uint32_t n_tokens,
1138 			      uint32_t n_lines,
1139 			      uint32_t *err_line,
1140 			      const char **err_msg)
1141 {
1142 	const char **new_fields;
1143 	char *name;
1144 
1145 	/* Handle end of block. */
1146 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1147 		*block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
1148 		return 0;
1149 	}
1150 
1151 	/* Check input arguments. */
1152 	if (n_tokens != 1) {
1153 		if (err_line)
1154 			*err_line = n_lines;
1155 		if (err_msg)
1156 			*err_msg = "Invalid selector field statement.";
1157 		return -EINVAL;
1158 	}
1159 
1160 	name = strdup(tokens[0]);
1161 	if (!name) {
1162 		if (err_line)
1163 			*err_line = n_lines;
1164 		if (err_msg)
1165 			*err_msg = "Memory allocation failed.";
1166 		return -ENOMEM;
1167 	}
1168 
1169 	new_fields = realloc(s->params.selector_field_names,
1170 			     (s->params.n_selector_fields + 1) * sizeof(char *));
1171 	if (!new_fields) {
1172 		free(name);
1173 
1174 		if (err_line)
1175 			*err_line = n_lines;
1176 		if (err_msg)
1177 			*err_msg = "Memory allocation failed.";
1178 		return -ENOMEM;
1179 	}
1180 
1181 	s->params.selector_field_names = new_fields;
1182 	s->params.selector_field_names[s->params.n_selector_fields] = name;
1183 	s->params.n_selector_fields++;
1184 
1185 	return 0;
1186 }
1187 
1188 static int
1189 selector_block_parse(struct selector_spec *s,
1190 		     uint32_t *block_mask,
1191 		     char **tokens,
1192 		     uint32_t n_tokens,
1193 		     uint32_t n_lines,
1194 		     uint32_t *err_line,
1195 		     const char **err_msg)
1196 {
1197 	if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK))
1198 		return selector_selector_block_parse(s,
1199 						     block_mask,
1200 						     tokens,
1201 						     n_tokens,
1202 						     n_lines,
1203 						     err_line,
1204 						     err_msg);
1205 
1206 	/* Handle end of block. */
1207 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1208 		*block_mask &= ~(1 << SELECTOR_BLOCK);
1209 		return 0;
1210 	}
1211 
1212 	if (!strcmp(tokens[0], "group_id")) {
1213 		if (n_tokens != 2) {
1214 			if (err_line)
1215 				*err_line = n_lines;
1216 			if (err_msg)
1217 				*err_msg = "Invalid group_id statement.";
1218 			return -EINVAL;
1219 		}
1220 
1221 		s->params.group_id_field_name = strdup(tokens[1]);
1222 		if (!s->params.group_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], "selector"))
1234 		return selector_selector_statement_parse(block_mask,
1235 							 tokens,
1236 							 n_tokens,
1237 							 n_lines,
1238 							 err_line,
1239 							 err_msg);
1240 
1241 	if (!strcmp(tokens[0], "member_id")) {
1242 		if (n_tokens != 2) {
1243 			if (err_line)
1244 				*err_line = n_lines;
1245 			if (err_msg)
1246 				*err_msg = "Invalid member_id statement.";
1247 			return -EINVAL;
1248 		}
1249 
1250 		s->params.member_id_field_name = strdup(tokens[1]);
1251 		if (!s->params.member_id_field_name) {
1252 			if (err_line)
1253 				*err_line = n_lines;
1254 			if (err_msg)
1255 				*err_msg = "Memory allocation failed.";
1256 			return -ENOMEM;
1257 		}
1258 
1259 		return 0;
1260 	}
1261 
1262 	if (!strcmp(tokens[0], "n_groups_max")) {
1263 		char *p = tokens[1];
1264 
1265 		if (n_tokens != 2) {
1266 			if (err_line)
1267 				*err_line = n_lines;
1268 			if (err_msg)
1269 				*err_msg = "Invalid n_groups statement.";
1270 			return -EINVAL;
1271 		}
1272 
1273 		s->params.n_groups_max = strtoul(p, &p, 0);
1274 		if (p[0]) {
1275 			if (err_line)
1276 				*err_line = n_lines;
1277 			if (err_msg)
1278 				*err_msg = "Invalid n_groups argument.";
1279 			return -EINVAL;
1280 		}
1281 
1282 		return 0;
1283 	}
1284 
1285 	if (!strcmp(tokens[0], "n_members_per_group_max")) {
1286 		char *p = tokens[1];
1287 
1288 		if (n_tokens != 2) {
1289 			if (err_line)
1290 				*err_line = n_lines;
1291 			if (err_msg)
1292 				*err_msg = "Invalid n_members_per_group statement.";
1293 			return -EINVAL;
1294 		}
1295 
1296 		s->params.n_members_per_group_max = strtoul(p, &p, 0);
1297 		if (p[0]) {
1298 			if (err_line)
1299 				*err_line = n_lines;
1300 			if (err_msg)
1301 				*err_msg = "Invalid n_members_per_group argument.";
1302 			return -EINVAL;
1303 		}
1304 
1305 		return 0;
1306 	}
1307 
1308 	/* Anything else. */
1309 	if (err_line)
1310 		*err_line = n_lines;
1311 	if (err_msg)
1312 		*err_msg = "Invalid statement.";
1313 	return -EINVAL;
1314 }
1315 
1316 /*
1317  * learner.
1318  *
1319  * learner {
1320  *	key {
1321  *		MATCH_FIELD_NAME
1322  *		...
1323  *	}
1324  *	actions {
1325  *		ACTION_NAME [ @tableonly | @defaultonly]
1326  *		...
1327  *	}
1328  *	default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
1329  *	size SIZE
1330  *	timeout TIMEOUT_IN_SECONDS
1331  * }
1332  */
1333 struct learner_spec {
1334 	char *name;
1335 	struct rte_swx_pipeline_learner_params params;
1336 	uint32_t size;
1337 	uint32_t timeout;
1338 };
1339 
1340 static void
1341 learner_spec_free(struct learner_spec *s)
1342 {
1343 	uintptr_t default_action_name;
1344 	uint32_t i;
1345 
1346 	if (!s)
1347 		return;
1348 
1349 	free(s->name);
1350 	s->name = NULL;
1351 
1352 	for (i = 0; i < s->params.n_fields; i++) {
1353 		uintptr_t name = (uintptr_t)s->params.field_names[i];
1354 
1355 		free((void *)name);
1356 	}
1357 
1358 	free(s->params.field_names);
1359 	s->params.field_names = NULL;
1360 
1361 	s->params.n_fields = 0;
1362 
1363 	for (i = 0; i < s->params.n_actions; i++) {
1364 		uintptr_t name = (uintptr_t)s->params.action_names[i];
1365 
1366 		free((void *)name);
1367 	}
1368 
1369 	free(s->params.action_names);
1370 	s->params.action_names = NULL;
1371 
1372 	s->params.n_actions = 0;
1373 
1374 	default_action_name = (uintptr_t)s->params.default_action_name;
1375 	free((void *)default_action_name);
1376 	s->params.default_action_name = NULL;
1377 
1378 	free(s->params.default_action_data);
1379 	s->params.default_action_data = NULL;
1380 
1381 	free(s->params.action_is_for_table_entries);
1382 	s->params.action_is_for_table_entries = NULL;
1383 
1384 	free(s->params.action_is_for_default_entry);
1385 	s->params.action_is_for_default_entry = NULL;
1386 
1387 	s->params.default_action_is_const = 0;
1388 
1389 	s->size = 0;
1390 
1391 	s->timeout = 0;
1392 }
1393 
1394 static int
1395 learner_key_statement_parse(uint32_t *block_mask,
1396 			    char **tokens,
1397 			    uint32_t n_tokens,
1398 			    uint32_t n_lines,
1399 			    uint32_t *err_line,
1400 			    const char **err_msg)
1401 {
1402 	/* Check format. */
1403 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1404 		if (err_line)
1405 			*err_line = n_lines;
1406 		if (err_msg)
1407 			*err_msg = "Invalid key statement.";
1408 		return -EINVAL;
1409 	}
1410 
1411 	/* block_mask. */
1412 	*block_mask |= 1 << LEARNER_KEY_BLOCK;
1413 
1414 	return 0;
1415 }
1416 
1417 static int
1418 learner_key_block_parse(struct learner_spec *s,
1419 			uint32_t *block_mask,
1420 			char **tokens,
1421 			uint32_t n_tokens,
1422 			uint32_t n_lines,
1423 			uint32_t *err_line,
1424 			const char **err_msg)
1425 {
1426 	const char **new_field_names = NULL;
1427 	char *field_name = NULL;
1428 
1429 	/* Handle end of block. */
1430 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1431 		*block_mask &= ~(1 << LEARNER_KEY_BLOCK);
1432 		return 0;
1433 	}
1434 
1435 	/* Check input arguments. */
1436 	if (n_tokens != 1) {
1437 		if (err_line)
1438 			*err_line = n_lines;
1439 		if (err_msg)
1440 			*err_msg = "Invalid match field statement.";
1441 		return -EINVAL;
1442 	}
1443 
1444 	field_name = strdup(tokens[0]);
1445 	new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
1446 	if (!field_name || !new_field_names) {
1447 		free(field_name);
1448 		free(new_field_names);
1449 
1450 		if (err_line)
1451 			*err_line = n_lines;
1452 		if (err_msg)
1453 			*err_msg = "Memory allocation failed.";
1454 		return -ENOMEM;
1455 	}
1456 
1457 	s->params.field_names = new_field_names;
1458 	s->params.field_names[s->params.n_fields] = field_name;
1459 	s->params.n_fields++;
1460 
1461 	return 0;
1462 }
1463 
1464 static int
1465 learner_actions_statement_parse(uint32_t *block_mask,
1466 				char **tokens,
1467 				uint32_t n_tokens,
1468 				uint32_t n_lines,
1469 				uint32_t *err_line,
1470 				const char **err_msg)
1471 {
1472 	/* Check format. */
1473 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1474 		if (err_line)
1475 			*err_line = n_lines;
1476 		if (err_msg)
1477 			*err_msg = "Invalid actions statement.";
1478 		return -EINVAL;
1479 	}
1480 
1481 	/* block_mask. */
1482 	*block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
1483 
1484 	return 0;
1485 }
1486 
1487 static int
1488 learner_actions_block_parse(struct learner_spec *s,
1489 			    uint32_t *block_mask,
1490 			    char **tokens,
1491 			    uint32_t n_tokens,
1492 			    uint32_t n_lines,
1493 			    uint32_t *err_line,
1494 			    const char **err_msg)
1495 {
1496 	const char **new_action_names = NULL;
1497 	int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
1498 	char *name = NULL;
1499 	int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
1500 
1501 	/* Handle end of block. */
1502 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1503 		*block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
1504 		return 0;
1505 	}
1506 
1507 	/* Check input arguments. */
1508 	if ((n_tokens > 2) ||
1509 	    ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
1510 	      strcmp(tokens[1], "@defaultonly"))) {
1511 		if (err_line)
1512 			*err_line = n_lines;
1513 		if (err_msg)
1514 			*err_msg = "Invalid action name statement.";
1515 		return -EINVAL;
1516 	}
1517 
1518 	name = strdup(tokens[0]);
1519 
1520 	if (n_tokens == 2) {
1521 		if (!strcmp(tokens[1], "@tableonly"))
1522 			action_is_for_default_entry = 0;
1523 
1524 		if (!strcmp(tokens[1], "@defaultonly"))
1525 			action_is_for_table_entries = 0;
1526 	}
1527 
1528 	new_action_names = realloc(s->params.action_names,
1529 				   (s->params.n_actions + 1) * sizeof(char *));
1530 	new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
1531 						  (s->params.n_actions + 1) * sizeof(int));
1532 	new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
1533 						  (s->params.n_actions + 1) * sizeof(int));
1534 
1535 	if (!name ||
1536 	    !new_action_names ||
1537 	    !new_action_is_for_table_entries ||
1538 	    !new_action_is_for_default_entry) {
1539 		free(name);
1540 		free(new_action_names);
1541 		free(new_action_is_for_table_entries);
1542 		free(new_action_is_for_default_entry);
1543 
1544 		if (err_line)
1545 			*err_line = n_lines;
1546 		if (err_msg)
1547 			*err_msg = "Memory allocation failed.";
1548 		return -ENOMEM;
1549 	}
1550 
1551 	s->params.action_names = new_action_names;
1552 	s->params.action_names[s->params.n_actions] = name;
1553 
1554 	s->params.action_is_for_table_entries = new_action_is_for_table_entries;
1555 	s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
1556 
1557 	s->params.action_is_for_default_entry = new_action_is_for_default_entry;
1558 	s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
1559 
1560 	s->params.n_actions++;
1561 
1562 	return 0;
1563 }
1564 
1565 static int
1566 learner_statement_parse(struct learner_spec *s,
1567 		      uint32_t *block_mask,
1568 		      char **tokens,
1569 		      uint32_t n_tokens,
1570 		      uint32_t n_lines,
1571 		      uint32_t *err_line,
1572 		      const char **err_msg)
1573 {
1574 	/* Check format. */
1575 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1576 		if (err_line)
1577 			*err_line = n_lines;
1578 		if (err_msg)
1579 			*err_msg = "Invalid learner statement.";
1580 		return -EINVAL;
1581 	}
1582 
1583 	/* spec. */
1584 	s->name = strdup(tokens[1]);
1585 	if (!s->name) {
1586 		if (err_line)
1587 			*err_line = n_lines;
1588 		if (err_msg)
1589 			*err_msg = "Memory allocation failed.";
1590 		return -ENOMEM;
1591 	}
1592 
1593 	/* block_mask. */
1594 	*block_mask |= 1 << LEARNER_BLOCK;
1595 
1596 	return 0;
1597 }
1598 
1599 static int
1600 learner_block_parse(struct learner_spec *s,
1601 		    uint32_t *block_mask,
1602 		    char **tokens,
1603 		    uint32_t n_tokens,
1604 		    uint32_t n_lines,
1605 		    uint32_t *err_line,
1606 		    const char **err_msg)
1607 {
1608 	if (*block_mask & (1 << LEARNER_KEY_BLOCK))
1609 		return learner_key_block_parse(s,
1610 					       block_mask,
1611 					       tokens,
1612 					       n_tokens,
1613 					       n_lines,
1614 					       err_line,
1615 					       err_msg);
1616 
1617 	if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
1618 		return learner_actions_block_parse(s,
1619 						   block_mask,
1620 						   tokens,
1621 						   n_tokens,
1622 						   n_lines,
1623 						   err_line,
1624 						   err_msg);
1625 
1626 	/* Handle end of block. */
1627 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1628 		*block_mask &= ~(1 << LEARNER_BLOCK);
1629 		return 0;
1630 	}
1631 
1632 	if (!strcmp(tokens[0], "key"))
1633 		return learner_key_statement_parse(block_mask,
1634 						   tokens,
1635 						   n_tokens,
1636 						   n_lines,
1637 						   err_line,
1638 						   err_msg);
1639 
1640 	if (!strcmp(tokens[0], "actions"))
1641 		return learner_actions_statement_parse(block_mask,
1642 						       tokens,
1643 						       n_tokens,
1644 						       n_lines,
1645 						       err_line,
1646 						       err_msg);
1647 
1648 	if (!strcmp(tokens[0], "default_action")) {
1649 		if (((n_tokens != 4) && (n_tokens != 5)) ||
1650 		    strcmp(tokens[2], "args") ||
1651 		    strcmp(tokens[3], "none") ||
1652 		    ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
1653 			if (err_line)
1654 				*err_line = n_lines;
1655 			if (err_msg)
1656 				*err_msg = "Invalid default_action statement.";
1657 			return -EINVAL;
1658 		}
1659 
1660 		if (s->params.default_action_name) {
1661 			if (err_line)
1662 				*err_line = n_lines;
1663 			if (err_msg)
1664 				*err_msg = "Duplicate default_action stmt.";
1665 			return -EINVAL;
1666 		}
1667 
1668 		s->params.default_action_name = strdup(tokens[1]);
1669 		if (!s->params.default_action_name) {
1670 			if (err_line)
1671 				*err_line = n_lines;
1672 			if (err_msg)
1673 				*err_msg = "Memory allocation failed.";
1674 			return -ENOMEM;
1675 		}
1676 
1677 		if (n_tokens == 5)
1678 			s->params.default_action_is_const = 1;
1679 
1680 		return 0;
1681 	}
1682 
1683 	if (!strcmp(tokens[0], "size")) {
1684 		char *p = tokens[1];
1685 
1686 		if (n_tokens != 2) {
1687 			if (err_line)
1688 				*err_line = n_lines;
1689 			if (err_msg)
1690 				*err_msg = "Invalid size statement.";
1691 			return -EINVAL;
1692 		}
1693 
1694 		s->size = strtoul(p, &p, 0);
1695 		if (p[0]) {
1696 			if (err_line)
1697 				*err_line = n_lines;
1698 			if (err_msg)
1699 				*err_msg = "Invalid size argument.";
1700 			return -EINVAL;
1701 		}
1702 
1703 		return 0;
1704 	}
1705 
1706 	if (!strcmp(tokens[0], "timeout")) {
1707 		char *p = tokens[1];
1708 
1709 		if (n_tokens != 2) {
1710 			if (err_line)
1711 				*err_line = n_lines;
1712 			if (err_msg)
1713 				*err_msg = "Invalid timeout statement.";
1714 			return -EINVAL;
1715 		}
1716 
1717 		s->timeout = strtoul(p, &p, 0);
1718 		if (p[0]) {
1719 			if (err_line)
1720 				*err_line = n_lines;
1721 			if (err_msg)
1722 				*err_msg = "Invalid timeout argument.";
1723 			return -EINVAL;
1724 		}
1725 
1726 		return 0;
1727 	}
1728 
1729 	/* Anything else. */
1730 	if (err_line)
1731 		*err_line = n_lines;
1732 	if (err_msg)
1733 		*err_msg = "Invalid statement.";
1734 	return -EINVAL;
1735 }
1736 
1737 /*
1738  * regarray.
1739  *
1740  * regarray NAME size SIZE initval INITVAL
1741  */
1742 struct regarray_spec {
1743 	char *name;
1744 	uint64_t init_val;
1745 	uint32_t size;
1746 };
1747 
1748 static void
1749 regarray_spec_free(struct regarray_spec *s)
1750 {
1751 	if (!s)
1752 		return;
1753 
1754 	free(s->name);
1755 	s->name = NULL;
1756 }
1757 
1758 static int
1759 regarray_statement_parse(struct regarray_spec *s,
1760 			 char **tokens,
1761 			 uint32_t n_tokens,
1762 			 uint32_t n_lines,
1763 			 uint32_t *err_line,
1764 			 const char **err_msg)
1765 {
1766 	char *p;
1767 
1768 	/* Check format. */
1769 	if ((n_tokens != 6) ||
1770 	     strcmp(tokens[2], "size") ||
1771 	     strcmp(tokens[4], "initval")) {
1772 		if (err_line)
1773 			*err_line = n_lines;
1774 		if (err_msg)
1775 			*err_msg = "Invalid regarray statement.";
1776 		return -EINVAL;
1777 	}
1778 
1779 	/* spec. */
1780 	s->name = strdup(tokens[1]);
1781 	if (!s->name) {
1782 		if (err_line)
1783 			*err_line = n_lines;
1784 		if (err_msg)
1785 			*err_msg = "Memory allocation failed.";
1786 		return -ENOMEM;
1787 	}
1788 
1789 	p = tokens[3];
1790 	s->size = strtoul(p, &p, 0);
1791 	if (p[0] || !s->size) {
1792 		if (err_line)
1793 			*err_line = n_lines;
1794 		if (err_msg)
1795 			*err_msg = "Invalid size argument.";
1796 		return -EINVAL;
1797 	}
1798 
1799 	p = tokens[5];
1800 	s->init_val = strtoull(p, &p, 0);
1801 	if (p[0]) {
1802 		if (err_line)
1803 			*err_line = n_lines;
1804 		if (err_msg)
1805 			*err_msg = "Invalid initval argument.";
1806 		return -EINVAL;
1807 	}
1808 
1809 	return 0;
1810 }
1811 
1812 /*
1813  * metarray.
1814  *
1815  * metarray NAME size SIZE
1816  */
1817 struct metarray_spec {
1818 	char *name;
1819 	uint32_t size;
1820 };
1821 
1822 static void
1823 metarray_spec_free(struct metarray_spec *s)
1824 {
1825 	if (!s)
1826 		return;
1827 
1828 	free(s->name);
1829 	s->name = NULL;
1830 }
1831 
1832 static int
1833 metarray_statement_parse(struct metarray_spec *s,
1834 			 char **tokens,
1835 			 uint32_t n_tokens,
1836 			 uint32_t n_lines,
1837 			 uint32_t *err_line,
1838 			 const char **err_msg)
1839 {
1840 	char *p;
1841 
1842 	/* Check format. */
1843 	if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
1844 		if (err_line)
1845 			*err_line = n_lines;
1846 		if (err_msg)
1847 			*err_msg = "Invalid metarray statement.";
1848 		return -EINVAL;
1849 	}
1850 
1851 	/* spec. */
1852 	s->name = strdup(tokens[1]);
1853 	if (!s->name) {
1854 		if (err_line)
1855 			*err_line = n_lines;
1856 		if (err_msg)
1857 			*err_msg = "Memory allocation failed.";
1858 		return -ENOMEM;
1859 	}
1860 
1861 	p = tokens[3];
1862 	s->size = strtoul(p, &p, 0);
1863 	if (p[0] || !s->size) {
1864 		if (err_line)
1865 			*err_line = n_lines;
1866 		if (err_msg)
1867 			*err_msg = "Invalid size argument.";
1868 		return -EINVAL;
1869 	}
1870 
1871 	return 0;
1872 }
1873 
1874 /*
1875  * apply.
1876  *
1877  * apply {
1878  *	INSTRUCTION
1879  *	...
1880  * }
1881  */
1882 struct apply_spec {
1883 	const char **instructions;
1884 	uint32_t n_instructions;
1885 };
1886 
1887 static void
1888 apply_spec_free(struct apply_spec *s)
1889 {
1890 	uint32_t i;
1891 
1892 	if (!s)
1893 		return;
1894 
1895 	for (i = 0; i < s->n_instructions; i++) {
1896 		uintptr_t instr = (uintptr_t)s->instructions[i];
1897 
1898 		free((void *)instr);
1899 	}
1900 
1901 	free(s->instructions);
1902 	s->instructions = NULL;
1903 
1904 	s->n_instructions = 0;
1905 }
1906 
1907 static int
1908 apply_statement_parse(uint32_t *block_mask,
1909 		      char **tokens,
1910 		      uint32_t n_tokens,
1911 		      uint32_t n_lines,
1912 		      uint32_t *err_line,
1913 		      const char **err_msg)
1914 {
1915 	/* Check format. */
1916 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1917 		if (err_line)
1918 			*err_line = n_lines;
1919 		if (err_msg)
1920 			*err_msg = "Invalid apply statement.";
1921 		return -EINVAL;
1922 	}
1923 
1924 	/* block_mask. */
1925 	*block_mask |= 1 << APPLY_BLOCK;
1926 
1927 	return 0;
1928 }
1929 
1930 static int
1931 apply_block_parse(struct apply_spec *s,
1932 		  uint32_t *block_mask,
1933 		  char **tokens,
1934 		  uint32_t n_tokens,
1935 		  uint32_t n_lines,
1936 		  uint32_t *err_line,
1937 		  const char **err_msg)
1938 {
1939 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1940 	const char **new_instructions;
1941 	uint32_t i;
1942 
1943 	/* Handle end of block. */
1944 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1945 		*block_mask &= ~(1 << APPLY_BLOCK);
1946 		return 0;
1947 	}
1948 
1949 	/* spec. */
1950 	buffer[0] = 0;
1951 	for (i = 0; i < n_tokens; i++) {
1952 		if (i)
1953 			strcat(buffer, " ");
1954 		strcat(buffer, tokens[i]);
1955 	}
1956 
1957 	instr = strdup(buffer);
1958 	if (!instr) {
1959 		if (err_line)
1960 			*err_line = n_lines;
1961 		if (err_msg)
1962 			*err_msg = "Memory allocation failed.";
1963 		return -ENOMEM;
1964 	}
1965 
1966 	new_instructions = realloc(s->instructions,
1967 				   (s->n_instructions + 1) * sizeof(char *));
1968 	if (!new_instructions) {
1969 		free(instr);
1970 
1971 		if (err_line)
1972 			*err_line = n_lines;
1973 		if (err_msg)
1974 			*err_msg = "Memory allocation failed.";
1975 		return -ENOMEM;
1976 	}
1977 
1978 	s->instructions = new_instructions;
1979 	s->instructions[s->n_instructions] = instr;
1980 	s->n_instructions++;
1981 
1982 	return 0;
1983 }
1984 
1985 /*
1986  * Pipeline.
1987  */
1988 int
1989 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1990 				 FILE *spec,
1991 				 uint32_t *err_line,
1992 				 const char **err_msg)
1993 {
1994 	struct extobj_spec extobj_spec = {0};
1995 	struct struct_spec struct_spec = {0};
1996 	struct header_spec header_spec = {0};
1997 	struct metadata_spec metadata_spec = {0};
1998 	struct action_spec action_spec = {0};
1999 	struct table_spec table_spec = {0};
2000 	struct selector_spec selector_spec = {0};
2001 	struct learner_spec learner_spec = {0};
2002 	struct regarray_spec regarray_spec = {0};
2003 	struct metarray_spec metarray_spec = {0};
2004 	struct apply_spec apply_spec = {0};
2005 	uint32_t n_lines;
2006 	uint32_t block_mask = 0;
2007 	int status;
2008 
2009 	/* Check the input arguments. */
2010 	if (!p) {
2011 		if (err_line)
2012 			*err_line = 0;
2013 		if (err_msg)
2014 			*err_msg = "Null pipeline arument.";
2015 		status = -EINVAL;
2016 		goto error;
2017 	}
2018 
2019 	if (!spec) {
2020 		if (err_line)
2021 			*err_line = 0;
2022 		if (err_msg)
2023 			*err_msg = "Null specification file argument.";
2024 		status = -EINVAL;
2025 		goto error;
2026 	}
2027 
2028 	for (n_lines = 1; ; n_lines++) {
2029 		char line[MAX_LINE_LENGTH];
2030 		char *tokens[MAX_TOKENS], *ptr = line;
2031 		uint32_t n_tokens = 0;
2032 
2033 		/* Read next line. */
2034 		if (!fgets(line, sizeof(line), spec))
2035 			break;
2036 
2037 		/* Parse the line into tokens. */
2038 		for ( ; ; ) {
2039 			char *token;
2040 
2041 			/* Get token. */
2042 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
2043 			if (!token)
2044 				break;
2045 
2046 			/* Handle comments. */
2047 			if ((token[0] == '#') ||
2048 			    (token[0] == ';') ||
2049 			    ((token[0] == '/') && (token[1] == '/'))) {
2050 				break;
2051 			}
2052 
2053 			/* Handle excessively long lines. */
2054 			if (n_tokens >= MAX_TOKENS) {
2055 				if (err_line)
2056 					*err_line = n_lines;
2057 				if (err_msg)
2058 					*err_msg = "Too many tokens.";
2059 				status = -EINVAL;
2060 				goto error;
2061 			}
2062 
2063 			/* Handle excessively long tokens. */
2064 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2065 			    RTE_SWX_NAME_SIZE) {
2066 				if (err_line)
2067 					*err_line = n_lines;
2068 				if (err_msg)
2069 					*err_msg = "Token too big.";
2070 				status = -EINVAL;
2071 				goto error;
2072 			}
2073 
2074 			/* Save token. */
2075 			tokens[n_tokens] = token;
2076 			n_tokens++;
2077 		}
2078 
2079 		/* Handle empty lines. */
2080 		if (!n_tokens)
2081 			continue;
2082 
2083 		/* struct block. */
2084 		if (block_mask & (1 << STRUCT_BLOCK)) {
2085 			status = struct_block_parse(&struct_spec,
2086 						    &block_mask,
2087 						    tokens,
2088 						    n_tokens,
2089 						    n_lines,
2090 						    err_line,
2091 						    err_msg);
2092 			if (status)
2093 				goto error;
2094 
2095 			if (block_mask & (1 << STRUCT_BLOCK))
2096 				continue;
2097 
2098 			/* End of block. */
2099 			status = rte_swx_pipeline_struct_type_register(p,
2100 				struct_spec.name,
2101 				struct_spec.fields,
2102 				struct_spec.n_fields,
2103 				struct_spec.varbit);
2104 			if (status) {
2105 				if (err_line)
2106 					*err_line = n_lines;
2107 				if (err_msg)
2108 					*err_msg = "Struct registration error.";
2109 				goto error;
2110 			}
2111 
2112 			struct_spec_free(&struct_spec);
2113 
2114 			continue;
2115 		}
2116 
2117 		/* action block. */
2118 		if (block_mask & (1 << ACTION_BLOCK)) {
2119 			status = action_block_parse(&action_spec,
2120 						    &block_mask,
2121 						    tokens,
2122 						    n_tokens,
2123 						    n_lines,
2124 						    err_line,
2125 						    err_msg);
2126 			if (status)
2127 				goto error;
2128 
2129 			if (block_mask & (1 << ACTION_BLOCK))
2130 				continue;
2131 
2132 			/* End of block. */
2133 			status = rte_swx_pipeline_action_config(p,
2134 				action_spec.name,
2135 				action_spec.args_struct_type_name,
2136 				action_spec.instructions,
2137 				action_spec.n_instructions);
2138 			if (status) {
2139 				if (err_line)
2140 					*err_line = n_lines;
2141 				if (err_msg)
2142 					*err_msg = "Action config error.";
2143 				goto error;
2144 			}
2145 
2146 			action_spec_free(&action_spec);
2147 
2148 			continue;
2149 		}
2150 
2151 		/* table block. */
2152 		if (block_mask & (1 << TABLE_BLOCK)) {
2153 			status = table_block_parse(&table_spec,
2154 						   &block_mask,
2155 						   tokens,
2156 						   n_tokens,
2157 						   n_lines,
2158 						   err_line,
2159 						   err_msg);
2160 			if (status)
2161 				goto error;
2162 
2163 			if (block_mask & (1 << TABLE_BLOCK))
2164 				continue;
2165 
2166 			/* End of block. */
2167 			status = rte_swx_pipeline_table_config(p,
2168 				table_spec.name,
2169 				&table_spec.params,
2170 				table_spec.recommended_table_type_name,
2171 				table_spec.args,
2172 				table_spec.size);
2173 			if (status) {
2174 				if (err_line)
2175 					*err_line = n_lines;
2176 				if (err_msg)
2177 					*err_msg = "Table configuration error.";
2178 				goto error;
2179 			}
2180 
2181 			table_spec_free(&table_spec);
2182 
2183 			continue;
2184 		}
2185 
2186 		/* selector block. */
2187 		if (block_mask & (1 << SELECTOR_BLOCK)) {
2188 			status = selector_block_parse(&selector_spec,
2189 						      &block_mask,
2190 						      tokens,
2191 						      n_tokens,
2192 						      n_lines,
2193 						      err_line,
2194 						      err_msg);
2195 			if (status)
2196 				goto error;
2197 
2198 			if (block_mask & (1 << SELECTOR_BLOCK))
2199 				continue;
2200 
2201 			/* End of block. */
2202 			status = rte_swx_pipeline_selector_config(p,
2203 				selector_spec.name,
2204 				&selector_spec.params);
2205 			if (status) {
2206 				if (err_line)
2207 					*err_line = n_lines;
2208 				if (err_msg)
2209 					*err_msg = "Selector configuration error.";
2210 				goto error;
2211 			}
2212 
2213 			selector_spec_free(&selector_spec);
2214 
2215 			continue;
2216 		}
2217 
2218 		/* learner block. */
2219 		if (block_mask & (1 << LEARNER_BLOCK)) {
2220 			status = learner_block_parse(&learner_spec,
2221 						     &block_mask,
2222 						     tokens,
2223 						     n_tokens,
2224 						     n_lines,
2225 						     err_line,
2226 						     err_msg);
2227 			if (status)
2228 				goto error;
2229 
2230 			if (block_mask & (1 << LEARNER_BLOCK))
2231 				continue;
2232 
2233 			/* End of block. */
2234 			status = rte_swx_pipeline_learner_config(p,
2235 				learner_spec.name,
2236 				&learner_spec.params,
2237 				learner_spec.size,
2238 				learner_spec.timeout);
2239 			if (status) {
2240 				if (err_line)
2241 					*err_line = n_lines;
2242 				if (err_msg)
2243 					*err_msg = "Learner table configuration error.";
2244 				goto error;
2245 			}
2246 
2247 			learner_spec_free(&learner_spec);
2248 
2249 			continue;
2250 		}
2251 
2252 		/* apply block. */
2253 		if (block_mask & (1 << APPLY_BLOCK)) {
2254 			status = apply_block_parse(&apply_spec,
2255 						   &block_mask,
2256 						   tokens,
2257 						   n_tokens,
2258 						   n_lines,
2259 						   err_line,
2260 						   err_msg);
2261 			if (status)
2262 				goto error;
2263 
2264 			if (block_mask & (1 << APPLY_BLOCK))
2265 				continue;
2266 
2267 			/* End of block. */
2268 			status = rte_swx_pipeline_instructions_config(p,
2269 				apply_spec.instructions,
2270 				apply_spec.n_instructions);
2271 			if (status) {
2272 				if (err_line)
2273 					*err_line = n_lines;
2274 				if (err_msg)
2275 					*err_msg = "Pipeline instructions err.";
2276 				goto error;
2277 			}
2278 
2279 			apply_spec_free(&apply_spec);
2280 
2281 			continue;
2282 		}
2283 
2284 		/* extobj. */
2285 		if (!strcmp(tokens[0], "extobj")) {
2286 			status = extobj_statement_parse(&extobj_spec,
2287 							tokens,
2288 							n_tokens,
2289 							n_lines,
2290 							err_line,
2291 							err_msg);
2292 			if (status)
2293 				goto error;
2294 
2295 			status = rte_swx_pipeline_extern_object_config(p,
2296 				extobj_spec.name,
2297 				extobj_spec.extern_type_name,
2298 				extobj_spec.pragma);
2299 			if (status) {
2300 				if (err_line)
2301 					*err_line = n_lines;
2302 				if (err_msg)
2303 					*err_msg = "Extern object config err.";
2304 				goto error;
2305 			}
2306 
2307 			extobj_spec_free(&extobj_spec);
2308 
2309 			continue;
2310 		}
2311 
2312 		/* struct. */
2313 		if (!strcmp(tokens[0], "struct")) {
2314 			status = struct_statement_parse(&struct_spec,
2315 							&block_mask,
2316 							tokens,
2317 							n_tokens,
2318 							n_lines,
2319 							err_line,
2320 							err_msg);
2321 			if (status)
2322 				goto error;
2323 
2324 			continue;
2325 		}
2326 
2327 		/* header. */
2328 		if (!strcmp(tokens[0], "header")) {
2329 			status = header_statement_parse(&header_spec,
2330 							tokens,
2331 							n_tokens,
2332 							n_lines,
2333 							err_line,
2334 							err_msg);
2335 			if (status)
2336 				goto error;
2337 
2338 			status = rte_swx_pipeline_packet_header_register(p,
2339 				header_spec.name,
2340 				header_spec.struct_type_name);
2341 			if (status) {
2342 				if (err_line)
2343 					*err_line = n_lines;
2344 				if (err_msg)
2345 					*err_msg = "Header registration error.";
2346 				goto error;
2347 			}
2348 
2349 			header_spec_free(&header_spec);
2350 
2351 			continue;
2352 		}
2353 
2354 		/* metadata. */
2355 		if (!strcmp(tokens[0], "metadata")) {
2356 			status = metadata_statement_parse(&metadata_spec,
2357 							  tokens,
2358 							  n_tokens,
2359 							  n_lines,
2360 							  err_line,
2361 							  err_msg);
2362 			if (status)
2363 				goto error;
2364 
2365 			status = rte_swx_pipeline_packet_metadata_register(p,
2366 				metadata_spec.struct_type_name);
2367 			if (status) {
2368 				if (err_line)
2369 					*err_line = n_lines;
2370 				if (err_msg)
2371 					*err_msg = "Meta-data reg err.";
2372 				goto error;
2373 			}
2374 
2375 			metadata_spec_free(&metadata_spec);
2376 
2377 			continue;
2378 		}
2379 
2380 		/* action. */
2381 		if (!strcmp(tokens[0], "action")) {
2382 			status = action_statement_parse(&action_spec,
2383 							&block_mask,
2384 							tokens,
2385 							n_tokens,
2386 							n_lines,
2387 							err_line,
2388 							err_msg);
2389 			if (status)
2390 				goto error;
2391 
2392 			continue;
2393 		}
2394 
2395 		/* table. */
2396 		if (!strcmp(tokens[0], "table")) {
2397 			status = table_statement_parse(&table_spec,
2398 						       &block_mask,
2399 						       tokens,
2400 						       n_tokens,
2401 						       n_lines,
2402 						       err_line,
2403 						       err_msg);
2404 			if (status)
2405 				goto error;
2406 
2407 			continue;
2408 		}
2409 
2410 		/* selector. */
2411 		if (!strcmp(tokens[0], "selector")) {
2412 			status = selector_statement_parse(&selector_spec,
2413 							  &block_mask,
2414 							  tokens,
2415 							  n_tokens,
2416 							  n_lines,
2417 							  err_line,
2418 							  err_msg);
2419 			if (status)
2420 				goto error;
2421 
2422 			continue;
2423 		}
2424 
2425 		/* learner. */
2426 		if (!strcmp(tokens[0], "learner")) {
2427 			status = learner_statement_parse(&learner_spec,
2428 							 &block_mask,
2429 							 tokens,
2430 							 n_tokens,
2431 							 n_lines,
2432 							 err_line,
2433 							 err_msg);
2434 			if (status)
2435 				goto error;
2436 
2437 			continue;
2438 		}
2439 
2440 		/* regarray. */
2441 		if (!strcmp(tokens[0], "regarray")) {
2442 			status = regarray_statement_parse(&regarray_spec,
2443 							  tokens,
2444 							  n_tokens,
2445 							  n_lines,
2446 							  err_line,
2447 							  err_msg);
2448 			if (status)
2449 				goto error;
2450 
2451 			status = rte_swx_pipeline_regarray_config(p,
2452 				regarray_spec.name,
2453 				regarray_spec.size,
2454 				regarray_spec.init_val);
2455 			if (status) {
2456 				if (err_line)
2457 					*err_line = n_lines;
2458 				if (err_msg)
2459 					*err_msg = "Register array configuration error.";
2460 				goto error;
2461 			}
2462 
2463 			regarray_spec_free(&regarray_spec);
2464 
2465 			continue;
2466 		}
2467 
2468 		/* metarray. */
2469 		if (!strcmp(tokens[0], "metarray")) {
2470 			status = metarray_statement_parse(&metarray_spec,
2471 							  tokens,
2472 							  n_tokens,
2473 							  n_lines,
2474 							  err_line,
2475 							  err_msg);
2476 			if (status)
2477 				goto error;
2478 
2479 			status = rte_swx_pipeline_metarray_config(p,
2480 				metarray_spec.name,
2481 				metarray_spec.size);
2482 			if (status) {
2483 				if (err_line)
2484 					*err_line = n_lines;
2485 				if (err_msg)
2486 					*err_msg = "Meter array configuration error.";
2487 				goto error;
2488 			}
2489 
2490 			metarray_spec_free(&metarray_spec);
2491 
2492 			continue;
2493 		}
2494 
2495 		/* apply. */
2496 		if (!strcmp(tokens[0], "apply")) {
2497 			status = apply_statement_parse(&block_mask,
2498 						       tokens,
2499 						       n_tokens,
2500 						       n_lines,
2501 						       err_line,
2502 						       err_msg);
2503 			if (status)
2504 				goto error;
2505 
2506 			continue;
2507 		}
2508 
2509 		/* Anything else. */
2510 		if (err_line)
2511 			*err_line = n_lines;
2512 		if (err_msg)
2513 			*err_msg = "Unknown statement.";
2514 		status = -EINVAL;
2515 		goto error;
2516 	}
2517 
2518 	/* Handle unfinished block. */
2519 	if (block_mask) {
2520 		if (err_line)
2521 			*err_line = n_lines;
2522 		if (err_msg)
2523 			*err_msg = "Missing }.";
2524 		status = -EINVAL;
2525 		goto error;
2526 	}
2527 
2528 	/* Pipeline build. */
2529 	status = rte_swx_pipeline_build(p);
2530 	if (status) {
2531 		if (err_line)
2532 			*err_line = n_lines;
2533 		if (err_msg)
2534 			*err_msg = "Pipeline build error.";
2535 		goto error;
2536 	}
2537 
2538 	return 0;
2539 
2540 error:
2541 	extobj_spec_free(&extobj_spec);
2542 	struct_spec_free(&struct_spec);
2543 	header_spec_free(&header_spec);
2544 	metadata_spec_free(&metadata_spec);
2545 	action_spec_free(&action_spec);
2546 	table_spec_free(&table_spec);
2547 	selector_spec_free(&selector_spec);
2548 	learner_spec_free(&learner_spec);
2549 	regarray_spec_free(&regarray_spec);
2550 	metarray_spec_free(&metarray_spec);
2551 	apply_spec_free(&apply_spec);
2552 	return status;
2553 }
2554