xref: /dpdk/lib/pipeline/rte_swx_pipeline_spec.c (revision 7faf4bd32566446fa0815eef743523ce6a95a355)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdint.h>
5 #include <inttypes.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 
11 #include <rte_common.h>
12 #include <rte_mempool.h>
13 
14 #include <rte_swx_port_ethdev.h>
15 #include <rte_swx_port_ring.h>
16 #include <rte_swx_port_source_sink.h>
17 #include <rte_swx_port_fd.h>
18 
19 #include "rte_swx_pipeline_spec.h"
20 
21 #ifndef MAX_LINE_LENGTH
22 #define MAX_LINE_LENGTH 2048
23 #endif
24 
25 #ifndef MAX_TOKENS
26 #define MAX_TOKENS 256
27 #endif
28 
29 #define STRUCT_BLOCK 0
30 #define ACTION_BLOCK 1
31 #define TABLE_BLOCK 2
32 #define TABLE_KEY_BLOCK 3
33 #define TABLE_ACTIONS_BLOCK 4
34 #define SELECTOR_BLOCK 5
35 #define SELECTOR_SELECTOR_BLOCK 6
36 #define LEARNER_BLOCK 7
37 #define LEARNER_KEY_BLOCK 8
38 #define LEARNER_ACTIONS_BLOCK 9
39 #define LEARNER_TIMEOUT_BLOCK 10
40 #define APPLY_BLOCK 11
41 
42 /*
43  * extobj.
44  */
45 static void
46 extobj_spec_free(struct extobj_spec *s)
47 {
48 	if (!s)
49 		return;
50 
51 	free(s->name);
52 	s->name = NULL;
53 
54 	free(s->extern_type_name);
55 	s->extern_type_name = NULL;
56 
57 	free(s->pragma);
58 	s->pragma = NULL;
59 }
60 
61 static int
62 extobj_statement_parse(struct extobj_spec *s,
63 		       char **tokens,
64 		       uint32_t n_tokens,
65 		       uint32_t n_lines,
66 		       uint32_t *err_line,
67 		       const char **err_msg)
68 {
69 	/* Check format. */
70 	if (((n_tokens != 4) && (n_tokens != 6)) ||
71 	    ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
72 	    ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
73 				 strcmp(tokens[4], "pragma")))) {
74 		if (err_line)
75 			*err_line = n_lines;
76 		if (err_msg)
77 			*err_msg = "Invalid extobj statement.";
78 		return -EINVAL;
79 	}
80 
81 	/* spec. */
82 	s->name = strdup(tokens[1]);
83 	s->extern_type_name = strdup(tokens[3]);
84 	s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
85 
86 	if (!s->name ||
87 	    !s->extern_type_name ||
88 	    ((n_tokens == 6) && !s->pragma)) {
89 		free(s->name);
90 		free(s->extern_type_name);
91 		free(s->pragma);
92 
93 		if (err_line)
94 			*err_line = n_lines;
95 		if (err_msg)
96 			*err_msg = "Memory allocation failed.";
97 		return -ENOMEM;
98 	}
99 
100 	return 0;
101 }
102 
103 /*
104  * struct.
105  *
106  */
107 static void
108 struct_spec_free(struct struct_spec *s)
109 {
110 	uint32_t i;
111 
112 	if (!s)
113 		return;
114 
115 	free(s->name);
116 	s->name = NULL;
117 
118 	for (i = 0; i < s->n_fields; i++) {
119 		uintptr_t name = (uintptr_t)s->fields[i].name;
120 
121 		free((void *)name);
122 	}
123 
124 	free(s->fields);
125 	s->fields = NULL;
126 
127 	s->n_fields = 0;
128 
129 	s->varbit = 0;
130 }
131 
132 static int
133 struct_statement_parse(struct struct_spec *s,
134 		       uint32_t *block_mask,
135 		       char **tokens,
136 		       uint32_t n_tokens,
137 		       uint32_t n_lines,
138 		       uint32_t *err_line,
139 		       const char **err_msg)
140 {
141 	/* Check format. */
142 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
143 		if (err_line)
144 			*err_line = n_lines;
145 		if (err_msg)
146 			*err_msg = "Invalid struct statement.";
147 		return -EINVAL;
148 	}
149 
150 	/* spec. */
151 	s->name = strdup(tokens[1]);
152 	if (!s->name) {
153 		if (err_line)
154 			*err_line = n_lines;
155 		if (err_msg)
156 			*err_msg = "Memory allocation failed.";
157 		return -ENOMEM;
158 	}
159 
160 	/* block_mask. */
161 	*block_mask |= 1 << STRUCT_BLOCK;
162 
163 	return 0;
164 }
165 
166 static int
167 struct_block_parse(struct struct_spec *s,
168 		   uint32_t *block_mask,
169 		   char **tokens,
170 		   uint32_t n_tokens,
171 		   uint32_t n_lines,
172 		   uint32_t *err_line,
173 		   const char **err_msg)
174 {
175 	struct rte_swx_field_params *new_fields;
176 	char *p = tokens[0], *name = NULL;
177 	uint32_t n_bits;
178 	int varbit = 0, error = 0, error_size_invalid = 0, error_varbit_not_last = 0;
179 
180 	/* Handle end of block. */
181 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
182 		*block_mask &= ~(1 << STRUCT_BLOCK);
183 		return 0;
184 	}
185 
186 	/* Check format. */
187 	if (n_tokens != 2) {
188 		error = -EINVAL;
189 		goto error;
190 	}
191 
192 	if (s->varbit) {
193 		error = -EINVAL;
194 		error_varbit_not_last = 1;
195 		goto error;
196 	}
197 
198 	if (!strncmp(p, "bit<", strlen("bit<"))) {
199 		size_t len = strlen(p);
200 
201 		if ((len < strlen("bit< >")) || (p[len - 1] != '>')) {
202 			error = -EINVAL;
203 			goto error;
204 		}
205 
206 		/* Remove the "bit<" and ">". */
207 		p[strlen(p) - 1] = 0;
208 		p += strlen("bit<");
209 	} else if (!strncmp(p, "varbit<", strlen("varbit<"))) {
210 		size_t len = strlen(p);
211 
212 		if ((len < strlen("varbit< >")) || (p[len - 1] != '>')) {
213 			error = -EINVAL;
214 			goto error;
215 		}
216 
217 		/* Remove the "varbit<" and ">". */
218 		p[strlen(p) - 1] = 0;
219 		p += strlen("varbit<");
220 
221 		/* Set the varbit flag. */
222 		varbit = 1;
223 	} else {
224 		error = -EINVAL;
225 		goto error;
226 	}
227 
228 	n_bits = strtoul(p, &p, 0);
229 	if ((p[0]) ||
230 	    !n_bits ||
231 	    (n_bits % 8)) {
232 		error = -EINVAL;
233 		error_size_invalid = 1;
234 		goto error;
235 	}
236 
237 	/* spec. */
238 	name = strdup(tokens[1]);
239 	if (!name) {
240 		error = -ENOMEM;
241 		goto error;
242 	}
243 
244 	new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
245 	if (!new_fields) {
246 		error = -ENOMEM;
247 		goto error;
248 	}
249 
250 	s->fields = new_fields;
251 	s->fields[s->n_fields].name = name;
252 	s->fields[s->n_fields].n_bits = n_bits;
253 	s->n_fields++;
254 	s->varbit = varbit;
255 
256 	return 0;
257 
258 error:
259 	free(name);
260 
261 	if (err_line)
262 		*err_line = n_lines;
263 
264 	if (err_msg) {
265 		*err_msg = "Invalid struct field statement.";
266 
267 		if ((error == -EINVAL) && error_varbit_not_last)
268 			*err_msg = "Varbit field is not the last struct field.";
269 
270 		if ((error == -EINVAL) && error_size_invalid)
271 			*err_msg = "Invalid struct field size.";
272 
273 		if (error == -ENOMEM)
274 			*err_msg = "Memory allocation failed.";
275 	}
276 
277 	return error;
278 }
279 
280 /*
281  * header.
282  *
283  */
284 static void
285 header_spec_free(struct header_spec *s)
286 {
287 	if (!s)
288 		return;
289 
290 	free(s->name);
291 	s->name = NULL;
292 
293 	free(s->struct_type_name);
294 	s->struct_type_name = NULL;
295 }
296 
297 static int
298 header_statement_parse(struct header_spec *s,
299 		       char **tokens,
300 		       uint32_t n_tokens,
301 		       uint32_t n_lines,
302 		       uint32_t *err_line,
303 		       const char **err_msg)
304 {
305 	/* Check format. */
306 	if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
307 		if (err_line)
308 			*err_line = n_lines;
309 		if (err_msg)
310 			*err_msg = "Invalid header statement.";
311 		return -EINVAL;
312 	}
313 
314 	/* spec. */
315 	s->name = strdup(tokens[1]);
316 	s->struct_type_name = strdup(tokens[3]);
317 
318 	if (!s->name || !s->struct_type_name) {
319 		free(s->name);
320 		free(s->struct_type_name);
321 
322 		if (err_line)
323 			*err_line = n_lines;
324 		if (err_msg)
325 			*err_msg = "Memory allocation failed.";
326 		return -ENOMEM;
327 	}
328 
329 	return 0;
330 }
331 
332 /*
333  * metadata.
334  *
335  */
336 static void
337 metadata_spec_free(struct metadata_spec *s)
338 {
339 	if (!s)
340 		return;
341 
342 	free(s->struct_type_name);
343 	s->struct_type_name = NULL;
344 }
345 
346 static int
347 metadata_statement_parse(struct metadata_spec *s,
348 			 char **tokens,
349 			 uint32_t n_tokens,
350 			 uint32_t n_lines,
351 			 uint32_t *err_line,
352 			 const char **err_msg)
353 {
354 	/* Check format. */
355 	if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
356 		if (err_line)
357 			*err_line = n_lines;
358 		if (err_msg)
359 			*err_msg = "Invalid metadata statement.";
360 		return -EINVAL;
361 	}
362 
363 	/* spec. */
364 	s->struct_type_name = strdup(tokens[2]);
365 	if (!s->struct_type_name) {
366 		if (err_line)
367 			*err_line = n_lines;
368 		if (err_msg)
369 			*err_msg = "Memory allocation failed.";
370 		return -ENOMEM;
371 	}
372 
373 	return 0;
374 }
375 
376 /*
377  * action.
378  *
379  */
380 static void
381 action_spec_free(struct action_spec *s)
382 {
383 	uint32_t i;
384 
385 	if (!s)
386 		return;
387 
388 	free(s->name);
389 	s->name = NULL;
390 
391 	free(s->args_struct_type_name);
392 	s->args_struct_type_name = NULL;
393 
394 	for (i = 0; i < s->n_instructions; i++) {
395 		uintptr_t instr = (uintptr_t)s->instructions[i];
396 
397 		free((void *)instr);
398 	}
399 
400 	free(s->instructions);
401 	s->instructions = NULL;
402 
403 	s->n_instructions = 0;
404 }
405 
406 static int
407 action_statement_parse(struct action_spec *s,
408 		       uint32_t *block_mask,
409 		       char **tokens,
410 		       uint32_t n_tokens,
411 		       uint32_t n_lines,
412 		       uint32_t *err_line,
413 		       const char **err_msg)
414 {
415 	/* Check format. */
416 	if (((n_tokens != 5) && (n_tokens != 6)) ||
417 	    ((n_tokens == 5) &&
418 	     (strcmp(tokens[2], "args") ||
419 	      strcmp(tokens[3], "none") ||
420 	      strcmp(tokens[4], "{"))) ||
421 	    ((n_tokens == 6) &&
422 	     (strcmp(tokens[2], "args") ||
423 	      strcmp(tokens[3], "instanceof") ||
424 	      strcmp(tokens[5], "{")))) {
425 		if (err_line)
426 			*err_line = n_lines;
427 		if (err_msg)
428 			*err_msg = "Invalid action statement.";
429 		return -EINVAL;
430 	}
431 
432 	/* spec. */
433 	s->name = strdup(tokens[1]);
434 	s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
435 
436 	if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
437 		if (err_line)
438 			*err_line = n_lines;
439 		if (err_msg)
440 			*err_msg = "Memory allocation failed.";
441 		return -ENOMEM;
442 	}
443 
444 	/* block_mask. */
445 	*block_mask |= 1 << ACTION_BLOCK;
446 
447 	return 0;
448 }
449 
450 static int
451 action_block_parse(struct action_spec *s,
452 		   uint32_t *block_mask,
453 		   char **tokens,
454 		   uint32_t n_tokens,
455 		   uint32_t n_lines,
456 		   uint32_t *err_line,
457 		   const char **err_msg)
458 {
459 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
460 	const char **new_instructions;
461 	uint32_t i;
462 
463 	/* Handle end of block. */
464 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
465 		*block_mask &= ~(1 << ACTION_BLOCK);
466 		return 0;
467 	}
468 
469 	/* spec. */
470 	buffer[0] = 0;
471 	for (i = 0; i < n_tokens; i++) {
472 		if (i)
473 			strcat(buffer, " ");
474 		strcat(buffer, tokens[i]);
475 	}
476 
477 	instr = strdup(buffer);
478 	if (!instr) {
479 		if (err_line)
480 			*err_line = n_lines;
481 		if (err_msg)
482 			*err_msg = "Memory allocation failed.";
483 		return -ENOMEM;
484 	}
485 
486 	new_instructions = realloc(s->instructions,
487 				   (s->n_instructions + 1) * sizeof(char *));
488 	if (!new_instructions) {
489 		free(instr);
490 
491 		if (err_line)
492 			*err_line = n_lines;
493 		if (err_msg)
494 			*err_msg = "Memory allocation failed.";
495 		return -ENOMEM;
496 	}
497 
498 	s->instructions = new_instructions;
499 	s->instructions[s->n_instructions] = instr;
500 	s->n_instructions++;
501 
502 	return 0;
503 }
504 
505 /*
506  * table.
507  *
508  */
509 static void
510 table_spec_free(struct table_spec *s)
511 {
512 	uintptr_t default_action_name, default_action_args, hash_func_name;
513 	uint32_t i;
514 
515 	if (!s)
516 		return;
517 
518 	free(s->name);
519 	s->name = NULL;
520 
521 	for (i = 0; i < s->params.n_fields; i++) {
522 		uintptr_t name = (uintptr_t)s->params.fields[i].name;
523 
524 		free((void *)name);
525 	}
526 
527 	free(s->params.fields);
528 	s->params.fields = NULL;
529 
530 	s->params.n_fields = 0;
531 
532 	for (i = 0; i < s->params.n_actions; i++) {
533 		uintptr_t name = (uintptr_t)s->params.action_names[i];
534 
535 		free((void *)name);
536 	}
537 
538 	free(s->params.action_names);
539 	s->params.action_names = NULL;
540 
541 	s->params.n_actions = 0;
542 
543 	default_action_name = (uintptr_t)s->params.default_action_name;
544 	free((void *)default_action_name);
545 	s->params.default_action_name = NULL;
546 
547 	default_action_args = (uintptr_t)s->params.default_action_args;
548 	free((void *)default_action_args);
549 	s->params.default_action_args = NULL;
550 
551 	free(s->params.action_is_for_table_entries);
552 	s->params.action_is_for_table_entries = NULL;
553 
554 	free(s->params.action_is_for_default_entry);
555 	s->params.action_is_for_default_entry = NULL;
556 
557 	s->params.default_action_is_const = 0;
558 
559 	hash_func_name = (uintptr_t)s->params.hash_func_name;
560 	free((void *)hash_func_name);
561 	s->params.hash_func_name = NULL;
562 
563 	free(s->recommended_table_type_name);
564 	s->recommended_table_type_name = NULL;
565 
566 	free(s->args);
567 	s->args = NULL;
568 
569 	s->size = 0;
570 }
571 
572 static int
573 table_key_statement_parse(uint32_t *block_mask,
574 			  char **tokens,
575 			  uint32_t n_tokens,
576 			  uint32_t n_lines,
577 			  uint32_t *err_line,
578 			  const char **err_msg)
579 {
580 	/* Check format. */
581 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
582 		if (err_line)
583 			*err_line = n_lines;
584 		if (err_msg)
585 			*err_msg = "Invalid key statement.";
586 		return -EINVAL;
587 	}
588 
589 	/* block_mask. */
590 	*block_mask |= 1 << TABLE_KEY_BLOCK;
591 
592 	return 0;
593 }
594 
595 static int
596 table_key_block_parse(struct table_spec *s,
597 		      uint32_t *block_mask,
598 		      char **tokens,
599 		      uint32_t n_tokens,
600 		      uint32_t n_lines,
601 		      uint32_t *err_line,
602 		      const char **err_msg)
603 {
604 	struct rte_swx_match_field_params *new_fields;
605 	enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
606 	char *name;
607 
608 	/* Handle end of block. */
609 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
610 		*block_mask &= ~(1 << TABLE_KEY_BLOCK);
611 		return 0;
612 	}
613 
614 	/* Check input arguments. */
615 	if ((n_tokens != 2) ||
616 	    (strcmp(tokens[1], "exact") &&
617 	     strcmp(tokens[1], "wildcard") &&
618 	     strcmp(tokens[1], "lpm"))) {
619 		if (err_line)
620 			*err_line = n_lines;
621 		if (err_msg)
622 			*err_msg = "Invalid match field statement.";
623 		return -EINVAL;
624 	}
625 
626 	if (!strcmp(tokens[1], "wildcard"))
627 		match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
628 	if (!strcmp(tokens[1], "lpm"))
629 		match_type = RTE_SWX_TABLE_MATCH_LPM;
630 	if (!strcmp(tokens[1], "exact"))
631 		match_type = RTE_SWX_TABLE_MATCH_EXACT;
632 
633 	name = strdup(tokens[0]);
634 	if (!name) {
635 		if (err_line)
636 			*err_line = n_lines;
637 		if (err_msg)
638 			*err_msg = "Memory allocation failed.";
639 		return -ENOMEM;
640 	}
641 
642 	new_fields = realloc(s->params.fields,
643 			     (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
644 	if (!new_fields) {
645 		free(name);
646 
647 		if (err_line)
648 			*err_line = n_lines;
649 		if (err_msg)
650 			*err_msg = "Memory allocation failed.";
651 		return -ENOMEM;
652 	}
653 
654 	s->params.fields = new_fields;
655 	s->params.fields[s->params.n_fields].name = name;
656 	s->params.fields[s->params.n_fields].match_type = match_type;
657 	s->params.n_fields++;
658 
659 	return 0;
660 }
661 
662 static int
663 table_actions_statement_parse(uint32_t *block_mask,
664 			      char **tokens,
665 			      uint32_t n_tokens,
666 			      uint32_t n_lines,
667 			      uint32_t *err_line,
668 			      const char **err_msg)
669 {
670 	/* Check format. */
671 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
672 		if (err_line)
673 			*err_line = n_lines;
674 		if (err_msg)
675 			*err_msg = "Invalid actions statement.";
676 		return -EINVAL;
677 	}
678 
679 	/* block_mask. */
680 	*block_mask |= 1 << TABLE_ACTIONS_BLOCK;
681 
682 	return 0;
683 }
684 
685 static int
686 table_actions_block_parse(struct table_spec *s,
687 			  uint32_t *block_mask,
688 			  char **tokens,
689 			  uint32_t n_tokens,
690 			  uint32_t n_lines,
691 			  uint32_t *err_line,
692 			  const char **err_msg)
693 {
694 	const char **new_action_names = NULL;
695 	int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
696 	char *name = NULL;
697 	int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
698 
699 	/* Handle end of block. */
700 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
701 		*block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
702 		return 0;
703 	}
704 
705 	/* Check input arguments. */
706 	if ((n_tokens > 2) ||
707 	    ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
708 	      strcmp(tokens[1], "@defaultonly"))) {
709 		if (err_line)
710 			*err_line = n_lines;
711 		if (err_msg)
712 			*err_msg = "Invalid action name statement.";
713 		return -EINVAL;
714 	}
715 
716 	name = strdup(tokens[0]);
717 
718 	if (n_tokens == 2) {
719 		if (!strcmp(tokens[1], "@tableonly"))
720 			action_is_for_default_entry = 0;
721 
722 		if (!strcmp(tokens[1], "@defaultonly"))
723 			action_is_for_table_entries = 0;
724 	}
725 
726 	new_action_names = realloc(s->params.action_names,
727 				   (s->params.n_actions + 1) * sizeof(char *));
728 	new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
729 						  (s->params.n_actions + 1) * sizeof(int));
730 	new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
731 						  (s->params.n_actions + 1) * sizeof(int));
732 
733 	if (!name ||
734 	    !new_action_names ||
735 	    !new_action_is_for_table_entries ||
736 	    !new_action_is_for_default_entry) {
737 		free(name);
738 		free(new_action_names);
739 		free(new_action_is_for_table_entries);
740 		free(new_action_is_for_default_entry);
741 
742 		if (err_line)
743 			*err_line = n_lines;
744 		if (err_msg)
745 			*err_msg = "Memory allocation failed.";
746 		return -ENOMEM;
747 	}
748 
749 	s->params.action_names = new_action_names;
750 	s->params.action_names[s->params.n_actions] = name;
751 
752 	s->params.action_is_for_table_entries = new_action_is_for_table_entries;
753 	s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
754 
755 	s->params.action_is_for_default_entry = new_action_is_for_default_entry;
756 	s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
757 
758 	s->params.n_actions++;
759 
760 	return 0;
761 }
762 
763 static int
764 table_default_action_statement_parse(struct table_spec *s,
765 				     char **tokens,
766 				     uint32_t n_tokens,
767 				     uint32_t n_lines,
768 				     uint32_t *err_line,
769 				     const char **err_msg)
770 {
771 	uint32_t i;
772 	int status = 0, duplicate = 0;
773 
774 	/* Check format. */
775 	if ((n_tokens < 4) ||
776 	    strcmp(tokens[2], "args")) {
777 		status = -EINVAL;
778 		goto error;
779 	}
780 
781 	if (s->params.default_action_name) {
782 		duplicate = 1;
783 		status = -EINVAL;
784 		goto error;
785 	}
786 
787 	s->params.default_action_name = strdup(tokens[1]);
788 	if (!s->params.default_action_name) {
789 		status = -ENOMEM;
790 		goto error;
791 	}
792 
793 	if (strcmp(tokens[3], "none")) {
794 		char buffer[MAX_LINE_LENGTH];
795 		uint32_t n_tokens_args = n_tokens - 3;
796 
797 		if (!strcmp(tokens[n_tokens - 1], "const"))
798 			n_tokens_args--;
799 
800 		if (!n_tokens_args) {
801 			status = -EINVAL;
802 			goto error;
803 		}
804 
805 		buffer[0] = 0;
806 		for (i = 0; i < n_tokens_args; i++) {
807 			if (i)
808 				strcat(buffer, " ");
809 
810 			strcat(buffer, tokens[3 + i]);
811 		}
812 
813 		s->params.default_action_args = strdup(buffer);
814 		if (!s->params.default_action_args) {
815 			status = -ENOMEM;
816 			goto error;
817 		}
818 	} else {
819 		if (((n_tokens != 4) && (n_tokens != 5)) ||
820 		    ((n_tokens == 5) && (strcmp(tokens[4], "const")))) {
821 			status = -EINVAL;
822 			goto error;
823 		}
824 	}
825 
826 	if (!strcmp(tokens[n_tokens - 1], "const"))
827 		s->params.default_action_is_const = 1;
828 
829 	return 0;
830 
831 error:
832 	if (err_line)
833 		*err_line = n_lines;
834 
835 	if (err_msg)
836 		switch (status) {
837 		case -ENOMEM:
838 			*err_msg = "Memory allocation failed.";
839 			break;
840 
841 		default:
842 			if (duplicate)
843 				*err_msg = "Duplicate default_action statement.";
844 
845 			*err_msg = "Invalid default_action statement.";
846 		}
847 
848 	return status;
849 }
850 
851 static int
852 table_statement_parse(struct table_spec *s,
853 		      uint32_t *block_mask,
854 		      char **tokens,
855 		      uint32_t n_tokens,
856 		      uint32_t n_lines,
857 		      uint32_t *err_line,
858 		      const char **err_msg)
859 {
860 	/* Check format. */
861 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
862 		if (err_line)
863 			*err_line = n_lines;
864 		if (err_msg)
865 			*err_msg = "Invalid table statement.";
866 		return -EINVAL;
867 	}
868 
869 	/* spec. */
870 	s->name = strdup(tokens[1]);
871 	if (!s->name) {
872 		if (err_line)
873 			*err_line = n_lines;
874 		if (err_msg)
875 			*err_msg = "Memory allocation failed.";
876 		return -ENOMEM;
877 	}
878 
879 	/* block_mask. */
880 	*block_mask |= 1 << TABLE_BLOCK;
881 
882 	return 0;
883 }
884 
885 static int
886 table_block_parse(struct table_spec *s,
887 		  uint32_t *block_mask,
888 		  char **tokens,
889 		  uint32_t n_tokens,
890 		  uint32_t n_lines,
891 		  uint32_t *err_line,
892 		  const char **err_msg)
893 {
894 	if (*block_mask & (1 << TABLE_KEY_BLOCK))
895 		return table_key_block_parse(s,
896 					     block_mask,
897 					     tokens,
898 					     n_tokens,
899 					     n_lines,
900 					     err_line,
901 					     err_msg);
902 
903 	if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
904 		return table_actions_block_parse(s,
905 						 block_mask,
906 						 tokens,
907 						 n_tokens,
908 						 n_lines,
909 						 err_line,
910 						 err_msg);
911 
912 	/* Handle end of block. */
913 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
914 		*block_mask &= ~(1 << TABLE_BLOCK);
915 		return 0;
916 	}
917 
918 	if (!strcmp(tokens[0], "key"))
919 		return table_key_statement_parse(block_mask,
920 						 tokens,
921 						 n_tokens,
922 						 n_lines,
923 						 err_line,
924 						 err_msg);
925 
926 	if (!strcmp(tokens[0], "actions"))
927 		return table_actions_statement_parse(block_mask,
928 						     tokens,
929 						     n_tokens,
930 						     n_lines,
931 						     err_line,
932 						     err_msg);
933 
934 	if (!strcmp(tokens[0], "default_action"))
935 		return table_default_action_statement_parse(s,
936 							    tokens,
937 							    n_tokens,
938 							    n_lines,
939 							    err_line,
940 							    err_msg);
941 
942 	if (!strcmp(tokens[0], "hash")) {
943 		if (n_tokens != 2) {
944 			if (err_line)
945 				*err_line = n_lines;
946 			if (err_msg)
947 				*err_msg = "Invalid hash statement.";
948 			return -EINVAL;
949 		}
950 
951 		if (s->params.hash_func_name) {
952 			if (err_line)
953 				*err_line = n_lines;
954 			if (err_msg)
955 				*err_msg = "Duplicate hash statement.";
956 			return -EINVAL;
957 		}
958 
959 		s->params.hash_func_name = strdup(tokens[1]);
960 		if (!s->params.hash_func_name) {
961 			if (err_line)
962 				*err_line = n_lines;
963 			if (err_msg)
964 				*err_msg = "Memory allocation failed.";
965 			return -ENOMEM;
966 		}
967 
968 		return 0;
969 	}
970 
971 	if (!strcmp(tokens[0], "instanceof")) {
972 		if (n_tokens != 2) {
973 			if (err_line)
974 				*err_line = n_lines;
975 			if (err_msg)
976 				*err_msg = "Invalid instanceof statement.";
977 			return -EINVAL;
978 		}
979 
980 		if (s->recommended_table_type_name) {
981 			if (err_line)
982 				*err_line = n_lines;
983 			if (err_msg)
984 				*err_msg = "Duplicate instanceof statement.";
985 			return -EINVAL;
986 		}
987 
988 		s->recommended_table_type_name = strdup(tokens[1]);
989 		if (!s->recommended_table_type_name) {
990 			if (err_line)
991 				*err_line = n_lines;
992 			if (err_msg)
993 				*err_msg = "Memory allocation failed.";
994 			return -ENOMEM;
995 		}
996 
997 		return 0;
998 	}
999 
1000 	if (!strcmp(tokens[0], "pragma")) {
1001 		if (n_tokens != 2) {
1002 			if (err_line)
1003 				*err_line = n_lines;
1004 			if (err_msg)
1005 				*err_msg = "Invalid pragma statement.";
1006 			return -EINVAL;
1007 		}
1008 
1009 		if (s->args) {
1010 			if (err_line)
1011 				*err_line = n_lines;
1012 			if (err_msg)
1013 				*err_msg = "Duplicate pragma statement.";
1014 			return -EINVAL;
1015 		}
1016 
1017 		s->args = strdup(tokens[1]);
1018 		if (!s->args) {
1019 			if (err_line)
1020 				*err_line = n_lines;
1021 			if (err_msg)
1022 				*err_msg = "Memory allocation failed.";
1023 			return -ENOMEM;
1024 		}
1025 
1026 		return 0;
1027 	}
1028 
1029 	if (!strcmp(tokens[0], "size")) {
1030 		char *p = tokens[1];
1031 
1032 		if (n_tokens != 2) {
1033 			if (err_line)
1034 				*err_line = n_lines;
1035 			if (err_msg)
1036 				*err_msg = "Invalid pragma statement.";
1037 			return -EINVAL;
1038 		}
1039 
1040 		s->size = strtoul(p, &p, 0);
1041 		if (p[0]) {
1042 			if (err_line)
1043 				*err_line = n_lines;
1044 			if (err_msg)
1045 				*err_msg = "Invalid size argument.";
1046 			return -EINVAL;
1047 		}
1048 
1049 		return 0;
1050 	}
1051 
1052 	/* Anything else. */
1053 	if (err_line)
1054 		*err_line = n_lines;
1055 	if (err_msg)
1056 		*err_msg = "Invalid statement.";
1057 	return -EINVAL;
1058 }
1059 
1060 /*
1061  * selector.
1062  *
1063  */
1064 static void
1065 selector_spec_free(struct selector_spec *s)
1066 {
1067 	uintptr_t field_name;
1068 	uint32_t i;
1069 
1070 	if (!s)
1071 		return;
1072 
1073 	/* name. */
1074 	free(s->name);
1075 	s->name = NULL;
1076 
1077 	/* params->group_id_field_name. */
1078 	field_name = (uintptr_t)s->params.group_id_field_name;
1079 	free((void *)field_name);
1080 	s->params.group_id_field_name = NULL;
1081 
1082 	/* params->selector_field_names. */
1083 	for (i = 0; i < s->params.n_selector_fields; i++) {
1084 		field_name = (uintptr_t)s->params.selector_field_names[i];
1085 
1086 		free((void *)field_name);
1087 	}
1088 
1089 	free(s->params.selector_field_names);
1090 	s->params.selector_field_names = NULL;
1091 
1092 	s->params.n_selector_fields = 0;
1093 
1094 	/* params->member_id_field_name. */
1095 	field_name = (uintptr_t)s->params.member_id_field_name;
1096 	free((void *)field_name);
1097 	s->params.member_id_field_name = NULL;
1098 
1099 	/* params->n_groups_max. */
1100 	s->params.n_groups_max = 0;
1101 
1102 	/* params->n_members_per_group_max. */
1103 	s->params.n_members_per_group_max = 0;
1104 }
1105 
1106 static int
1107 selector_statement_parse(struct selector_spec *s,
1108 			 uint32_t *block_mask,
1109 			 char **tokens,
1110 			 uint32_t n_tokens,
1111 			 uint32_t n_lines,
1112 			 uint32_t *err_line,
1113 			 const char **err_msg)
1114 {
1115 	/* Check format. */
1116 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1117 		if (err_line)
1118 			*err_line = n_lines;
1119 		if (err_msg)
1120 			*err_msg = "Invalid selector statement.";
1121 		return -EINVAL;
1122 	}
1123 
1124 	/* spec. */
1125 	s->name = strdup(tokens[1]);
1126 	if (!s->name) {
1127 		if (err_line)
1128 			*err_line = n_lines;
1129 		if (err_msg)
1130 			*err_msg = "Memory allocation failed.";
1131 		return -ENOMEM;
1132 	}
1133 
1134 	/* block_mask. */
1135 	*block_mask |= 1 << SELECTOR_BLOCK;
1136 
1137 	return 0;
1138 }
1139 
1140 static int
1141 selector_selector_statement_parse(uint32_t *block_mask,
1142 				  char **tokens,
1143 				  uint32_t n_tokens,
1144 				  uint32_t n_lines,
1145 				  uint32_t *err_line,
1146 				  const char **err_msg)
1147 {
1148 	/* Check format. */
1149 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1150 		if (err_line)
1151 			*err_line = n_lines;
1152 		if (err_msg)
1153 			*err_msg = "Invalid selector statement.";
1154 		return -EINVAL;
1155 	}
1156 
1157 	/* block_mask. */
1158 	*block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
1159 
1160 	return 0;
1161 }
1162 
1163 static int
1164 selector_selector_block_parse(struct selector_spec *s,
1165 			      uint32_t *block_mask,
1166 			      char **tokens,
1167 			      uint32_t n_tokens,
1168 			      uint32_t n_lines,
1169 			      uint32_t *err_line,
1170 			      const char **err_msg)
1171 {
1172 	const char **new_fields;
1173 	char *name;
1174 
1175 	/* Handle end of block. */
1176 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1177 		*block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
1178 		return 0;
1179 	}
1180 
1181 	/* Check input arguments. */
1182 	if (n_tokens != 1) {
1183 		if (err_line)
1184 			*err_line = n_lines;
1185 		if (err_msg)
1186 			*err_msg = "Invalid selector field statement.";
1187 		return -EINVAL;
1188 	}
1189 
1190 	name = strdup(tokens[0]);
1191 	if (!name) {
1192 		if (err_line)
1193 			*err_line = n_lines;
1194 		if (err_msg)
1195 			*err_msg = "Memory allocation failed.";
1196 		return -ENOMEM;
1197 	}
1198 
1199 	new_fields = realloc(s->params.selector_field_names,
1200 			     (s->params.n_selector_fields + 1) * sizeof(char *));
1201 	if (!new_fields) {
1202 		free(name);
1203 
1204 		if (err_line)
1205 			*err_line = n_lines;
1206 		if (err_msg)
1207 			*err_msg = "Memory allocation failed.";
1208 		return -ENOMEM;
1209 	}
1210 
1211 	s->params.selector_field_names = new_fields;
1212 	s->params.selector_field_names[s->params.n_selector_fields] = name;
1213 	s->params.n_selector_fields++;
1214 
1215 	return 0;
1216 }
1217 
1218 static int
1219 selector_block_parse(struct selector_spec *s,
1220 		     uint32_t *block_mask,
1221 		     char **tokens,
1222 		     uint32_t n_tokens,
1223 		     uint32_t n_lines,
1224 		     uint32_t *err_line,
1225 		     const char **err_msg)
1226 {
1227 	if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK))
1228 		return selector_selector_block_parse(s,
1229 						     block_mask,
1230 						     tokens,
1231 						     n_tokens,
1232 						     n_lines,
1233 						     err_line,
1234 						     err_msg);
1235 
1236 	/* Handle end of block. */
1237 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1238 		*block_mask &= ~(1 << SELECTOR_BLOCK);
1239 		return 0;
1240 	}
1241 
1242 	if (!strcmp(tokens[0], "group_id")) {
1243 		if (n_tokens != 2) {
1244 			if (err_line)
1245 				*err_line = n_lines;
1246 			if (err_msg)
1247 				*err_msg = "Invalid group_id statement.";
1248 			return -EINVAL;
1249 		}
1250 
1251 		s->params.group_id_field_name = strdup(tokens[1]);
1252 		if (!s->params.group_id_field_name) {
1253 			if (err_line)
1254 				*err_line = n_lines;
1255 			if (err_msg)
1256 				*err_msg = "Memory allocation failed.";
1257 			return -ENOMEM;
1258 		}
1259 
1260 		return 0;
1261 	}
1262 
1263 	if (!strcmp(tokens[0], "selector"))
1264 		return selector_selector_statement_parse(block_mask,
1265 							 tokens,
1266 							 n_tokens,
1267 							 n_lines,
1268 							 err_line,
1269 							 err_msg);
1270 
1271 	if (!strcmp(tokens[0], "member_id")) {
1272 		if (n_tokens != 2) {
1273 			if (err_line)
1274 				*err_line = n_lines;
1275 			if (err_msg)
1276 				*err_msg = "Invalid member_id statement.";
1277 			return -EINVAL;
1278 		}
1279 
1280 		s->params.member_id_field_name = strdup(tokens[1]);
1281 		if (!s->params.member_id_field_name) {
1282 			if (err_line)
1283 				*err_line = n_lines;
1284 			if (err_msg)
1285 				*err_msg = "Memory allocation failed.";
1286 			return -ENOMEM;
1287 		}
1288 
1289 		return 0;
1290 	}
1291 
1292 	if (!strcmp(tokens[0], "n_groups_max")) {
1293 		char *p = tokens[1];
1294 
1295 		if (n_tokens != 2) {
1296 			if (err_line)
1297 				*err_line = n_lines;
1298 			if (err_msg)
1299 				*err_msg = "Invalid n_groups statement.";
1300 			return -EINVAL;
1301 		}
1302 
1303 		s->params.n_groups_max = strtoul(p, &p, 0);
1304 		if (p[0]) {
1305 			if (err_line)
1306 				*err_line = n_lines;
1307 			if (err_msg)
1308 				*err_msg = "Invalid n_groups argument.";
1309 			return -EINVAL;
1310 		}
1311 
1312 		return 0;
1313 	}
1314 
1315 	if (!strcmp(tokens[0], "n_members_per_group_max")) {
1316 		char *p = tokens[1];
1317 
1318 		if (n_tokens != 2) {
1319 			if (err_line)
1320 				*err_line = n_lines;
1321 			if (err_msg)
1322 				*err_msg = "Invalid n_members_per_group statement.";
1323 			return -EINVAL;
1324 		}
1325 
1326 		s->params.n_members_per_group_max = strtoul(p, &p, 0);
1327 		if (p[0]) {
1328 			if (err_line)
1329 				*err_line = n_lines;
1330 			if (err_msg)
1331 				*err_msg = "Invalid n_members_per_group argument.";
1332 			return -EINVAL;
1333 		}
1334 
1335 		return 0;
1336 	}
1337 
1338 	/* Anything else. */
1339 	if (err_line)
1340 		*err_line = n_lines;
1341 	if (err_msg)
1342 		*err_msg = "Invalid statement.";
1343 	return -EINVAL;
1344 }
1345 
1346 /*
1347  * learner.
1348  *
1349  */
1350 static void
1351 learner_spec_free(struct learner_spec *s)
1352 {
1353 	uintptr_t default_action_name, default_action_args, hash_func_name;
1354 	uint32_t i;
1355 
1356 	if (!s)
1357 		return;
1358 
1359 	free(s->name);
1360 	s->name = NULL;
1361 
1362 	for (i = 0; i < s->params.n_fields; i++) {
1363 		uintptr_t name = (uintptr_t)s->params.field_names[i];
1364 
1365 		free((void *)name);
1366 	}
1367 
1368 	free(s->params.field_names);
1369 	s->params.field_names = NULL;
1370 
1371 	s->params.n_fields = 0;
1372 
1373 	for (i = 0; i < s->params.n_actions; i++) {
1374 		uintptr_t name = (uintptr_t)s->params.action_names[i];
1375 
1376 		free((void *)name);
1377 	}
1378 
1379 	free(s->params.action_names);
1380 	s->params.action_names = NULL;
1381 
1382 	s->params.n_actions = 0;
1383 
1384 	default_action_name = (uintptr_t)s->params.default_action_name;
1385 	free((void *)default_action_name);
1386 	s->params.default_action_name = NULL;
1387 
1388 	default_action_args = (uintptr_t)s->params.default_action_args;
1389 	free((void *)default_action_args);
1390 	s->params.default_action_args = NULL;
1391 
1392 	free(s->params.action_is_for_table_entries);
1393 	s->params.action_is_for_table_entries = NULL;
1394 
1395 	free(s->params.action_is_for_default_entry);
1396 	s->params.action_is_for_default_entry = NULL;
1397 
1398 	s->params.default_action_is_const = 0;
1399 
1400 	hash_func_name = (uintptr_t)s->params.hash_func_name;
1401 	free((void *)hash_func_name);
1402 	s->params.hash_func_name = NULL;
1403 
1404 	s->size = 0;
1405 
1406 	free(s->timeout);
1407 	s->timeout = NULL;
1408 
1409 	s->n_timeouts = 0;
1410 }
1411 
1412 static int
1413 learner_key_statement_parse(uint32_t *block_mask,
1414 			    char **tokens,
1415 			    uint32_t n_tokens,
1416 			    uint32_t n_lines,
1417 			    uint32_t *err_line,
1418 			    const char **err_msg)
1419 {
1420 	/* Check format. */
1421 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1422 		if (err_line)
1423 			*err_line = n_lines;
1424 		if (err_msg)
1425 			*err_msg = "Invalid key statement.";
1426 		return -EINVAL;
1427 	}
1428 
1429 	/* block_mask. */
1430 	*block_mask |= 1 << LEARNER_KEY_BLOCK;
1431 
1432 	return 0;
1433 }
1434 
1435 static int
1436 learner_key_block_parse(struct learner_spec *s,
1437 			uint32_t *block_mask,
1438 			char **tokens,
1439 			uint32_t n_tokens,
1440 			uint32_t n_lines,
1441 			uint32_t *err_line,
1442 			const char **err_msg)
1443 {
1444 	const char **new_field_names = NULL;
1445 	char *field_name = NULL;
1446 
1447 	/* Handle end of block. */
1448 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1449 		*block_mask &= ~(1 << LEARNER_KEY_BLOCK);
1450 		return 0;
1451 	}
1452 
1453 	/* Check input arguments. */
1454 	if (n_tokens != 1) {
1455 		if (err_line)
1456 			*err_line = n_lines;
1457 		if (err_msg)
1458 			*err_msg = "Invalid match field statement.";
1459 		return -EINVAL;
1460 	}
1461 
1462 	field_name = strdup(tokens[0]);
1463 	new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
1464 	if (!field_name || !new_field_names) {
1465 		free(field_name);
1466 		free(new_field_names);
1467 
1468 		if (err_line)
1469 			*err_line = n_lines;
1470 		if (err_msg)
1471 			*err_msg = "Memory allocation failed.";
1472 		return -ENOMEM;
1473 	}
1474 
1475 	s->params.field_names = new_field_names;
1476 	s->params.field_names[s->params.n_fields] = field_name;
1477 	s->params.n_fields++;
1478 
1479 	return 0;
1480 }
1481 
1482 static int
1483 learner_actions_statement_parse(uint32_t *block_mask,
1484 				char **tokens,
1485 				uint32_t n_tokens,
1486 				uint32_t n_lines,
1487 				uint32_t *err_line,
1488 				const char **err_msg)
1489 {
1490 	/* Check format. */
1491 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1492 		if (err_line)
1493 			*err_line = n_lines;
1494 		if (err_msg)
1495 			*err_msg = "Invalid actions statement.";
1496 		return -EINVAL;
1497 	}
1498 
1499 	/* block_mask. */
1500 	*block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
1501 
1502 	return 0;
1503 }
1504 
1505 static int
1506 learner_actions_block_parse(struct learner_spec *s,
1507 			    uint32_t *block_mask,
1508 			    char **tokens,
1509 			    uint32_t n_tokens,
1510 			    uint32_t n_lines,
1511 			    uint32_t *err_line,
1512 			    const char **err_msg)
1513 {
1514 	const char **new_action_names = NULL;
1515 	int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
1516 	char *name = NULL;
1517 	int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
1518 
1519 	/* Handle end of block. */
1520 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1521 		*block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
1522 		return 0;
1523 	}
1524 
1525 	/* Check input arguments. */
1526 	if ((n_tokens > 2) ||
1527 	    ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
1528 	      strcmp(tokens[1], "@defaultonly"))) {
1529 		if (err_line)
1530 			*err_line = n_lines;
1531 		if (err_msg)
1532 			*err_msg = "Invalid action name statement.";
1533 		return -EINVAL;
1534 	}
1535 
1536 	name = strdup(tokens[0]);
1537 
1538 	if (n_tokens == 2) {
1539 		if (!strcmp(tokens[1], "@tableonly"))
1540 			action_is_for_default_entry = 0;
1541 
1542 		if (!strcmp(tokens[1], "@defaultonly"))
1543 			action_is_for_table_entries = 0;
1544 	}
1545 
1546 	new_action_names = realloc(s->params.action_names,
1547 				   (s->params.n_actions + 1) * sizeof(char *));
1548 	new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
1549 						  (s->params.n_actions + 1) * sizeof(int));
1550 	new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
1551 						  (s->params.n_actions + 1) * sizeof(int));
1552 
1553 	if (!name ||
1554 	    !new_action_names ||
1555 	    !new_action_is_for_table_entries ||
1556 	    !new_action_is_for_default_entry) {
1557 		free(name);
1558 		free(new_action_names);
1559 		free(new_action_is_for_table_entries);
1560 		free(new_action_is_for_default_entry);
1561 
1562 		if (err_line)
1563 			*err_line = n_lines;
1564 		if (err_msg)
1565 			*err_msg = "Memory allocation failed.";
1566 		return -ENOMEM;
1567 	}
1568 
1569 	s->params.action_names = new_action_names;
1570 	s->params.action_names[s->params.n_actions] = name;
1571 
1572 	s->params.action_is_for_table_entries = new_action_is_for_table_entries;
1573 	s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
1574 
1575 	s->params.action_is_for_default_entry = new_action_is_for_default_entry;
1576 	s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
1577 
1578 	s->params.n_actions++;
1579 
1580 	return 0;
1581 }
1582 
1583 static int
1584 learner_default_action_statement_parse(struct learner_spec *s,
1585 				       char **tokens,
1586 				       uint32_t n_tokens,
1587 				       uint32_t n_lines,
1588 				       uint32_t *err_line,
1589 				       const char **err_msg)
1590 {
1591 	uint32_t i;
1592 	int status = 0, duplicate = 0;
1593 
1594 	/* Check format. */
1595 	if ((n_tokens < 4) ||
1596 	    strcmp(tokens[2], "args")) {
1597 		status = -EINVAL;
1598 		goto error;
1599 	}
1600 
1601 	if (s->params.default_action_name) {
1602 		duplicate = 1;
1603 		status = -EINVAL;
1604 		goto error;
1605 	}
1606 
1607 	s->params.default_action_name = strdup(tokens[1]);
1608 	if (!s->params.default_action_name) {
1609 		status = -ENOMEM;
1610 		goto error;
1611 	}
1612 
1613 	if (strcmp(tokens[3], "none")) {
1614 		char buffer[MAX_LINE_LENGTH];
1615 		uint32_t n_tokens_args = n_tokens - 3;
1616 
1617 		if (!strcmp(tokens[n_tokens - 1], "const"))
1618 			n_tokens_args--;
1619 
1620 		if (!n_tokens_args) {
1621 			status = -EINVAL;
1622 			goto error;
1623 		}
1624 
1625 		buffer[0] = 0;
1626 		for (i = 0; i < n_tokens_args; i++) {
1627 			if (i)
1628 				strcat(buffer, " ");
1629 
1630 			strcat(buffer, tokens[3 + i]);
1631 		}
1632 
1633 		s->params.default_action_args = strdup(buffer);
1634 		if (!s->params.default_action_args) {
1635 			status = -ENOMEM;
1636 			goto error;
1637 		}
1638 	} else {
1639 		if (((n_tokens != 4) && (n_tokens != 5)) ||
1640 		    ((n_tokens == 5) && (strcmp(tokens[4], "const")))) {
1641 			status = -EINVAL;
1642 			goto error;
1643 		}
1644 	}
1645 
1646 	if (!strcmp(tokens[n_tokens - 1], "const"))
1647 		s->params.default_action_is_const = 1;
1648 
1649 	return 0;
1650 
1651 error:
1652 	if (err_line)
1653 		*err_line = n_lines;
1654 
1655 	if (err_msg)
1656 		switch (status) {
1657 		case -ENOMEM:
1658 			*err_msg = "Memory allocation failed.";
1659 			break;
1660 
1661 		default:
1662 			if (duplicate)
1663 				*err_msg = "Duplicate default_action statement.";
1664 
1665 			*err_msg = "Invalid default_action statement.";
1666 		}
1667 
1668 	return status;
1669 }
1670 
1671 static int
1672 learner_timeout_statement_parse(uint32_t *block_mask,
1673 				char **tokens,
1674 				uint32_t n_tokens,
1675 				uint32_t n_lines,
1676 				uint32_t *err_line,
1677 				const char **err_msg)
1678 {
1679 	/* Check format. */
1680 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1681 		if (err_line)
1682 			*err_line = n_lines;
1683 		if (err_msg)
1684 			*err_msg = "Invalid timeout statement.";
1685 		return -EINVAL;
1686 	}
1687 
1688 	/* block_mask. */
1689 	*block_mask |= 1 << LEARNER_TIMEOUT_BLOCK;
1690 
1691 	return 0;
1692 }
1693 
1694 static int
1695 learner_timeout_block_parse(struct learner_spec *s,
1696 			    uint32_t *block_mask,
1697 			    char **tokens,
1698 			    uint32_t n_tokens,
1699 			    uint32_t n_lines,
1700 			    uint32_t *err_line,
1701 			    const char **err_msg)
1702 {
1703 	uint32_t *new_timeout = NULL;
1704 	char *str;
1705 	uint32_t val;
1706 	int status = 0;
1707 
1708 	/* Handle end of block. */
1709 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1710 		*block_mask &= ~(1 << LEARNER_TIMEOUT_BLOCK);
1711 		return 0;
1712 	}
1713 
1714 	/* Check input arguments. */
1715 	if (n_tokens != 1) {
1716 		status = -EINVAL;
1717 		goto error;
1718 	}
1719 
1720 	str = tokens[0];
1721 	val = strtoul(str, &str, 0);
1722 	if (str[0]) {
1723 		status = -EINVAL;
1724 		goto error;
1725 	}
1726 
1727 	new_timeout = realloc(s->timeout, (s->n_timeouts + 1) * sizeof(uint32_t));
1728 	if (!new_timeout) {
1729 		status = -ENOMEM;
1730 		goto error;
1731 	}
1732 
1733 	s->timeout = new_timeout;
1734 	s->timeout[s->n_timeouts] = val;
1735 	s->n_timeouts++;
1736 
1737 	return 0;
1738 
1739 error:
1740 	free(new_timeout);
1741 
1742 	if (err_line)
1743 		*err_line = n_lines;
1744 
1745 	if (err_msg)
1746 		switch (status) {
1747 		case -ENOMEM:
1748 			*err_msg = "Memory allocation failed.";
1749 			break;
1750 
1751 		default:
1752 			*err_msg = "Invalid timeout value statement.";
1753 			break;
1754 		}
1755 
1756 	return status;
1757 }
1758 
1759 
1760 static int
1761 learner_statement_parse(struct learner_spec *s,
1762 		      uint32_t *block_mask,
1763 		      char **tokens,
1764 		      uint32_t n_tokens,
1765 		      uint32_t n_lines,
1766 		      uint32_t *err_line,
1767 		      const char **err_msg)
1768 {
1769 	/* Check format. */
1770 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1771 		if (err_line)
1772 			*err_line = n_lines;
1773 		if (err_msg)
1774 			*err_msg = "Invalid learner statement.";
1775 		return -EINVAL;
1776 	}
1777 
1778 	/* spec. */
1779 	s->name = strdup(tokens[1]);
1780 	if (!s->name) {
1781 		if (err_line)
1782 			*err_line = n_lines;
1783 		if (err_msg)
1784 			*err_msg = "Memory allocation failed.";
1785 		return -ENOMEM;
1786 	}
1787 
1788 	/* block_mask. */
1789 	*block_mask |= 1 << LEARNER_BLOCK;
1790 
1791 	return 0;
1792 }
1793 
1794 static int
1795 learner_block_parse(struct learner_spec *s,
1796 		    uint32_t *block_mask,
1797 		    char **tokens,
1798 		    uint32_t n_tokens,
1799 		    uint32_t n_lines,
1800 		    uint32_t *err_line,
1801 		    const char **err_msg)
1802 {
1803 	if (*block_mask & (1 << LEARNER_KEY_BLOCK))
1804 		return learner_key_block_parse(s,
1805 					       block_mask,
1806 					       tokens,
1807 					       n_tokens,
1808 					       n_lines,
1809 					       err_line,
1810 					       err_msg);
1811 
1812 	if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
1813 		return learner_actions_block_parse(s,
1814 						   block_mask,
1815 						   tokens,
1816 						   n_tokens,
1817 						   n_lines,
1818 						   err_line,
1819 						   err_msg);
1820 
1821 	if (*block_mask & (1 << LEARNER_TIMEOUT_BLOCK))
1822 		return learner_timeout_block_parse(s,
1823 						   block_mask,
1824 						   tokens,
1825 						   n_tokens,
1826 						   n_lines,
1827 						   err_line,
1828 						   err_msg);
1829 
1830 	/* Handle end of block. */
1831 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1832 		*block_mask &= ~(1 << LEARNER_BLOCK);
1833 		return 0;
1834 	}
1835 
1836 	if (!strcmp(tokens[0], "key"))
1837 		return learner_key_statement_parse(block_mask,
1838 						   tokens,
1839 						   n_tokens,
1840 						   n_lines,
1841 						   err_line,
1842 						   err_msg);
1843 
1844 	if (!strcmp(tokens[0], "actions"))
1845 		return learner_actions_statement_parse(block_mask,
1846 						       tokens,
1847 						       n_tokens,
1848 						       n_lines,
1849 						       err_line,
1850 						       err_msg);
1851 
1852 	if (!strcmp(tokens[0], "default_action"))
1853 		return learner_default_action_statement_parse(s,
1854 							      tokens,
1855 							      n_tokens,
1856 							      n_lines,
1857 							      err_line,
1858 							      err_msg);
1859 
1860 	if (!strcmp(tokens[0], "hash")) {
1861 		if (n_tokens != 2) {
1862 			if (err_line)
1863 				*err_line = n_lines;
1864 			if (err_msg)
1865 				*err_msg = "Invalid hash statement.";
1866 			return -EINVAL;
1867 		}
1868 
1869 		if (s->params.hash_func_name) {
1870 			if (err_line)
1871 				*err_line = n_lines;
1872 			if (err_msg)
1873 				*err_msg = "Duplicate hash statement.";
1874 			return -EINVAL;
1875 		}
1876 
1877 		s->params.hash_func_name = strdup(tokens[1]);
1878 		if (!s->params.hash_func_name) {
1879 			if (err_line)
1880 				*err_line = n_lines;
1881 			if (err_msg)
1882 				*err_msg = "Memory allocation failed.";
1883 			return -ENOMEM;
1884 		}
1885 
1886 		return 0;
1887 	}
1888 
1889 	if (!strcmp(tokens[0], "size")) {
1890 		char *p = tokens[1];
1891 
1892 		if (n_tokens != 2) {
1893 			if (err_line)
1894 				*err_line = n_lines;
1895 			if (err_msg)
1896 				*err_msg = "Invalid size statement.";
1897 			return -EINVAL;
1898 		}
1899 
1900 		s->size = strtoul(p, &p, 0);
1901 		if (p[0]) {
1902 			if (err_line)
1903 				*err_line = n_lines;
1904 			if (err_msg)
1905 				*err_msg = "Invalid size argument.";
1906 			return -EINVAL;
1907 		}
1908 
1909 		return 0;
1910 	}
1911 
1912 	if (!strcmp(tokens[0], "timeout"))
1913 		return learner_timeout_statement_parse(block_mask,
1914 						       tokens,
1915 						       n_tokens,
1916 						       n_lines,
1917 						       err_line,
1918 						       err_msg);
1919 
1920 	/* Anything else. */
1921 	if (err_line)
1922 		*err_line = n_lines;
1923 	if (err_msg)
1924 		*err_msg = "Invalid statement.";
1925 	return -EINVAL;
1926 }
1927 
1928 /*
1929  * regarray.
1930  *
1931  */
1932 static void
1933 regarray_spec_free(struct regarray_spec *s)
1934 {
1935 	if (!s)
1936 		return;
1937 
1938 	free(s->name);
1939 	s->name = NULL;
1940 }
1941 
1942 static int
1943 regarray_statement_parse(struct regarray_spec *s,
1944 			 char **tokens,
1945 			 uint32_t n_tokens,
1946 			 uint32_t n_lines,
1947 			 uint32_t *err_line,
1948 			 const char **err_msg)
1949 {
1950 	char *p;
1951 
1952 	/* Check format. */
1953 	if ((n_tokens != 6) ||
1954 	     strcmp(tokens[2], "size") ||
1955 	     strcmp(tokens[4], "initval")) {
1956 		if (err_line)
1957 			*err_line = n_lines;
1958 		if (err_msg)
1959 			*err_msg = "Invalid regarray statement.";
1960 		return -EINVAL;
1961 	}
1962 
1963 	/* spec. */
1964 	s->name = strdup(tokens[1]);
1965 	if (!s->name) {
1966 		if (err_line)
1967 			*err_line = n_lines;
1968 		if (err_msg)
1969 			*err_msg = "Memory allocation failed.";
1970 		return -ENOMEM;
1971 	}
1972 
1973 	p = tokens[3];
1974 	s->size = strtoul(p, &p, 0);
1975 	if (p[0] || !s->size) {
1976 		if (err_line)
1977 			*err_line = n_lines;
1978 		if (err_msg)
1979 			*err_msg = "Invalid size argument.";
1980 		return -EINVAL;
1981 	}
1982 
1983 	p = tokens[5];
1984 	s->init_val = strtoull(p, &p, 0);
1985 	if (p[0]) {
1986 		if (err_line)
1987 			*err_line = n_lines;
1988 		if (err_msg)
1989 			*err_msg = "Invalid initval argument.";
1990 		return -EINVAL;
1991 	}
1992 
1993 	return 0;
1994 }
1995 
1996 /*
1997  * metarray.
1998  *
1999  */
2000 static void
2001 metarray_spec_free(struct metarray_spec *s)
2002 {
2003 	if (!s)
2004 		return;
2005 
2006 	free(s->name);
2007 	s->name = NULL;
2008 }
2009 
2010 static int
2011 metarray_statement_parse(struct metarray_spec *s,
2012 			 char **tokens,
2013 			 uint32_t n_tokens,
2014 			 uint32_t n_lines,
2015 			 uint32_t *err_line,
2016 			 const char **err_msg)
2017 {
2018 	char *p;
2019 
2020 	/* Check format. */
2021 	if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
2022 		if (err_line)
2023 			*err_line = n_lines;
2024 		if (err_msg)
2025 			*err_msg = "Invalid metarray statement.";
2026 		return -EINVAL;
2027 	}
2028 
2029 	/* spec. */
2030 	s->name = strdup(tokens[1]);
2031 	if (!s->name) {
2032 		if (err_line)
2033 			*err_line = n_lines;
2034 		if (err_msg)
2035 			*err_msg = "Memory allocation failed.";
2036 		return -ENOMEM;
2037 	}
2038 
2039 	p = tokens[3];
2040 	s->size = strtoul(p, &p, 0);
2041 	if (p[0] || !s->size) {
2042 		if (err_line)
2043 			*err_line = n_lines;
2044 		if (err_msg)
2045 			*err_msg = "Invalid size argument.";
2046 		return -EINVAL;
2047 	}
2048 
2049 	return 0;
2050 }
2051 
2052 /*
2053  *
2054  * rss
2055  *
2056  */
2057 
2058 static void
2059 rss_spec_free(struct rss_spec *s)
2060 {
2061 	if (!s)
2062 		return;
2063 
2064 	free(s->name);
2065 	s->name = NULL;
2066 }
2067 
2068 static int
2069 rss_statement_parse(struct rss_spec *s,
2070 			 char **tokens,
2071 			 uint32_t n_tokens,
2072 			 uint32_t n_lines,
2073 			 uint32_t *err_line,
2074 			 const char **err_msg)
2075 {
2076 	/* Check format. */
2077 	if ((n_tokens != 2)) {
2078 		if (err_line)
2079 			*err_line = n_lines;
2080 		if (err_msg)
2081 			*err_msg = "Invalid rss statement.";
2082 		return -EINVAL;
2083 	}
2084 
2085 	/* spec. */
2086 	s->name = strdup(tokens[1]);
2087 	if (!s->name) {
2088 		if (err_line)
2089 			*err_line = n_lines;
2090 		if (err_msg)
2091 			*err_msg = "Memory allocation failed.";
2092 		return -ENOMEM;
2093 	}
2094 
2095 	return 0;
2096 }
2097 
2098 /*
2099  * apply.
2100  *
2101  */
2102 static void
2103 apply_spec_free(struct apply_spec *s)
2104 {
2105 	uint32_t i;
2106 
2107 	if (!s)
2108 		return;
2109 
2110 	for (i = 0; i < s->n_instructions; i++) {
2111 		uintptr_t instr = (uintptr_t)s->instructions[i];
2112 
2113 		free((void *)instr);
2114 	}
2115 
2116 	free(s->instructions);
2117 	s->instructions = NULL;
2118 
2119 	s->n_instructions = 0;
2120 }
2121 
2122 static int
2123 apply_statement_parse(uint32_t *block_mask,
2124 		      char **tokens,
2125 		      uint32_t n_tokens,
2126 		      uint32_t n_lines,
2127 		      uint32_t *err_line,
2128 		      const char **err_msg)
2129 {
2130 	/* Check format. */
2131 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
2132 		if (err_line)
2133 			*err_line = n_lines;
2134 		if (err_msg)
2135 			*err_msg = "Invalid apply statement.";
2136 		return -EINVAL;
2137 	}
2138 
2139 	/* block_mask. */
2140 	*block_mask |= 1 << APPLY_BLOCK;
2141 
2142 	return 0;
2143 }
2144 
2145 static int
2146 apply_block_parse(struct apply_spec *s,
2147 		  uint32_t *block_mask,
2148 		  char **tokens,
2149 		  uint32_t n_tokens,
2150 		  uint32_t n_lines,
2151 		  uint32_t *err_line,
2152 		  const char **err_msg)
2153 {
2154 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
2155 	const char **new_instructions;
2156 	uint32_t i;
2157 
2158 	/* Handle end of block. */
2159 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
2160 		*block_mask &= ~(1 << APPLY_BLOCK);
2161 		return 0;
2162 	}
2163 
2164 	/* spec. */
2165 	buffer[0] = 0;
2166 	for (i = 0; i < n_tokens; i++) {
2167 		if (i)
2168 			strcat(buffer, " ");
2169 		strcat(buffer, tokens[i]);
2170 	}
2171 
2172 	instr = strdup(buffer);
2173 	if (!instr) {
2174 		if (err_line)
2175 			*err_line = n_lines;
2176 		if (err_msg)
2177 			*err_msg = "Memory allocation failed.";
2178 		return -ENOMEM;
2179 	}
2180 
2181 	new_instructions = realloc(s->instructions,
2182 				   (s->n_instructions + 1) * sizeof(char *));
2183 	if (!new_instructions) {
2184 		free(instr);
2185 
2186 		if (err_line)
2187 			*err_line = n_lines;
2188 		if (err_msg)
2189 			*err_msg = "Memory allocation failed.";
2190 		return -ENOMEM;
2191 	}
2192 
2193 	s->instructions = new_instructions;
2194 	s->instructions[s->n_instructions] = instr;
2195 	s->n_instructions++;
2196 
2197 	return 0;
2198 }
2199 
2200 /*
2201  * Pipeline.
2202  */
2203 void
2204 pipeline_spec_free(struct pipeline_spec *s)
2205 {
2206 	if (!s)
2207 		return;
2208 
2209 	free(s->extobjs);
2210 	free(s->structs);
2211 	free(s->headers);
2212 	free(s->metadata);
2213 	free(s->actions);
2214 	free(s->tables);
2215 	free(s->selectors);
2216 	free(s->learners);
2217 	free(s->regarrays);
2218 	free(s->metarrays);
2219 	free(s->apply);
2220 
2221 	memset(s, 0, sizeof(struct pipeline_spec));
2222 }
2223 
2224 static const char *
2225 match_type_string_get(enum rte_swx_table_match_type match_type)
2226 {
2227 	switch (match_type) {
2228 	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
2229 	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
2230 	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
2231 	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
2232 	}
2233 }
2234 
2235 void
2236 pipeline_spec_codegen(FILE *f,
2237 		      struct pipeline_spec *s)
2238 {
2239 	uint32_t i;
2240 
2241 	/* Check the input arguments. */
2242 	if (!f || !s)
2243 		return;
2244 
2245 	/* extobj. */
2246 	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
2247 
2248 	for (i = 0; i < s->n_extobjs; i++) {
2249 		struct extobj_spec *extobj_spec = &s->extobjs[i];
2250 
2251 		fprintf(f, "\t[%d] = {\n", i);
2252 		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
2253 		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
2254 		if (extobj_spec->pragma)
2255 			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
2256 		else
2257 			fprintf(f, "\t\t.pragma = NULL,\n");
2258 		fprintf(f, "\t},\n");
2259 	}
2260 
2261 	fprintf(f, "};\n\n");
2262 
2263 	/* regarray. */
2264 	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
2265 
2266 	for (i = 0; i < s->n_regarrays; i++) {
2267 		struct regarray_spec *regarray_spec = &s->regarrays[i];
2268 
2269 		fprintf(f, "\t[%d] = {\n", i);
2270 		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
2271 		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
2272 		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
2273 		fprintf(f, "\t},\n");
2274 	}
2275 
2276 	fprintf(f, "};\n\n");
2277 
2278 	/* metarray. */
2279 	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
2280 
2281 	for (i = 0; i < s->n_metarrays; i++) {
2282 		struct metarray_spec *metarray_spec = &s->metarrays[i];
2283 
2284 		fprintf(f, "\t[%d] = {\n", i);
2285 		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
2286 		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
2287 		fprintf(f, "\t},\n");
2288 	}
2289 
2290 	fprintf(f, "};\n\n");
2291 
2292 	/* rss. */
2293 	fprintf(f, "static struct rss_spec rss[] = {\n");
2294 
2295 	for (i = 0; i < s->n_rss; i++) {
2296 		struct rss_spec *rss_spec = &s->rss[i];
2297 		fprintf(f, "\t[%d] = {\n", i);
2298 		fprintf(f, "\t\t.name = \"%s\",\n", rss_spec->name);
2299 		fprintf(f, "\t},\n");
2300 	}
2301 	fprintf(f, "};\n\n");
2302 
2303 	/* struct. */
2304 	for (i = 0; i < s->n_structs; i++) {
2305 		struct struct_spec *struct_spec = &s->structs[i];
2306 		uint32_t j;
2307 
2308 		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
2309 			struct_spec->name);
2310 
2311 		for (j = 0; j < struct_spec->n_fields; j++) {
2312 			struct rte_swx_field_params *field = &struct_spec->fields[j];
2313 
2314 			fprintf(f, "\t[%d] = {\n", j);
2315 			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
2316 			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
2317 			fprintf(f, "\t},\n");
2318 		}
2319 
2320 		fprintf(f, "};\n\n");
2321 	}
2322 
2323 	fprintf(f, "static struct struct_spec structs[] = {\n");
2324 
2325 	for (i = 0; i < s->n_structs; i++) {
2326 		struct struct_spec *struct_spec = &s->structs[i];
2327 
2328 		fprintf(f, "\t[%d] = {\n", i);
2329 		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
2330 		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
2331 		fprintf(f, "\t\t.n_fields = "
2332 			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
2333 			struct_spec->name,
2334 			struct_spec->name);
2335 		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
2336 		fprintf(f, "\t},\n");
2337 	}
2338 
2339 	fprintf(f, "};\n\n");
2340 
2341 	/* header. */
2342 	fprintf(f, "static struct header_spec headers[] = {\n");
2343 
2344 	for (i = 0; i < s->n_headers; i++) {
2345 		struct header_spec *header_spec = &s->headers[i];
2346 
2347 		fprintf(f, "\t[%d] = {\n", i);
2348 		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
2349 		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
2350 		fprintf(f, "\t},\n");
2351 	}
2352 
2353 	fprintf(f, "};\n\n");
2354 
2355 	/* metadata. */
2356 	fprintf(f, "static struct metadata_spec metadata[] = {\n");
2357 
2358 	for (i = 0; i < s->n_metadata; i++) {
2359 		struct metadata_spec *metadata_spec = &s->metadata[i];
2360 
2361 		fprintf(f, "\t[%d] = {\n", i);
2362 		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
2363 		fprintf(f, "\t},\n");
2364 
2365 	}
2366 
2367 	fprintf(f, "};\n\n");
2368 
2369 	/* action. */
2370 	for (i = 0; i < s->n_actions; i++) {
2371 		struct action_spec *action_spec = &s->actions[i];
2372 		uint32_t j;
2373 
2374 		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
2375 			action_spec->name);
2376 
2377 		for (j = 0; j < action_spec->n_instructions; j++) {
2378 			const char *instr = action_spec->instructions[j];
2379 
2380 			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
2381 		}
2382 
2383 		fprintf(f, "};\n\n");
2384 	}
2385 
2386 	fprintf(f, "static struct action_spec actions[] = {\n");
2387 
2388 	for (i = 0; i < s->n_actions; i++) {
2389 		struct action_spec *action_spec = &s->actions[i];
2390 
2391 		fprintf(f, "\t[%d] = {\n", i);
2392 		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
2393 
2394 		if (action_spec->args_struct_type_name)
2395 			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
2396 				action_spec->args_struct_type_name);
2397 		else
2398 			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
2399 
2400 		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
2401 			action_spec->name);
2402 		fprintf(f, "\t\t.n_instructions = "
2403 			"sizeof(action_%s_initial_instructions) / "
2404 			"sizeof(action_%s_initial_instructions[0]),\n",
2405 			action_spec->name,
2406 			action_spec->name);
2407 		fprintf(f, "\t},\n");
2408 	}
2409 
2410 	fprintf(f, "};\n\n");
2411 
2412 	/* table. */
2413 	for (i = 0; i < s->n_tables; i++) {
2414 		struct table_spec *table_spec = &s->tables[i];
2415 		uint32_t j;
2416 
2417 		/* fields. */
2418 		if (table_spec->params.fields && table_spec->params.n_fields) {
2419 			fprintf(f, "static struct rte_swx_match_field_params "
2420 				"table_%s_fields[] = {\n",
2421 				table_spec->name);
2422 
2423 			for (j = 0; j < table_spec->params.n_fields; j++) {
2424 				struct rte_swx_match_field_params *field =
2425 					&table_spec->params.fields[j];
2426 
2427 				fprintf(f, "\t[%d] = {\n", j);
2428 				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
2429 				fprintf(f, "\t\t.match_type = %s,\n",
2430 					match_type_string_get(field->match_type));
2431 				fprintf(f, "\t},\n");
2432 			}
2433 
2434 			fprintf(f, "};\n\n");
2435 		}
2436 
2437 		/* action_names. */
2438 		if (table_spec->params.action_names && table_spec->params.n_actions) {
2439 			fprintf(f, "static const char *table_%s_action_names[] = {\n",
2440 				table_spec->name);
2441 
2442 			for (j = 0; j < table_spec->params.n_actions; j++) {
2443 				const char *action_name = table_spec->params.action_names[j];
2444 
2445 				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
2446 			}
2447 
2448 			fprintf(f, "};\n\n");
2449 		}
2450 
2451 		/* action_is_for_table_entries. */
2452 		if (table_spec->params.action_is_for_table_entries &&
2453 		    table_spec->params.n_actions) {
2454 			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
2455 				table_spec->name);
2456 
2457 			for (j = 0; j < table_spec->params.n_actions; j++) {
2458 				int value = table_spec->params.action_is_for_table_entries[j];
2459 
2460 				fprintf(f, "\t[%d] = %d,\n", j, value);
2461 			}
2462 
2463 			fprintf(f, "};\n\n");
2464 		}
2465 
2466 		/* action_is_for_default_entry. */
2467 		if (table_spec->params.action_is_for_default_entry &&
2468 		    table_spec->params.n_actions) {
2469 			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
2470 				table_spec->name);
2471 
2472 			for (j = 0; j < table_spec->params.n_actions; j++) {
2473 				int value = table_spec->params.action_is_for_default_entry[j];
2474 
2475 				fprintf(f, "\t[%d] = %d,\n", j, value);
2476 			}
2477 
2478 			fprintf(f, "};\n\n");
2479 		}
2480 	}
2481 
2482 	fprintf(f, "static struct table_spec tables[] = {\n");
2483 
2484 	for (i = 0; i < s->n_tables; i++) {
2485 		struct table_spec *table_spec = &s->tables[i];
2486 
2487 		fprintf(f, "\t[%d] = {\n", i);
2488 		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
2489 
2490 		fprintf(f, "\t\t.params = {\n");
2491 
2492 		if (table_spec->params.fields && table_spec->params.n_fields) {
2493 			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
2494 			fprintf(f, "\t\t\t.n_fields = "
2495 				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
2496 				table_spec->name,
2497 				table_spec->name);
2498 		} else {
2499 			fprintf(f, "\t\t\t.fields = NULL,\n");
2500 			fprintf(f, "\t\t\t.n_fields = 0,\n");
2501 		}
2502 
2503 		if (table_spec->params.action_names && table_spec->params.n_actions)
2504 			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
2505 				table_spec->name);
2506 		else
2507 			fprintf(f, "\t\t\t.action_names = NULL,\n");
2508 
2509 		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
2510 			fprintf(f, "\t\t\t.action_is_for_table_entries = "
2511 				"table_%s_action_is_for_table_entries,\n",
2512 				table_spec->name);
2513 		else
2514 			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
2515 
2516 		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
2517 			fprintf(f, "\t\t\t.action_is_for_default_entry = "
2518 				"table_%s_action_is_for_default_entry,\n",
2519 				table_spec->name);
2520 		else
2521 			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
2522 
2523 		if (table_spec->params.n_actions)
2524 			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
2525 				"sizeof(table_%s_action_names[0]),\n",
2526 				table_spec->name,
2527 				table_spec->name);
2528 		else
2529 			fprintf(f, "\t\t\t.n_actions = 0,\n");
2530 
2531 		if (table_spec->params.default_action_name)
2532 			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
2533 				table_spec->params.default_action_name);
2534 		else
2535 			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
2536 
2537 		if (table_spec->params.default_action_args)
2538 			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
2539 				table_spec->params.default_action_args);
2540 		else
2541 			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
2542 
2543 		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
2544 			table_spec->params.default_action_is_const);
2545 
2546 		if (table_spec->params.hash_func_name)
2547 			fprintf(f, "\t\t\t.hash_func_name = \"%s\",\n",
2548 				table_spec->params.hash_func_name);
2549 		else
2550 			fprintf(f, "\t\t\t.hash_func_name = NULL,\n");
2551 
2552 		fprintf(f, "\t\t},\n");
2553 
2554 		if (table_spec->recommended_table_type_name)
2555 			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
2556 				table_spec->recommended_table_type_name);
2557 		else
2558 			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
2559 
2560 		if (table_spec->args)
2561 			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
2562 		else
2563 			fprintf(f, "\t\t.args = NULL,\n");
2564 
2565 		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
2566 
2567 		fprintf(f, "\t},\n");
2568 	}
2569 
2570 	fprintf(f, "};\n\n");
2571 
2572 	/* selector. */
2573 	for (i = 0; i < s->n_selectors; i++) {
2574 		struct selector_spec *selector_spec = &s->selectors[i];
2575 		uint32_t j;
2576 
2577 		if (selector_spec->params.selector_field_names &&
2578 		    selector_spec->params.n_selector_fields) {
2579 			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
2580 				selector_spec->name);
2581 
2582 			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
2583 				const char *field_name =
2584 					selector_spec->params.selector_field_names[j];
2585 
2586 				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
2587 			}
2588 
2589 			fprintf(f, "};\n\n");
2590 		}
2591 	}
2592 
2593 	fprintf(f, "static struct selector_spec selectors[] = {\n");
2594 
2595 	for (i = 0; i < s->n_selectors; i++) {
2596 		struct selector_spec *selector_spec = &s->selectors[i];
2597 
2598 		fprintf(f, "\t[%d] = {\n", i);
2599 
2600 		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
2601 		fprintf(f, "\t\t.params = {\n");
2602 
2603 		if (selector_spec->params.group_id_field_name)
2604 			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
2605 				selector_spec->params.group_id_field_name);
2606 		else
2607 			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
2608 
2609 		if (selector_spec->params.selector_field_names &&
2610 		    selector_spec->params.n_selector_fields) {
2611 			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
2612 				selector_spec->name);
2613 			fprintf(f, "\t\t\t.n_selector_fields = "
2614 				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
2615 				selector_spec->name,
2616 				selector_spec->name);
2617 		} else {
2618 			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
2619 			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
2620 		}
2621 
2622 		if (selector_spec->params.member_id_field_name)
2623 			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
2624 				selector_spec->params.member_id_field_name);
2625 		else
2626 			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
2627 
2628 		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
2629 
2630 		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
2631 			selector_spec->params.n_members_per_group_max);
2632 
2633 		fprintf(f, "\t\t},\n");
2634 		fprintf(f, "\t},\n");
2635 	}
2636 
2637 	fprintf(f, "};\n\n");
2638 
2639 	/* learner. */
2640 	for (i = 0; i < s->n_learners; i++) {
2641 		struct learner_spec *learner_spec = &s->learners[i];
2642 		uint32_t j;
2643 
2644 		/* field_names. */
2645 		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
2646 			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
2647 				learner_spec->name);
2648 
2649 			for (j = 0; j < learner_spec->params.n_fields; j++) {
2650 				const char *field_name = learner_spec->params.field_names[j];
2651 
2652 				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
2653 			}
2654 
2655 			fprintf(f, "};\n\n");
2656 		}
2657 
2658 		/* action_names. */
2659 		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
2660 			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
2661 				learner_spec->name);
2662 
2663 			for (j = 0; j < learner_spec->params.n_actions; j++) {
2664 				const char *action_name = learner_spec->params.action_names[j];
2665 
2666 				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
2667 			}
2668 
2669 			fprintf(f, "};\n\n");
2670 		}
2671 
2672 		/* action_is_for_table_entries. */
2673 		if (learner_spec->params.action_is_for_table_entries &&
2674 		    learner_spec->params.n_actions) {
2675 			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
2676 				learner_spec->name);
2677 
2678 			for (j = 0; j < learner_spec->params.n_actions; j++) {
2679 				int value = learner_spec->params.action_is_for_table_entries[j];
2680 
2681 				fprintf(f, "\t[%d] = %d,\n", j, value);
2682 			}
2683 
2684 			fprintf(f, "};\n\n");
2685 		}
2686 
2687 		/* action_is_for_default_entry. */
2688 		if (learner_spec->params.action_is_for_default_entry &&
2689 		    learner_spec->params.n_actions) {
2690 			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
2691 				learner_spec->name);
2692 
2693 			for (j = 0; j < learner_spec->params.n_actions; j++) {
2694 				int value = learner_spec->params.action_is_for_default_entry[j];
2695 
2696 				fprintf(f, "\t[%d] = %d,\n", j, value);
2697 			}
2698 
2699 			fprintf(f, "};\n\n");
2700 		}
2701 
2702 		/* timeout. */
2703 		if (learner_spec->timeout && learner_spec->n_timeouts) {
2704 			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
2705 				learner_spec->name);
2706 
2707 			for (j = 0; j < learner_spec->n_timeouts; j++) {
2708 				uint32_t value = learner_spec->timeout[j];
2709 
2710 				fprintf(f, "\t[%d] = %u,\n", j, value);
2711 			}
2712 
2713 			fprintf(f, "};\n\n");
2714 		}
2715 	}
2716 
2717 	fprintf(f, "static struct learner_spec learners[] = {\n");
2718 
2719 	for (i = 0; i < s->n_learners; i++) {
2720 		struct learner_spec *learner_spec = &s->learners[i];
2721 
2722 		fprintf(f, "\t[%d] = {\n", i);
2723 		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
2724 
2725 		fprintf(f, "\t\t.params = {\n");
2726 
2727 		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
2728 			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
2729 				learner_spec->name);
2730 			fprintf(f, "\t\t\t.n_fields = "
2731 				"sizeof(learner_%s_field_names) / "
2732 				"sizeof(learner_%s_field_names[0]),\n",
2733 				learner_spec->name,
2734 				learner_spec->name);
2735 		} else {
2736 			fprintf(f, "\t\t\t.field_names = NULL,\n");
2737 			fprintf(f, "\t\t\t.n_fields = 0,\n");
2738 		}
2739 
2740 		if (learner_spec->params.action_names && learner_spec->params.n_actions)
2741 			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
2742 				learner_spec->name);
2743 		else
2744 			fprintf(f, "\t\t\t.action_names = NULL,\n");
2745 
2746 		if (learner_spec->params.action_is_for_table_entries &&
2747 		    learner_spec->params.n_actions)
2748 			fprintf(f, "\t\t\t.action_is_for_table_entries = "
2749 				"learner_%s_action_is_for_table_entries,\n",
2750 				learner_spec->name);
2751 		else
2752 			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
2753 
2754 		if (learner_spec->params.action_is_for_default_entry &&
2755 		    learner_spec->params.n_actions)
2756 			fprintf(f, "\t\t\t.action_is_for_default_entry = "
2757 				"learner_%s_action_is_for_default_entry,\n",
2758 				learner_spec->name);
2759 		else
2760 			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
2761 
2762 		if (learner_spec->params.action_names && learner_spec->params.n_actions)
2763 			fprintf(f, "\t\t\t.n_actions = "
2764 				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
2765 				learner_spec->name,
2766 				learner_spec->name);
2767 		else
2768 			fprintf(f, "\t\t\t.n_actions = NULL,\n");
2769 
2770 		if (learner_spec->params.default_action_name)
2771 			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
2772 				learner_spec->params.default_action_name);
2773 		else
2774 			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
2775 
2776 		if (learner_spec->params.default_action_args)
2777 			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
2778 				learner_spec->params.default_action_args);
2779 		else
2780 			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
2781 
2782 		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
2783 			learner_spec->params.default_action_is_const);
2784 
2785 		if (learner_spec->params.hash_func_name)
2786 			fprintf(f, "\t\t\t.hash_func_name = \"%s\",\n",
2787 				learner_spec->params.hash_func_name);
2788 		else
2789 			fprintf(f, "\t\t\t.hash_func_name = NULL,\n");
2790 
2791 		fprintf(f, "\t\t},\n");
2792 
2793 		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
2794 
2795 		if (learner_spec->timeout && learner_spec->n_timeouts) {
2796 			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
2797 			fprintf(f, "\t\t\t.n_timeouts = "
2798 				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
2799 				learner_spec->name,
2800 				learner_spec->name);
2801 		} else {
2802 			fprintf(f, "\t\t.timeout = NULL,\n");
2803 			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
2804 		}
2805 
2806 		fprintf(f, "\t},\n");
2807 	}
2808 
2809 	fprintf(f, "};\n\n");
2810 
2811 	/* apply. */
2812 	for (i = 0; i < s->n_apply; i++) {
2813 		struct apply_spec *apply_spec = &s->apply[i];
2814 		uint32_t j;
2815 
2816 		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
2817 
2818 		for (j = 0; j < apply_spec->n_instructions; j++) {
2819 			const char *instr = apply_spec->instructions[j];
2820 
2821 			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
2822 		}
2823 
2824 		fprintf(f, "};\n\n");
2825 	}
2826 
2827 	fprintf(f, "static struct apply_spec apply[] = {\n");
2828 
2829 	for (i = 0; i < s->n_apply; i++) {
2830 		fprintf(f, "\t[%d] = {\n", i);
2831 		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
2832 		fprintf(f, "\t.n_instructions = "
2833 			"sizeof(apply%u_initial_instructions) / "
2834 			"sizeof(apply%u_initial_instructions[0]),\n",
2835 			i,
2836 			i);
2837 		fprintf(f, "\t},\n");
2838 	}
2839 
2840 	fprintf(f, "};\n\n");
2841 
2842 	/* pipeline. */
2843 	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
2844 	fprintf(f, "\t.extobjs = extobjs,\n");
2845 	fprintf(f, "\t.structs = structs,\n");
2846 	fprintf(f, "\t.headers = headers,\n");
2847 	fprintf(f, "\t.metadata = metadata,\n");
2848 	fprintf(f, "\t.actions = actions,\n");
2849 	fprintf(f, "\t.tables = tables,\n");
2850 	fprintf(f, "\t.selectors = selectors,\n");
2851 	fprintf(f, "\t.learners = learners,\n");
2852 	fprintf(f, "\t.regarrays = regarrays,\n");
2853 	fprintf(f, "\t.metarrays = metarrays,\n");
2854 	fprintf(f, "\t.rss = rss,\n");
2855 	fprintf(f, "\t.apply = apply,\n");
2856 	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
2857 	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
2858 	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
2859 	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
2860 	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
2861 	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
2862 	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
2863 	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
2864 	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
2865 	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
2866 	fprintf(f, "\t.n_rss = sizeof(rss) / sizeof(rss[0]),\n");
2867 	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
2868 	fprintf(f, "};\n");
2869 }
2870 
2871 struct pipeline_spec *
2872 pipeline_spec_parse(FILE *spec,
2873 		    uint32_t *err_line,
2874 		    const char **err_msg)
2875 {
2876 	struct extobj_spec extobj_spec = {0};
2877 	struct struct_spec struct_spec = {0};
2878 	struct header_spec header_spec = {0};
2879 	struct metadata_spec metadata_spec = {0};
2880 	struct action_spec action_spec = {0};
2881 	struct table_spec table_spec = {0};
2882 	struct selector_spec selector_spec = {0};
2883 	struct learner_spec learner_spec = {0};
2884 	struct regarray_spec regarray_spec = {0};
2885 	struct metarray_spec metarray_spec = {0};
2886 	struct rss_spec rss_spec = {0};
2887 	struct apply_spec apply_spec = {0};
2888 	struct pipeline_spec *s = NULL;
2889 	uint32_t n_lines = 0;
2890 	uint32_t block_mask = 0;
2891 	int status = 0;
2892 
2893 	/* Check the input arguments. */
2894 	if (!spec) {
2895 		if (err_line)
2896 			*err_line = n_lines;
2897 		if (err_msg)
2898 			*err_msg = "Invalid input argument.";
2899 		status = -EINVAL;
2900 		goto error;
2901 	}
2902 
2903 	/* Memory allocation. */
2904 	s = calloc(sizeof(struct pipeline_spec), 1);
2905 	if (!s) {
2906 		if (err_line)
2907 			*err_line = n_lines;
2908 		if (err_msg)
2909 			*err_msg = "Memory allocation failed.";
2910 		status = -ENOMEM;
2911 		goto error;
2912 	}
2913 
2914 	for (n_lines = 1; ; n_lines++) {
2915 		char line[MAX_LINE_LENGTH];
2916 		char *tokens[MAX_TOKENS], *ptr = line;
2917 		uint32_t n_tokens = 0;
2918 
2919 		/* Read next line. */
2920 		if (!fgets(line, sizeof(line), spec))
2921 			break;
2922 
2923 		/* Parse the line into tokens. */
2924 		for ( ; ; ) {
2925 			char *token;
2926 
2927 			/* Get token. */
2928 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
2929 			if (!token)
2930 				break;
2931 
2932 			/* Handle comments. */
2933 			if ((token[0] == '#') ||
2934 			    (token[0] == ';') ||
2935 			    ((token[0] == '/') && (token[1] == '/'))) {
2936 				break;
2937 			}
2938 
2939 			/* Handle excessively long lines. */
2940 			if (n_tokens >= RTE_DIM(tokens)) {
2941 				if (err_line)
2942 					*err_line = n_lines;
2943 				if (err_msg)
2944 					*err_msg = "Too many tokens.";
2945 				status = -EINVAL;
2946 				goto error;
2947 			}
2948 
2949 			/* Handle excessively long tokens. */
2950 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2951 			    RTE_SWX_NAME_SIZE) {
2952 				if (err_line)
2953 					*err_line = n_lines;
2954 				if (err_msg)
2955 					*err_msg = "Token too big.";
2956 				status = -EINVAL;
2957 				goto error;
2958 			}
2959 
2960 			/* Save token. */
2961 			tokens[n_tokens] = token;
2962 			n_tokens++;
2963 		}
2964 
2965 		/* Handle empty lines. */
2966 		if (!n_tokens)
2967 			continue;
2968 
2969 		/* struct block. */
2970 		if (block_mask & (1 << STRUCT_BLOCK)) {
2971 			struct struct_spec *new_structs;
2972 
2973 			status = struct_block_parse(&struct_spec,
2974 						    &block_mask,
2975 						    tokens,
2976 						    n_tokens,
2977 						    n_lines,
2978 						    err_line,
2979 						    err_msg);
2980 			if (status)
2981 				goto error;
2982 
2983 			if (block_mask & (1 << STRUCT_BLOCK))
2984 				continue;
2985 
2986 			/* End of block. */
2987 			new_structs = realloc(s->structs,
2988 					      (s->n_structs + 1) * sizeof(struct struct_spec));
2989 			if (!new_structs) {
2990 				if (err_line)
2991 					*err_line = n_lines;
2992 				if (err_msg)
2993 					*err_msg = "Memory allocation failed.";
2994 				status = -ENOMEM;
2995 				goto error;
2996 			}
2997 
2998 			s->structs = new_structs;
2999 			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
3000 			s->n_structs++;
3001 			memset(&struct_spec, 0, sizeof(struct struct_spec));
3002 
3003 			continue;
3004 		}
3005 
3006 		/* action block. */
3007 		if (block_mask & (1 << ACTION_BLOCK)) {
3008 			struct action_spec *new_actions;
3009 
3010 			status = action_block_parse(&action_spec,
3011 						    &block_mask,
3012 						    tokens,
3013 						    n_tokens,
3014 						    n_lines,
3015 						    err_line,
3016 						    err_msg);
3017 			if (status)
3018 				goto error;
3019 
3020 			if (block_mask & (1 << ACTION_BLOCK))
3021 				continue;
3022 
3023 			/* End of block. */
3024 			new_actions = realloc(s->actions,
3025 					      (s->n_actions + 1) * sizeof(struct action_spec));
3026 			if (!new_actions) {
3027 				if (err_line)
3028 					*err_line = n_lines;
3029 				if (err_msg)
3030 					*err_msg = "Memory allocation failed.";
3031 				status = -ENOMEM;
3032 				goto error;
3033 			}
3034 
3035 			s->actions = new_actions;
3036 			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
3037 			s->n_actions++;
3038 			memset(&action_spec, 0, sizeof(struct action_spec));
3039 
3040 			continue;
3041 		}
3042 
3043 		/* table block. */
3044 		if (block_mask & (1 << TABLE_BLOCK)) {
3045 			struct table_spec *new_tables;
3046 
3047 			status = table_block_parse(&table_spec,
3048 						   &block_mask,
3049 						   tokens,
3050 						   n_tokens,
3051 						   n_lines,
3052 						   err_line,
3053 						   err_msg);
3054 			if (status)
3055 				goto error;
3056 
3057 			if (block_mask & (1 << TABLE_BLOCK))
3058 				continue;
3059 
3060 			/* End of block. */
3061 			new_tables = realloc(s->tables,
3062 					     (s->n_tables + 1) * sizeof(struct table_spec));
3063 			if (!new_tables) {
3064 				if (err_line)
3065 					*err_line = n_lines;
3066 				if (err_msg)
3067 					*err_msg = "Memory allocation failed.";
3068 				status = -ENOMEM;
3069 				goto error;
3070 			}
3071 
3072 			s->tables = new_tables;
3073 			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
3074 			s->n_tables++;
3075 			memset(&table_spec, 0, sizeof(struct table_spec));
3076 
3077 			continue;
3078 		}
3079 
3080 		/* selector block. */
3081 		if (block_mask & (1 << SELECTOR_BLOCK)) {
3082 			struct selector_spec *new_selectors;
3083 
3084 			status = selector_block_parse(&selector_spec,
3085 						      &block_mask,
3086 						      tokens,
3087 						      n_tokens,
3088 						      n_lines,
3089 						      err_line,
3090 						      err_msg);
3091 			if (status)
3092 				goto error;
3093 
3094 			if (block_mask & (1 << SELECTOR_BLOCK))
3095 				continue;
3096 
3097 			/* End of block. */
3098 			new_selectors = realloc(s->selectors,
3099 				(s->n_selectors + 1) * sizeof(struct selector_spec));
3100 			if (!new_selectors) {
3101 				if (err_line)
3102 					*err_line = n_lines;
3103 				if (err_msg)
3104 					*err_msg = "Memory allocation failed.";
3105 				status = -ENOMEM;
3106 				goto error;
3107 			}
3108 
3109 			s->selectors = new_selectors;
3110 			memcpy(&s->selectors[s->n_selectors],
3111 			       &selector_spec,
3112 			       sizeof(struct selector_spec));
3113 			s->n_selectors++;
3114 			memset(&selector_spec, 0, sizeof(struct selector_spec));
3115 
3116 			continue;
3117 		}
3118 
3119 		/* learner block. */
3120 		if (block_mask & (1 << LEARNER_BLOCK)) {
3121 			struct learner_spec *new_learners;
3122 
3123 			status = learner_block_parse(&learner_spec,
3124 						     &block_mask,
3125 						     tokens,
3126 						     n_tokens,
3127 						     n_lines,
3128 						     err_line,
3129 						     err_msg);
3130 			if (status)
3131 				goto error;
3132 
3133 			if (block_mask & (1 << LEARNER_BLOCK))
3134 				continue;
3135 
3136 			/* End of block. */
3137 			new_learners = realloc(s->learners,
3138 					       (s->n_learners + 1) * sizeof(struct learner_spec));
3139 			if (!new_learners) {
3140 				if (err_line)
3141 					*err_line = n_lines;
3142 				if (err_msg)
3143 					*err_msg = "Memory allocation failed.";
3144 				status = -ENOMEM;
3145 				goto error;
3146 			}
3147 
3148 			s->learners = new_learners;
3149 			memcpy(&s->learners[s->n_learners],
3150 			       &learner_spec,
3151 			       sizeof(struct learner_spec));
3152 			s->n_learners++;
3153 			memset(&learner_spec, 0, sizeof(struct learner_spec));
3154 
3155 			continue;
3156 		}
3157 
3158 		/* apply block. */
3159 		if (block_mask & (1 << APPLY_BLOCK)) {
3160 			struct apply_spec *new_apply;
3161 
3162 			status = apply_block_parse(&apply_spec,
3163 						   &block_mask,
3164 						   tokens,
3165 						   n_tokens,
3166 						   n_lines,
3167 						   err_line,
3168 						   err_msg);
3169 			if (status)
3170 				goto error;
3171 
3172 			if (block_mask & (1 << APPLY_BLOCK))
3173 				continue;
3174 
3175 			/* End of block. */
3176 			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
3177 			if (!new_apply) {
3178 				if (err_line)
3179 					*err_line = n_lines;
3180 				if (err_msg)
3181 					*err_msg = "Memory allocation failed.";
3182 				status = -ENOMEM;
3183 				goto error;
3184 			}
3185 
3186 			s->apply = new_apply;
3187 			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
3188 			s->n_apply++;
3189 			memset(&apply_spec, 0, sizeof(struct apply_spec));
3190 
3191 			continue;
3192 		}
3193 
3194 		/* extobj. */
3195 		if (!strcmp(tokens[0], "extobj")) {
3196 			struct extobj_spec *new_extobjs;
3197 
3198 			status = extobj_statement_parse(&extobj_spec,
3199 							tokens,
3200 							n_tokens,
3201 							n_lines,
3202 							err_line,
3203 							err_msg);
3204 			if (status)
3205 				goto error;
3206 
3207 			new_extobjs = realloc(s->extobjs,
3208 					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
3209 			if (!new_extobjs) {
3210 				if (err_line)
3211 					*err_line = n_lines;
3212 				if (err_msg)
3213 					*err_msg = "Memory allocation failed.";
3214 				status = -ENOMEM;
3215 				goto error;
3216 			}
3217 
3218 			s->extobjs = new_extobjs;
3219 			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
3220 			s->n_extobjs++;
3221 			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
3222 
3223 			continue;
3224 		}
3225 
3226 		/* struct. */
3227 		if (!strcmp(tokens[0], "struct")) {
3228 			status = struct_statement_parse(&struct_spec,
3229 							&block_mask,
3230 							tokens,
3231 							n_tokens,
3232 							n_lines,
3233 							err_line,
3234 							err_msg);
3235 			if (status)
3236 				goto error;
3237 
3238 			continue;
3239 		}
3240 
3241 		/* header. */
3242 		if (!strcmp(tokens[0], "header")) {
3243 			struct header_spec *new_headers;
3244 
3245 			status = header_statement_parse(&header_spec,
3246 							tokens,
3247 							n_tokens,
3248 							n_lines,
3249 							err_line,
3250 							err_msg);
3251 			if (status)
3252 				goto error;
3253 
3254 			new_headers = realloc(s->headers,
3255 					      (s->n_headers + 1) * sizeof(struct header_spec));
3256 			if (!new_headers) {
3257 				if (err_line)
3258 					*err_line = n_lines;
3259 				if (err_msg)
3260 					*err_msg = "Memory allocation failed.";
3261 				status = -ENOMEM;
3262 				goto error;
3263 			}
3264 
3265 			s->headers = new_headers;
3266 			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
3267 			s->n_headers++;
3268 			memset(&header_spec, 0, sizeof(struct header_spec));
3269 
3270 			continue;
3271 		}
3272 
3273 		/* metadata. */
3274 		if (!strcmp(tokens[0], "metadata")) {
3275 			struct metadata_spec *new_metadata;
3276 
3277 			status = metadata_statement_parse(&metadata_spec,
3278 							  tokens,
3279 							  n_tokens,
3280 							  n_lines,
3281 							  err_line,
3282 							  err_msg);
3283 			if (status)
3284 				goto error;
3285 
3286 			new_metadata = realloc(s->metadata,
3287 					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
3288 			if (!new_metadata) {
3289 				if (err_line)
3290 					*err_line = n_lines;
3291 				if (err_msg)
3292 					*err_msg = "Memory allocation failed.";
3293 				status = -ENOMEM;
3294 				goto error;
3295 			}
3296 
3297 			s->metadata = new_metadata;
3298 			memcpy(&s->metadata[s->n_metadata],
3299 			       &metadata_spec,
3300 			       sizeof(struct metadata_spec));
3301 			s->n_metadata++;
3302 			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
3303 
3304 			continue;
3305 		}
3306 
3307 		/* action. */
3308 		if (!strcmp(tokens[0], "action")) {
3309 			status = action_statement_parse(&action_spec,
3310 							&block_mask,
3311 							tokens,
3312 							n_tokens,
3313 							n_lines,
3314 							err_line,
3315 							err_msg);
3316 			if (status)
3317 				goto error;
3318 
3319 			continue;
3320 		}
3321 
3322 		/* table. */
3323 		if (!strcmp(tokens[0], "table")) {
3324 			status = table_statement_parse(&table_spec,
3325 						       &block_mask,
3326 						       tokens,
3327 						       n_tokens,
3328 						       n_lines,
3329 						       err_line,
3330 						       err_msg);
3331 			if (status)
3332 				goto error;
3333 
3334 			continue;
3335 		}
3336 
3337 		/* selector. */
3338 		if (!strcmp(tokens[0], "selector")) {
3339 			status = selector_statement_parse(&selector_spec,
3340 							  &block_mask,
3341 							  tokens,
3342 							  n_tokens,
3343 							  n_lines,
3344 							  err_line,
3345 							  err_msg);
3346 			if (status)
3347 				goto error;
3348 
3349 			continue;
3350 		}
3351 
3352 		/* learner. */
3353 		if (!strcmp(tokens[0], "learner")) {
3354 			status = learner_statement_parse(&learner_spec,
3355 							 &block_mask,
3356 							 tokens,
3357 							 n_tokens,
3358 							 n_lines,
3359 							 err_line,
3360 							 err_msg);
3361 			if (status)
3362 				goto error;
3363 
3364 			continue;
3365 		}
3366 
3367 		/* regarray. */
3368 		if (!strcmp(tokens[0], "regarray")) {
3369 			struct regarray_spec *new_regarrays;
3370 
3371 			status = regarray_statement_parse(&regarray_spec,
3372 							  tokens,
3373 							  n_tokens,
3374 							  n_lines,
3375 							  err_line,
3376 							  err_msg);
3377 			if (status)
3378 				goto error;
3379 
3380 			new_regarrays = realloc(s->regarrays,
3381 				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
3382 			if (!new_regarrays) {
3383 				if (err_line)
3384 					*err_line = n_lines;
3385 				if (err_msg)
3386 					*err_msg = "Memory allocation failed.";
3387 				status = -ENOMEM;
3388 				goto error;
3389 			}
3390 
3391 			s->regarrays = new_regarrays;
3392 			memcpy(&s->regarrays[s->n_regarrays],
3393 			       &regarray_spec,
3394 			       sizeof(struct regarray_spec));
3395 			s->n_regarrays++;
3396 			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
3397 
3398 			continue;
3399 		}
3400 
3401 		/* metarray. */
3402 		if (!strcmp(tokens[0], "metarray")) {
3403 			struct metarray_spec *new_metarrays;
3404 
3405 			status = metarray_statement_parse(&metarray_spec,
3406 							  tokens,
3407 							  n_tokens,
3408 							  n_lines,
3409 							  err_line,
3410 							  err_msg);
3411 			if (status)
3412 				goto error;
3413 
3414 			new_metarrays = realloc(s->metarrays,
3415 				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
3416 			if (!new_metarrays) {
3417 				if (err_line)
3418 					*err_line = n_lines;
3419 				if (err_msg)
3420 					*err_msg = "Memory allocation failed.";
3421 				status = -ENOMEM;
3422 				goto error;
3423 			}
3424 
3425 			s->metarrays = new_metarrays;
3426 			memcpy(&s->metarrays[s->n_metarrays],
3427 			       &metarray_spec,
3428 			       sizeof(struct metarray_spec));
3429 			s->n_metarrays++;
3430 			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
3431 
3432 			continue;
3433 		}
3434 
3435 		/* rss object configuration */
3436 		if (!strcmp(tokens[0], "rss")) {
3437 			struct rss_spec *new_rss;
3438 
3439 			status = rss_statement_parse(&rss_spec,
3440 						     tokens,
3441 						     n_tokens,
3442 						     n_lines,
3443 						     err_line,
3444 						     err_msg);
3445 			if (status)
3446 				goto error;
3447 
3448 			new_rss = realloc(s->rss,
3449 				(s->n_rss + 1) * sizeof(struct rss_spec));
3450 			if (!new_rss) {
3451 				if (err_line)
3452 					*err_line = n_lines;
3453 				if (err_msg)
3454 					*err_msg = "Memory allocation failed.";
3455 				status = -ENOMEM;
3456 				goto error;
3457 			}
3458 
3459 			s->rss = new_rss;
3460 			memcpy(&s->rss[s->n_rss],
3461 			       &rss_spec,
3462 			       sizeof(struct rss_spec));
3463 			s->n_rss++;
3464 			memset(&rss_spec, 0, sizeof(struct rss_spec));
3465 
3466 			continue;
3467 		}
3468 
3469 		/* apply. */
3470 		if (!strcmp(tokens[0], "apply")) {
3471 			status = apply_statement_parse(&block_mask,
3472 						       tokens,
3473 						       n_tokens,
3474 						       n_lines,
3475 						       err_line,
3476 						       err_msg);
3477 			if (status)
3478 				goto error;
3479 
3480 			continue;
3481 		}
3482 
3483 		/* Anything else. */
3484 		if (err_line)
3485 			*err_line = n_lines;
3486 		if (err_msg)
3487 			*err_msg = "Unknown statement.";
3488 		status = -EINVAL;
3489 		goto error;
3490 	}
3491 
3492 	/* Handle unfinished block. */
3493 	if (block_mask) {
3494 		if (err_line)
3495 			*err_line = n_lines;
3496 		if (err_msg)
3497 			*err_msg = "Missing }.";
3498 		status = -EINVAL;
3499 		goto error;
3500 	}
3501 
3502 	return s;
3503 
3504 error:
3505 	extobj_spec_free(&extobj_spec);
3506 	struct_spec_free(&struct_spec);
3507 	header_spec_free(&header_spec);
3508 	metadata_spec_free(&metadata_spec);
3509 	action_spec_free(&action_spec);
3510 	table_spec_free(&table_spec);
3511 	selector_spec_free(&selector_spec);
3512 	learner_spec_free(&learner_spec);
3513 	regarray_spec_free(&regarray_spec);
3514 	metarray_spec_free(&metarray_spec);
3515 	rss_spec_free(&rss_spec);
3516 	apply_spec_free(&apply_spec);
3517 	pipeline_spec_free(s);
3518 
3519 	return NULL;
3520 }
3521 
3522 int
3523 pipeline_spec_configure(struct rte_swx_pipeline *p,
3524 			struct pipeline_spec *s,
3525 			const char **err_msg)
3526 {
3527 	uint32_t i;
3528 	int status = 0;
3529 
3530 	/* extobj. */
3531 	for (i = 0; i < s->n_extobjs; i++) {
3532 		struct extobj_spec *extobj_spec = &s->extobjs[i];
3533 
3534 		status = rte_swx_pipeline_extern_object_config(p,
3535 			extobj_spec->name,
3536 			extobj_spec->extern_type_name,
3537 			extobj_spec->pragma);
3538 		if (status) {
3539 			if (err_msg)
3540 				*err_msg = "Extern object configuration error.";
3541 			return status;
3542 		}
3543 	}
3544 
3545 	/* regarray. */
3546 	for (i = 0; i < s->n_regarrays; i++) {
3547 		struct regarray_spec *regarray_spec = &s->regarrays[i];
3548 
3549 		status = rte_swx_pipeline_regarray_config(p,
3550 			regarray_spec->name,
3551 			regarray_spec->size,
3552 			regarray_spec->init_val);
3553 		if (status) {
3554 			if (err_msg)
3555 				*err_msg = "Register array configuration error.";
3556 			return status;
3557 		}
3558 	}
3559 
3560 	/* rss. */
3561 	for (i = 0; i < s->n_rss; i++) {
3562 		struct rss_spec *rss_spec = &s->rss[i];
3563 
3564 		status = rte_swx_pipeline_rss_config(p, rss_spec->name);
3565 		if (status) {
3566 			if (err_msg)
3567 				*err_msg = "rss object configuration error.";
3568 			return status;
3569 		}
3570 	}
3571 
3572 	/* metarray. */
3573 	for (i = 0; i < s->n_metarrays; i++) {
3574 		struct metarray_spec *metarray_spec = &s->metarrays[i];
3575 
3576 		status = rte_swx_pipeline_metarray_config(p,
3577 			metarray_spec->name,
3578 			metarray_spec->size);
3579 		if (status) {
3580 			if (err_msg)
3581 				*err_msg = "Meter array configuration error.";
3582 			return status;
3583 		}
3584 	}
3585 
3586 	/* struct. */
3587 	for (i = 0; i < s->n_structs; i++) {
3588 		struct struct_spec *struct_spec = &s->structs[i];
3589 
3590 		status = rte_swx_pipeline_struct_type_register(p,
3591 			struct_spec->name,
3592 			struct_spec->fields,
3593 			struct_spec->n_fields,
3594 			struct_spec->varbit);
3595 		if (status) {
3596 			if (err_msg)
3597 				*err_msg = "Struct type registration error.";
3598 			return status;
3599 		}
3600 	}
3601 
3602 	/* header. */
3603 	for (i = 0; i < s->n_headers; i++) {
3604 		struct header_spec *header_spec = &s->headers[i];
3605 
3606 		status = rte_swx_pipeline_packet_header_register(p,
3607 			header_spec->name,
3608 			header_spec->struct_type_name);
3609 		if (status) {
3610 			if (err_msg)
3611 				*err_msg = "Header configuration error.";
3612 			return status;
3613 		}
3614 	}
3615 
3616 	/* metadata. */
3617 	for (i = 0; i < s->n_metadata; i++) {
3618 		struct metadata_spec *metadata_spec = &s->metadata[i];
3619 
3620 		status = rte_swx_pipeline_packet_metadata_register(p,
3621 			metadata_spec->struct_type_name);
3622 		if (status) {
3623 			if (err_msg)
3624 				*err_msg = "Meta-data registration error.";
3625 			return status;
3626 		}
3627 	}
3628 
3629 	/* action. */
3630 	for (i = 0; i < s->n_actions; i++) {
3631 		struct action_spec *action_spec = &s->actions[i];
3632 
3633 		status = rte_swx_pipeline_action_config(p,
3634 			action_spec->name,
3635 			action_spec->args_struct_type_name,
3636 			action_spec->instructions,
3637 			action_spec->n_instructions);
3638 		if (status) {
3639 			if (err_msg)
3640 				*err_msg = "Action configuration error.";
3641 			return status;
3642 		}
3643 	}
3644 
3645 	/* table. */
3646 	for (i = 0; i < s->n_tables; i++) {
3647 		struct table_spec *table_spec = &s->tables[i];
3648 
3649 		status = rte_swx_pipeline_table_config(p,
3650 			table_spec->name,
3651 			&table_spec->params,
3652 			table_spec->recommended_table_type_name,
3653 			table_spec->args,
3654 			table_spec->size);
3655 		if (status) {
3656 			if (err_msg)
3657 				*err_msg = "Table configuration error.";
3658 			return status;
3659 		}
3660 	}
3661 
3662 	/* selector. */
3663 	for (i = 0; i < s->n_selectors; i++) {
3664 		struct selector_spec *selector_spec = &s->selectors[i];
3665 
3666 		status = rte_swx_pipeline_selector_config(p,
3667 			selector_spec->name,
3668 			&selector_spec->params);
3669 		if (status) {
3670 			if (err_msg)
3671 				*err_msg = "Selector table configuration error.";
3672 			return status;
3673 		}
3674 	}
3675 
3676 	/* learner. */
3677 	for (i = 0; i < s->n_learners; i++) {
3678 		struct learner_spec *learner_spec = &s->learners[i];
3679 
3680 		status = rte_swx_pipeline_learner_config(p,
3681 			learner_spec->name,
3682 			&learner_spec->params,
3683 			learner_spec->size,
3684 			learner_spec->timeout,
3685 			learner_spec->n_timeouts);
3686 		if (status) {
3687 			if (err_msg)
3688 				*err_msg = "Learner table configuration error.";
3689 			return status;
3690 		}
3691 	}
3692 
3693 	/* apply. */
3694 	for (i = 0; i < s->n_apply; i++) {
3695 		struct apply_spec *apply_spec = &s->apply[i];
3696 
3697 		status = rte_swx_pipeline_instructions_config(p,
3698 			apply_spec->instructions,
3699 			apply_spec->n_instructions);
3700 		if (status) {
3701 			if (err_msg)
3702 				*err_msg = "Pipeline instructions configuration error.";
3703 			return status;
3704 		}
3705 	}
3706 
3707 	return 0;
3708 }
3709 
3710 static void
3711 port_in_params_free(void *params, const char *port_type)
3712 {
3713 	uintptr_t dev_name;
3714 
3715 	if (!params || !port_type)
3716 		return;
3717 
3718 	if (!strcmp(port_type, "ethdev")) {
3719 		struct rte_swx_port_ethdev_reader_params *p = params;
3720 
3721 		dev_name = (uintptr_t)p->dev_name;
3722 	} else if (!strcmp(port_type, "ring")) {
3723 		struct rte_swx_port_ring_reader_params *p = params;
3724 
3725 		dev_name = (uintptr_t)p->name;
3726 	} else if (!strcmp(port_type, "source")) {
3727 		struct rte_swx_port_source_params *p = params;
3728 
3729 		dev_name = (uintptr_t)p->file_name;
3730 	} else
3731 		dev_name = (uintptr_t)NULL;
3732 
3733 	free((void *)dev_name);
3734 	free(params);
3735 }
3736 
3737 static void
3738 port_out_params_free(void *params, const char *port_type)
3739 {
3740 	uintptr_t dev_name;
3741 
3742 	if (!params || !port_type)
3743 		return;
3744 
3745 	if (!strcmp(port_type, "ethdev")) {
3746 		struct rte_swx_port_ethdev_writer_params *p = params;
3747 
3748 		dev_name = (uintptr_t)p->dev_name;
3749 	} else if (!strcmp(port_type, "ring")) {
3750 		struct rte_swx_port_ring_writer_params *p = params;
3751 
3752 		dev_name = (uintptr_t)p->name;
3753 	} else if (!strcmp(port_type, "sink")) {
3754 		struct rte_swx_port_sink_params *p = params;
3755 
3756 		dev_name = (uintptr_t)p->file_name;
3757 	} else
3758 		dev_name = (uintptr_t)NULL;
3759 
3760 	free((void *)dev_name);
3761 	free(params);
3762 }
3763 
3764 void
3765 pipeline_iospec_free(struct pipeline_iospec *s)
3766 {
3767 	uint32_t i;
3768 
3769 	if (!s)
3770 		return;
3771 
3772 	/* Input ports. */
3773 	for (i = 0; i < s->n_ports_in; i++) {
3774 		uintptr_t name = (uintptr_t)s->port_in_type[i];
3775 
3776 		port_in_params_free(s->port_in_params[i], s->port_in_type[i]);
3777 		free((void *)name);
3778 	}
3779 
3780 	free(s->port_in_type);
3781 	free(s->port_in_params);
3782 
3783 	/* Output ports. */
3784 	for (i = 0; i < s->n_ports_out; i++) {
3785 		uintptr_t name = (uintptr_t)s->port_out_type[i];
3786 
3787 		port_out_params_free(s->port_out_params[i], s->port_out_type[i]);
3788 		free((void *)name);
3789 	}
3790 
3791 	free(s->port_out_type);
3792 	free(s->port_out_params);
3793 
3794 	free(s);
3795 }
3796 
3797 static int
3798 mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,
3799 		char **tokens,
3800 		uint32_t n_tokens,
3801 		const char **err_msg)
3802 {
3803 	char *token;
3804 
3805 	if ((n_tokens != 4) || strcmp(tokens[0], "slots") || strcmp(tokens[2], "sessions")) {
3806 		if (err_msg)
3807 			*err_msg = "Invalid statement.";
3808 		return -EINVAL;
3809 	}
3810 
3811 	/* <n_slots>. */
3812 	token = tokens[1];
3813 	p->n_slots = strtoul(token, &token, 0);
3814 	if (token[0]) {
3815 		if (err_msg)
3816 			*err_msg = "Invalid <n_slots> parameter.";
3817 		return -EINVAL;
3818 	}
3819 
3820 	/* <n_sessions>. */
3821 	token = tokens[3];
3822 	p->n_sessions = strtoul(token, &token, 0);
3823 	if (token[0]) {
3824 		if (err_msg)
3825 			*err_msg = "Invalid <n_sessions> parameter.";
3826 		return -EINVAL;
3827 	}
3828 
3829 	return 0;
3830 }
3831 
3832 static void *
3833 port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3834 {
3835 	struct rte_swx_port_ethdev_reader_params *p = NULL;
3836 	char *token, *dev_name = NULL;
3837 	uint32_t queue_id, burst_size;
3838 
3839 	if ((n_tokens != 5) || strcmp(tokens[1], "rxq") || strcmp(tokens[3], "bsz")) {
3840 		if (err_msg)
3841 			*err_msg = "Invalid statement.";
3842 		return NULL;
3843 	}
3844 
3845 	/* <queue_id>. */
3846 	token = tokens[2];
3847 	queue_id = strtoul(token, &token, 0);
3848 	if (token[0]) {
3849 		if (err_msg)
3850 			*err_msg = "Invalid <queue_id> parameter.";
3851 		return NULL;
3852 	}
3853 
3854 	/* <burst_size>. */
3855 	token = tokens[4];
3856 	burst_size = strtoul(token, &token, 0);
3857 	if (token[0]) {
3858 		if (err_msg)
3859 			*err_msg = "Invalid <burst_size> parameter.";
3860 		return NULL;
3861 	}
3862 
3863 	/* Memory allocation. */
3864 	dev_name = strdup(tokens[0]);
3865 	p = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));
3866 	if (!dev_name || !p) {
3867 		free(dev_name);
3868 		free(p);
3869 
3870 		if (err_msg)
3871 			*err_msg = "Memory allocation failed.";
3872 		return NULL;
3873 	}
3874 
3875 	/* Initialization. */
3876 	p->dev_name = dev_name;
3877 	p->queue_id = queue_id;
3878 	p->burst_size = burst_size;
3879 
3880 	return p;
3881 }
3882 
3883 static void *
3884 port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3885 {
3886 	struct rte_swx_port_ring_reader_params *p = NULL;
3887 	char *token, *name = NULL;
3888 	uint32_t burst_size;
3889 
3890 	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
3891 		if (err_msg)
3892 			*err_msg = "Invalid statement.";
3893 		return NULL;
3894 	}
3895 
3896 	/* <burst_size>. */
3897 	token = tokens[2];
3898 	burst_size = strtoul(token, &token, 0);
3899 	if (token[0]) {
3900 		if (err_msg)
3901 			*err_msg = "Invalid <burst_size> parameter.";
3902 		return NULL;
3903 	}
3904 
3905 	/* Memory allocation. */
3906 	name = strdup(tokens[0]);
3907 	p = malloc(sizeof(struct rte_swx_port_ring_reader_params));
3908 	if (!name || !p) {
3909 		free(name);
3910 		free(p);
3911 
3912 		if (err_msg)
3913 			*err_msg = "Memory allocation failed.";
3914 		return NULL;
3915 	}
3916 
3917 	/* Initialization. */
3918 	p->name = name;
3919 	p->burst_size = burst_size;
3920 
3921 	return p;
3922 }
3923 
3924 static void *
3925 port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3926 {
3927 	struct rte_swx_port_source_params *p = NULL;
3928 	struct rte_mempool *pool = NULL;
3929 	char *token, *file_name = NULL;
3930 	uint32_t n_loops, n_pkts_max;
3931 
3932 	if ((n_tokens != 8) ||
3933 	    strcmp(tokens[0], "mempool") ||
3934 	    strcmp(tokens[2], "file") ||
3935 	    strcmp(tokens[4], "loop") ||
3936 	    strcmp(tokens[6], "packets")) {
3937 		if (err_msg)
3938 			*err_msg = "Invalid statement.";
3939 		return NULL;
3940 	}
3941 
3942 	/* <mempool_name>. */
3943 	pool = rte_mempool_lookup(tokens[1]);
3944 	if (!pool) {
3945 		if (err_msg)
3946 			*err_msg = "Invalid <mempool_name> parameter.";
3947 		return NULL;
3948 	}
3949 
3950 	/* <n_loops>. */
3951 	token = tokens[5];
3952 	n_loops = strtoul(token, &token, 0);
3953 	if (token[0]) {
3954 		if (err_msg)
3955 			*err_msg = "Invalid <n_loops> parameter.";
3956 		return NULL;
3957 	}
3958 
3959 	/* <n_pkts_max>. */
3960 	token = tokens[7];
3961 	n_pkts_max = strtoul(token, &token, 0);
3962 	if (token[0]) {
3963 		if (err_msg)
3964 			*err_msg = "Invalid <n_pkts_max> parameter.";
3965 		return NULL;
3966 	}
3967 
3968 	/* Memory allocation. */
3969 	file_name = strdup(tokens[3]);
3970 	p = malloc(sizeof(struct rte_swx_port_source_params));
3971 	if (!file_name || !p) {
3972 		free(file_name);
3973 		free(p);
3974 
3975 		if (err_msg)
3976 			*err_msg = "Memory allocation failed.";
3977 		return NULL;
3978 	}
3979 
3980 	/* Initialization. */
3981 	p->pool = pool;
3982 	p->file_name = file_name;
3983 	p->n_loops = n_loops;
3984 	p->n_pkts_max = n_pkts_max;
3985 
3986 	return p;
3987 }
3988 
3989 static void *
3990 port_in_fd_parse(char **tokens,
3991 		 uint32_t n_tokens,
3992 		 const char **err_msg)
3993 {
3994 	struct rte_swx_port_fd_reader_params *p = NULL;
3995 	struct rte_mempool *mempool = NULL;
3996 	char *token;
3997 	uint32_t mtu, burst_size;
3998 	int fd;
3999 
4000 	if ((n_tokens != 7) ||
4001 	    strcmp(tokens[1], "mtu") ||
4002 	    strcmp(tokens[3], "mempool") ||
4003 	    strcmp(tokens[5], "bsz")) {
4004 		if (err_msg)
4005 			*err_msg = "Invalid statement.";
4006 		return NULL;
4007 	}
4008 
4009 	/* <file_descriptor>. */
4010 	token = tokens[0];
4011 	fd = strtol(token, &token, 0);
4012 	if (token[0]) {
4013 		if (err_msg)
4014 			*err_msg = "Invalid <file_descriptor> parameter.";
4015 		return NULL;
4016 	}
4017 
4018 	/* <mtu>. */
4019 	token = tokens[2];
4020 	mtu = strtoul(token, &token, 0);
4021 	if (token[0]) {
4022 		if (err_msg)
4023 			*err_msg = "Invalid <mtu> parameter.";
4024 		return NULL;
4025 	}
4026 
4027 	/* <mempool_name>. */
4028 	mempool = rte_mempool_lookup(tokens[4]);
4029 	if (!mempool) {
4030 		if (err_msg)
4031 			*err_msg = "Invalid <mempool_name> parameter.";
4032 		return NULL;
4033 	}
4034 
4035 	/* <burst_size>. */
4036 	token = tokens[6];
4037 	burst_size = strtoul(token, &token, 0);
4038 	if (token[0]) {
4039 		if (err_msg)
4040 			*err_msg = "Invalid <burst_size> parameter.";
4041 		return NULL;
4042 	}
4043 
4044 	/* Memory allocation. */
4045 	p = malloc(sizeof(struct rte_swx_port_fd_reader_params));
4046 	if (!p) {
4047 		if (err_msg)
4048 			*err_msg = "Memory allocation failed.";
4049 		return NULL;
4050 	}
4051 
4052 	/* Initialization. */
4053 	p->fd = fd;
4054 	p->mtu = mtu;
4055 	p->mempool = mempool;
4056 	p->burst_size = burst_size;
4057 
4058 	return p;
4059 }
4060 
4061 static void *
4062 port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
4063 {
4064 	struct rte_swx_port_ethdev_writer_params *p = NULL;
4065 	char *token, *dev_name = NULL;
4066 	uint32_t queue_id, burst_size;
4067 
4068 	if ((n_tokens != 5) || strcmp(tokens[1], "txq") || strcmp(tokens[3], "bsz")) {
4069 		if (err_msg)
4070 			*err_msg = "Invalid statement.";
4071 		return NULL;
4072 	}
4073 
4074 	/* <queue_id>. */
4075 	token = tokens[2];
4076 	queue_id = strtoul(token, &token, 0);
4077 	if (token[0]) {
4078 		if (err_msg)
4079 			*err_msg = "Invalid <queue_id> parameter.";
4080 		return NULL;
4081 	}
4082 
4083 	/* <burst_size>. */
4084 	token = tokens[4];
4085 	burst_size = strtoul(token, &token, 0);
4086 	if (token[0]) {
4087 		if (err_msg)
4088 			*err_msg = "Invalid <burst_size> parameter.";
4089 		return NULL;
4090 	}
4091 
4092 	/* Memory allocation. */
4093 	dev_name = strdup(tokens[0]);
4094 	p = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));
4095 	if (!dev_name || !p) {
4096 		free(dev_name);
4097 		free(p);
4098 
4099 		if (err_msg)
4100 			*err_msg = "Memory allocation failed.";
4101 		return NULL;
4102 	}
4103 
4104 	/* Initialization. */
4105 	p->dev_name = dev_name;
4106 	p->queue_id = queue_id;
4107 	p->burst_size = burst_size;
4108 
4109 	return p;
4110 }
4111 
4112 static void *
4113 port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
4114 {
4115 	struct rte_swx_port_ring_writer_params *p = NULL;
4116 	char *token, *name = NULL;
4117 	uint32_t burst_size;
4118 
4119 	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
4120 		if (err_msg)
4121 			*err_msg = "Invalid statement.";
4122 		return NULL;
4123 	}
4124 
4125 	/* <burst_size>. */
4126 	token = tokens[2];
4127 	burst_size = strtoul(token, &token, 0);
4128 	if (token[0]) {
4129 		if (err_msg)
4130 			*err_msg = "Invalid <burst_size> parameter.";
4131 		return NULL;
4132 	}
4133 
4134 	/* Memory allocation. */
4135 	name = strdup(tokens[0]);
4136 	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
4137 	if (!name || !p) {
4138 		free(name);
4139 		free(p);
4140 
4141 		if (err_msg)
4142 			*err_msg = "Memory allocation failed.";
4143 		return NULL;
4144 	}
4145 
4146 	/* Initialization. */
4147 	p->name = name;
4148 	p->burst_size = burst_size;
4149 
4150 	return p;
4151 }
4152 
4153 static void *
4154 port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
4155 {
4156 	struct rte_swx_port_sink_params *p = NULL;
4157 	char *file_name = NULL;
4158 	int file_name_valid = 0;
4159 
4160 	if ((n_tokens != 2) || strcmp(tokens[0], "file")) {
4161 		if (err_msg)
4162 			*err_msg = "Invalid statement.";
4163 		return NULL;
4164 	}
4165 
4166 	/* Memory allocation. */
4167 	if (strcmp(tokens[1], "none")) {
4168 		file_name_valid = 1;
4169 		file_name = strdup(tokens[1]);
4170 	}
4171 
4172 	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
4173 	if ((file_name_valid && !file_name) || !p) {
4174 		free(file_name);
4175 		free(p);
4176 
4177 		if (err_msg)
4178 			*err_msg = "Memory allocation failed.";
4179 		return NULL;
4180 	}
4181 
4182 	/* Initialization. */
4183 	p->file_name = file_name;
4184 
4185 	return p;
4186 }
4187 
4188 static void *
4189 port_out_fd_parse(char **tokens,
4190 		  uint32_t n_tokens,
4191 		  const char **err_msg)
4192 {
4193 	struct rte_swx_port_fd_writer_params *p = NULL;
4194 	char *token;
4195 	uint32_t burst_size;
4196 	int fd;
4197 
4198 	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
4199 		if (err_msg)
4200 			*err_msg = "Invalid statement.";
4201 		return NULL;
4202 	}
4203 
4204 	/* <file_descriptor>. */
4205 	token = tokens[0];
4206 	fd = strtol(token, &token, 0);
4207 	if (token[0]) {
4208 		if (err_msg)
4209 			*err_msg = "Invalid <file_descriptor> parameter.";
4210 		return NULL;
4211 	}
4212 
4213 	/* <burst_size>. */
4214 	token = tokens[2];
4215 	burst_size = strtoul(token, &token, 0);
4216 	if (token[0]) {
4217 		if (err_msg)
4218 			*err_msg = "Invalid <burst_size> parameter.";
4219 		return NULL;
4220 	}
4221 
4222 	/* Memory allocation. */
4223 	p = malloc(sizeof(struct rte_swx_port_fd_writer_params));
4224 	if (!p) {
4225 		if (err_msg)
4226 			*err_msg = "Memory allocation failed.";
4227 		return NULL;
4228 	}
4229 
4230 	/* Initialization. */
4231 	p->fd = fd;
4232 	p->burst_size = burst_size;
4233 
4234 	return p;
4235 }
4236 
4237 struct pipeline_iospec *
4238 pipeline_iospec_parse(FILE *spec,
4239 		      uint32_t *err_line,
4240 		      const char **err_msg)
4241 {
4242 	struct pipeline_iospec *s = NULL;
4243 	uint32_t n_lines = 0;
4244 
4245 	/* Check the input arguments. */
4246 	if (!spec) {
4247 		if (err_line)
4248 			*err_line = n_lines;
4249 		if (err_msg)
4250 			*err_msg = "Invalid input argument.";
4251 		goto error;
4252 	}
4253 
4254 	/* Memory allocation. */
4255 	s = calloc(sizeof(struct pipeline_iospec), 1);
4256 	if (!s) {
4257 		if (err_line)
4258 			*err_line = n_lines;
4259 		if (err_msg)
4260 			*err_msg = "Memory allocation failed.";
4261 		goto error;
4262 	}
4263 
4264 	/* Initialize with the default values. */
4265 	s->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;
4266 	s->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;
4267 
4268 	for (n_lines = 1; ; n_lines++) {
4269 		char line[MAX_LINE_LENGTH];
4270 		char *tokens[MAX_TOKENS], *ptr = line;
4271 		uint32_t n_tokens = 0;
4272 
4273 		/* Read next line. */
4274 		if (!fgets(line, sizeof(line), spec))
4275 			break;
4276 
4277 		/* Parse the line into tokens. */
4278 		for ( ; ; ) {
4279 			char *token;
4280 
4281 			/* Get token. */
4282 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
4283 			if (!token)
4284 				break;
4285 
4286 			/* Handle comments. */
4287 			if ((token[0] == '#') ||
4288 			    (token[0] == ';') ||
4289 			    ((token[0] == '/') && (token[1] == '/'))) {
4290 				break;
4291 			}
4292 
4293 			/* Handle excessively long lines. */
4294 			if (n_tokens >= RTE_DIM(tokens)) {
4295 				if (err_line)
4296 					*err_line = n_lines;
4297 				if (err_msg)
4298 					*err_msg = "Too many tokens.";
4299 				goto error;
4300 			}
4301 
4302 			/* Handle excessively long tokens. */
4303 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
4304 			    RTE_SWX_NAME_SIZE) {
4305 				if (err_line)
4306 					*err_line = n_lines;
4307 				if (err_msg)
4308 					*err_msg = "Token too big.";
4309 				goto error;
4310 			}
4311 
4312 			/* Save token. */
4313 			tokens[n_tokens] = token;
4314 			n_tokens++;
4315 		}
4316 
4317 		/* Handle empty lines. */
4318 		if (!n_tokens)
4319 			continue;
4320 
4321 		/* mirroring. */
4322 		if ((n_tokens >= 1) && !strcmp(tokens[0], "mirroring")) {
4323 			int status = 0;
4324 
4325 			status = mirroring_parse(&s->mirroring_params,
4326 						 &tokens[1],
4327 						 n_tokens - 1,
4328 						 err_msg);
4329 			if (status) {
4330 				if (err_line)
4331 					*err_line = n_lines;
4332 				goto error;
4333 			}
4334 
4335 			continue;
4336 		}
4337 
4338 		/* port in. */
4339 		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "in")) {
4340 			char *token = tokens[2];
4341 			uint32_t *new_id = NULL;
4342 			const char **new_type = NULL, *port_type = NULL;
4343 			void **new_params = NULL, *p = NULL;
4344 			uint32_t port_id;
4345 
4346 			/* <port_id>. */
4347 			port_id = strtoul(token, &token, 0);
4348 			if (token[0]) {
4349 				if (err_line)
4350 					*err_line = n_lines;
4351 				if (err_msg)
4352 					*err_msg = "Invalid port ID.";
4353 				goto error;
4354 			}
4355 
4356 			/* <port_type>. */
4357 			if (!strcmp(tokens[3], "ethdev"))
4358 				p = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
4359 			else if (!strcmp(tokens[3], "ring"))
4360 				p = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);
4361 			else if (!strcmp(tokens[3], "source"))
4362 				p = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);
4363 			else if (!strcmp(tokens[3], "fd"))
4364 				p = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);
4365 			else {
4366 				p = NULL;
4367 				if (err_msg)
4368 					*err_msg = "Invalid port type.";
4369 			}
4370 
4371 			if (!p) {
4372 				if (err_line)
4373 					*err_line = n_lines;
4374 				goto error;
4375 			}
4376 
4377 			/* New port. */
4378 			port_type = strdup(tokens[3]);
4379 			new_id = realloc(s->port_in_id,
4380 					 (s->n_ports_in + 1) * sizeof(uint32_t));
4381 			new_type = realloc(s->port_in_type,
4382 					   (s->n_ports_in + 1) * sizeof(char *));
4383 			new_params = realloc(s->port_in_params,
4384 					     (s->n_ports_in + 1) * sizeof(void *));
4385 			if (!port_type || !new_id || !new_type || !new_params) {
4386 				uintptr_t pt = (uintptr_t)port_type;
4387 
4388 				port_in_params_free(p, tokens[3]);
4389 				free((void *)pt);
4390 				free(new_id);
4391 				free(new_type);
4392 				free(new_params);
4393 
4394 				if (err_line)
4395 					*err_line = n_lines;
4396 				if (err_msg)
4397 					*err_msg = "Memory allocation failed.";
4398 				goto error;
4399 			}
4400 
4401 			s->port_in_id = new_id;
4402 			s->port_in_type = new_type;
4403 			s->port_in_params = new_params;
4404 
4405 			s->port_in_id[s->n_ports_in] = port_id;
4406 			s->port_in_type[s->n_ports_in] = port_type;
4407 			s->port_in_params[s->n_ports_in] = p;
4408 			s->n_ports_in++;
4409 
4410 			continue;
4411 		}
4412 
4413 		/* port out. */
4414 		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "out")) {
4415 			char *token = tokens[2];
4416 			uint32_t *new_id = NULL;
4417 			const char **new_type = NULL, *port_type = NULL;
4418 			void **new_params = NULL, *p = NULL;
4419 			uint32_t port_id;
4420 
4421 			/* <port_id>. */
4422 			port_id = strtoul(token, &token, 0);
4423 			if (token[0]) {
4424 				if (err_line)
4425 					*err_line = n_lines;
4426 				if (err_msg)
4427 					*err_msg = "Invalid port ID.";
4428 				goto error;
4429 			}
4430 
4431 			/* <port_type>. */
4432 			if (!strcmp(tokens[3], "ethdev"))
4433 				p = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
4434 			else if (!strcmp(tokens[3], "ring"))
4435 				p = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);
4436 			else if (!strcmp(tokens[3], "sink"))
4437 				p = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);
4438 			else if (!strcmp(tokens[3], "fd"))
4439 				p = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);
4440 			else {
4441 				p = NULL;
4442 				if (err_msg)
4443 					*err_msg = "Invalid port type.";
4444 			}
4445 
4446 			if (!p) {
4447 				if (err_line)
4448 					*err_line = n_lines;
4449 				goto error;
4450 			}
4451 
4452 			/* New port. */
4453 			port_type = strdup(tokens[3]);
4454 			new_id = realloc(s->port_out_id,
4455 					 (s->n_ports_out + 1) * sizeof(uint32_t));
4456 			new_type = realloc(s->port_out_type,
4457 					   (s->n_ports_out + 1) * sizeof(char *));
4458 			new_params = realloc(s->port_out_params,
4459 					     (s->n_ports_out + 1) * sizeof(void *));
4460 			if (!port_type || !new_id || !new_type || !new_params) {
4461 				uintptr_t pt = (uintptr_t)port_type;
4462 
4463 				port_out_params_free(p, tokens[3]);
4464 				free((void *)pt);
4465 				free(new_id);
4466 				free(new_type);
4467 				free(new_params);
4468 
4469 				if (err_line)
4470 					*err_line = n_lines;
4471 				if (err_msg)
4472 					*err_msg = "Memory allocation failed.";
4473 				goto error;
4474 			}
4475 
4476 			s->port_out_id = new_id;
4477 			s->port_out_type = new_type;
4478 			s->port_out_params = new_params;
4479 
4480 			s->port_out_id[s->n_ports_out] = port_id;
4481 			s->port_out_type[s->n_ports_out] = port_type;
4482 			s->port_out_params[s->n_ports_out] = p;
4483 			s->n_ports_out++;
4484 
4485 			continue;
4486 		}
4487 
4488 		/* Anything else. */
4489 		if (err_line)
4490 			*err_line = n_lines;
4491 		if (err_msg)
4492 			*err_msg = "Unknown I/O statement.";
4493 		goto error;
4494 	}
4495 
4496 	return s;
4497 
4498 error:
4499 	pipeline_iospec_free(s);
4500 
4501 	return NULL;
4502 }
4503 
4504 int
4505 pipeline_iospec_configure(struct rte_swx_pipeline *p,
4506 			  struct pipeline_iospec *s,
4507 			  const char **err_msg)
4508 {
4509 	uint32_t i;
4510 	int status = 0;
4511 
4512 	/* Check input arguments. */
4513 	if (!p || !s) {
4514 		if (err_msg)
4515 			*err_msg = "Invalid input argument";
4516 		return -EINVAL;
4517 	}
4518 
4519 	/* Mirroring. */
4520 	status = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);
4521 	if (status) {
4522 		if (err_msg)
4523 			*err_msg = "Pipeline mirroring configuration error.";
4524 		return status;
4525 	}
4526 
4527 	/* Input ports. */
4528 	for (i = 0; i < s->n_ports_in; i++) {
4529 		status = rte_swx_pipeline_port_in_config(p,
4530 							 i,
4531 							 s->port_in_type[i],
4532 							 s->port_in_params[i]);
4533 		if (status) {
4534 			if (err_msg)
4535 				*err_msg = "Pipeline input port configuration error.";
4536 			return status;
4537 		}
4538 	}
4539 
4540 	/* Output ports. */
4541 	for (i = 0; i < s->n_ports_out; i++) {
4542 		status = rte_swx_pipeline_port_out_config(p,
4543 							  i,
4544 							  s->port_out_type[i],
4545 							  s->port_out_params[i]);
4546 		if (status) {
4547 			if (err_msg)
4548 				*err_msg = "Pipeline output port configuration error.";
4549 			return status;
4550 		}
4551 	}
4552 
4553 	return 0;
4554 }
4555