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