xref: /dpdk/lib/pipeline/rte_swx_pipeline_spec.c (revision b269bd630e96b276a69d698e13ad9ebfbbb67512)
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  * apply.
2054  *
2055  */
2056 static void
2057 apply_spec_free(struct apply_spec *s)
2058 {
2059 	uint32_t i;
2060 
2061 	if (!s)
2062 		return;
2063 
2064 	for (i = 0; i < s->n_instructions; i++) {
2065 		uintptr_t instr = (uintptr_t)s->instructions[i];
2066 
2067 		free((void *)instr);
2068 	}
2069 
2070 	free(s->instructions);
2071 	s->instructions = NULL;
2072 
2073 	s->n_instructions = 0;
2074 }
2075 
2076 static int
2077 apply_statement_parse(uint32_t *block_mask,
2078 		      char **tokens,
2079 		      uint32_t n_tokens,
2080 		      uint32_t n_lines,
2081 		      uint32_t *err_line,
2082 		      const char **err_msg)
2083 {
2084 	/* Check format. */
2085 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
2086 		if (err_line)
2087 			*err_line = n_lines;
2088 		if (err_msg)
2089 			*err_msg = "Invalid apply statement.";
2090 		return -EINVAL;
2091 	}
2092 
2093 	/* block_mask. */
2094 	*block_mask |= 1 << APPLY_BLOCK;
2095 
2096 	return 0;
2097 }
2098 
2099 static int
2100 apply_block_parse(struct apply_spec *s,
2101 		  uint32_t *block_mask,
2102 		  char **tokens,
2103 		  uint32_t n_tokens,
2104 		  uint32_t n_lines,
2105 		  uint32_t *err_line,
2106 		  const char **err_msg)
2107 {
2108 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
2109 	const char **new_instructions;
2110 	uint32_t i;
2111 
2112 	/* Handle end of block. */
2113 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
2114 		*block_mask &= ~(1 << APPLY_BLOCK);
2115 		return 0;
2116 	}
2117 
2118 	/* spec. */
2119 	buffer[0] = 0;
2120 	for (i = 0; i < n_tokens; i++) {
2121 		if (i)
2122 			strcat(buffer, " ");
2123 		strcat(buffer, tokens[i]);
2124 	}
2125 
2126 	instr = strdup(buffer);
2127 	if (!instr) {
2128 		if (err_line)
2129 			*err_line = n_lines;
2130 		if (err_msg)
2131 			*err_msg = "Memory allocation failed.";
2132 		return -ENOMEM;
2133 	}
2134 
2135 	new_instructions = realloc(s->instructions,
2136 				   (s->n_instructions + 1) * sizeof(char *));
2137 	if (!new_instructions) {
2138 		free(instr);
2139 
2140 		if (err_line)
2141 			*err_line = n_lines;
2142 		if (err_msg)
2143 			*err_msg = "Memory allocation failed.";
2144 		return -ENOMEM;
2145 	}
2146 
2147 	s->instructions = new_instructions;
2148 	s->instructions[s->n_instructions] = instr;
2149 	s->n_instructions++;
2150 
2151 	return 0;
2152 }
2153 
2154 /*
2155  * Pipeline.
2156  */
2157 void
2158 pipeline_spec_free(struct pipeline_spec *s)
2159 {
2160 	if (!s)
2161 		return;
2162 
2163 	free(s->extobjs);
2164 	free(s->structs);
2165 	free(s->headers);
2166 	free(s->metadata);
2167 	free(s->actions);
2168 	free(s->tables);
2169 	free(s->selectors);
2170 	free(s->learners);
2171 	free(s->regarrays);
2172 	free(s->metarrays);
2173 	free(s->apply);
2174 
2175 	memset(s, 0, sizeof(struct pipeline_spec));
2176 }
2177 
2178 static const char *
2179 match_type_string_get(enum rte_swx_table_match_type match_type)
2180 {
2181 	switch (match_type) {
2182 	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
2183 	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
2184 	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
2185 	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
2186 	}
2187 }
2188 
2189 void
2190 pipeline_spec_codegen(FILE *f,
2191 		      struct pipeline_spec *s)
2192 {
2193 	uint32_t i;
2194 
2195 	/* Check the input arguments. */
2196 	if (!f || !s)
2197 		return;
2198 
2199 	/* extobj. */
2200 	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
2201 
2202 	for (i = 0; i < s->n_extobjs; i++) {
2203 		struct extobj_spec *extobj_spec = &s->extobjs[i];
2204 
2205 		fprintf(f, "\t[%d] = {\n", i);
2206 		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
2207 		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
2208 		if (extobj_spec->pragma)
2209 			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
2210 		else
2211 			fprintf(f, "\t\t.pragma = NULL,\n");
2212 		fprintf(f, "\t},\n");
2213 	}
2214 
2215 	fprintf(f, "};\n\n");
2216 
2217 	/* regarray. */
2218 	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
2219 
2220 	for (i = 0; i < s->n_regarrays; i++) {
2221 		struct regarray_spec *regarray_spec = &s->regarrays[i];
2222 
2223 		fprintf(f, "\t[%d] = {\n", i);
2224 		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
2225 		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
2226 		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
2227 		fprintf(f, "\t},\n");
2228 	}
2229 
2230 	fprintf(f, "};\n\n");
2231 
2232 	/* metarray. */
2233 	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
2234 
2235 	for (i = 0; i < s->n_metarrays; i++) {
2236 		struct metarray_spec *metarray_spec = &s->metarrays[i];
2237 
2238 		fprintf(f, "\t[%d] = {\n", i);
2239 		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
2240 		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
2241 		fprintf(f, "\t},\n");
2242 	}
2243 
2244 	fprintf(f, "};\n\n");
2245 
2246 	/* struct. */
2247 	for (i = 0; i < s->n_structs; i++) {
2248 		struct struct_spec *struct_spec = &s->structs[i];
2249 		uint32_t j;
2250 
2251 		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
2252 			struct_spec->name);
2253 
2254 		for (j = 0; j < struct_spec->n_fields; j++) {
2255 			struct rte_swx_field_params *field = &struct_spec->fields[j];
2256 
2257 			fprintf(f, "\t[%d] = {\n", j);
2258 			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
2259 			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
2260 			fprintf(f, "\t},\n");
2261 		}
2262 
2263 		fprintf(f, "};\n\n");
2264 	}
2265 
2266 	fprintf(f, "static struct struct_spec structs[] = {\n");
2267 
2268 	for (i = 0; i < s->n_structs; i++) {
2269 		struct struct_spec *struct_spec = &s->structs[i];
2270 
2271 		fprintf(f, "\t[%d] = {\n", i);
2272 		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
2273 		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
2274 		fprintf(f, "\t\t.n_fields = "
2275 			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
2276 			struct_spec->name,
2277 			struct_spec->name);
2278 		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
2279 		fprintf(f, "\t},\n");
2280 	}
2281 
2282 	fprintf(f, "};\n\n");
2283 
2284 	/* header. */
2285 	fprintf(f, "static struct header_spec headers[] = {\n");
2286 
2287 	for (i = 0; i < s->n_headers; i++) {
2288 		struct header_spec *header_spec = &s->headers[i];
2289 
2290 		fprintf(f, "\t[%d] = {\n", i);
2291 		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
2292 		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
2293 		fprintf(f, "\t},\n");
2294 	}
2295 
2296 	fprintf(f, "};\n\n");
2297 
2298 	/* metadata. */
2299 	fprintf(f, "static struct metadata_spec metadata[] = {\n");
2300 
2301 	for (i = 0; i < s->n_metadata; i++) {
2302 		struct metadata_spec *metadata_spec = &s->metadata[i];
2303 
2304 		fprintf(f, "\t[%d] = {\n", i);
2305 		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
2306 		fprintf(f, "\t},\n");
2307 
2308 	}
2309 
2310 	fprintf(f, "};\n\n");
2311 
2312 	/* action. */
2313 	for (i = 0; i < s->n_actions; i++) {
2314 		struct action_spec *action_spec = &s->actions[i];
2315 		uint32_t j;
2316 
2317 		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
2318 			action_spec->name);
2319 
2320 		for (j = 0; j < action_spec->n_instructions; j++) {
2321 			const char *instr = action_spec->instructions[j];
2322 
2323 			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
2324 		}
2325 
2326 		fprintf(f, "};\n\n");
2327 	}
2328 
2329 	fprintf(f, "static struct action_spec actions[] = {\n");
2330 
2331 	for (i = 0; i < s->n_actions; i++) {
2332 		struct action_spec *action_spec = &s->actions[i];
2333 
2334 		fprintf(f, "\t[%d] = {\n", i);
2335 		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
2336 
2337 		if (action_spec->args_struct_type_name)
2338 			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
2339 				action_spec->args_struct_type_name);
2340 		else
2341 			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
2342 
2343 		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
2344 			action_spec->name);
2345 		fprintf(f, "\t\t.n_instructions = "
2346 			"sizeof(action_%s_initial_instructions) / "
2347 			"sizeof(action_%s_initial_instructions[0]),\n",
2348 			action_spec->name,
2349 			action_spec->name);
2350 		fprintf(f, "\t},\n");
2351 	}
2352 
2353 	fprintf(f, "};\n\n");
2354 
2355 	/* table. */
2356 	for (i = 0; i < s->n_tables; i++) {
2357 		struct table_spec *table_spec = &s->tables[i];
2358 		uint32_t j;
2359 
2360 		/* fields. */
2361 		if (table_spec->params.fields && table_spec->params.n_fields) {
2362 			fprintf(f, "static struct rte_swx_match_field_params "
2363 				"table_%s_fields[] = {\n",
2364 				table_spec->name);
2365 
2366 			for (j = 0; j < table_spec->params.n_fields; j++) {
2367 				struct rte_swx_match_field_params *field =
2368 					&table_spec->params.fields[j];
2369 
2370 				fprintf(f, "\t[%d] = {\n", j);
2371 				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
2372 				fprintf(f, "\t\t.match_type = %s,\n",
2373 					match_type_string_get(field->match_type));
2374 				fprintf(f, "\t},\n");
2375 			}
2376 
2377 			fprintf(f, "};\n\n");
2378 		}
2379 
2380 		/* action_names. */
2381 		if (table_spec->params.action_names && table_spec->params.n_actions) {
2382 			fprintf(f, "static const char *table_%s_action_names[] = {\n",
2383 				table_spec->name);
2384 
2385 			for (j = 0; j < table_spec->params.n_actions; j++) {
2386 				const char *action_name = table_spec->params.action_names[j];
2387 
2388 				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
2389 			}
2390 
2391 			fprintf(f, "};\n\n");
2392 		}
2393 
2394 		/* action_is_for_table_entries. */
2395 		if (table_spec->params.action_is_for_table_entries &&
2396 		    table_spec->params.n_actions) {
2397 			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
2398 				table_spec->name);
2399 
2400 			for (j = 0; j < table_spec->params.n_actions; j++) {
2401 				int value = table_spec->params.action_is_for_table_entries[j];
2402 
2403 				fprintf(f, "\t[%d] = %d,\n", j, value);
2404 			}
2405 
2406 			fprintf(f, "};\n\n");
2407 		}
2408 
2409 		/* action_is_for_default_entry. */
2410 		if (table_spec->params.action_is_for_default_entry &&
2411 		    table_spec->params.n_actions) {
2412 			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
2413 				table_spec->name);
2414 
2415 			for (j = 0; j < table_spec->params.n_actions; j++) {
2416 				int value = table_spec->params.action_is_for_default_entry[j];
2417 
2418 				fprintf(f, "\t[%d] = %d,\n", j, value);
2419 			}
2420 
2421 			fprintf(f, "};\n\n");
2422 		}
2423 	}
2424 
2425 	fprintf(f, "static struct table_spec tables[] = {\n");
2426 
2427 	for (i = 0; i < s->n_tables; i++) {
2428 		struct table_spec *table_spec = &s->tables[i];
2429 
2430 		fprintf(f, "\t[%d] = {\n", i);
2431 		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
2432 
2433 		fprintf(f, "\t\t.params = {\n");
2434 
2435 		if (table_spec->params.fields && table_spec->params.n_fields) {
2436 			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
2437 			fprintf(f, "\t\t\t.n_fields = "
2438 				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
2439 				table_spec->name,
2440 				table_spec->name);
2441 		} else {
2442 			fprintf(f, "\t\t\t.fields = NULL,\n");
2443 			fprintf(f, "\t\t\t.n_fields = 0,\n");
2444 		}
2445 
2446 		if (table_spec->params.action_names && table_spec->params.n_actions)
2447 			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
2448 				table_spec->name);
2449 		else
2450 			fprintf(f, "\t\t\t.action_names = NULL,\n");
2451 
2452 		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
2453 			fprintf(f, "\t\t\t.action_is_for_table_entries = "
2454 				"table_%s_action_is_for_table_entries,\n",
2455 				table_spec->name);
2456 		else
2457 			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
2458 
2459 		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
2460 			fprintf(f, "\t\t\t.action_is_for_default_entry = "
2461 				"table_%s_action_is_for_default_entry,\n",
2462 				table_spec->name);
2463 		else
2464 			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
2465 
2466 		if (table_spec->params.n_actions)
2467 			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
2468 				"sizeof(table_%s_action_names[0]),\n",
2469 				table_spec->name,
2470 				table_spec->name);
2471 		else
2472 			fprintf(f, "\t\t\t.n_actions = 0,\n");
2473 
2474 		if (table_spec->params.default_action_name)
2475 			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
2476 				table_spec->params.default_action_name);
2477 		else
2478 			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
2479 
2480 		if (table_spec->params.default_action_args)
2481 			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
2482 				table_spec->params.default_action_args);
2483 		else
2484 			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
2485 
2486 		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
2487 			table_spec->params.default_action_is_const);
2488 
2489 		if (table_spec->params.hash_func_name)
2490 			fprintf(f, "\t\t\t.hash_func_name = \"%s\",\n",
2491 				table_spec->params.hash_func_name);
2492 		else
2493 			fprintf(f, "\t\t\t.hash_func_name = NULL,\n");
2494 
2495 		fprintf(f, "\t\t},\n");
2496 
2497 		if (table_spec->recommended_table_type_name)
2498 			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
2499 				table_spec->recommended_table_type_name);
2500 		else
2501 			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
2502 
2503 		if (table_spec->args)
2504 			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
2505 		else
2506 			fprintf(f, "\t\t.args = NULL,\n");
2507 
2508 		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
2509 
2510 		fprintf(f, "\t},\n");
2511 	}
2512 
2513 	fprintf(f, "};\n\n");
2514 
2515 	/* selector. */
2516 	for (i = 0; i < s->n_selectors; i++) {
2517 		struct selector_spec *selector_spec = &s->selectors[i];
2518 		uint32_t j;
2519 
2520 		if (selector_spec->params.selector_field_names &&
2521 		    selector_spec->params.n_selector_fields) {
2522 			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
2523 				selector_spec->name);
2524 
2525 			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
2526 				const char *field_name =
2527 					selector_spec->params.selector_field_names[j];
2528 
2529 				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
2530 			}
2531 
2532 			fprintf(f, "};\n\n");
2533 		}
2534 	}
2535 
2536 	fprintf(f, "static struct selector_spec selectors[] = {\n");
2537 
2538 	for (i = 0; i < s->n_selectors; i++) {
2539 		struct selector_spec *selector_spec = &s->selectors[i];
2540 
2541 		fprintf(f, "\t[%d] = {\n", i);
2542 
2543 		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
2544 		fprintf(f, "\t\t.params = {\n");
2545 
2546 		if (selector_spec->params.group_id_field_name)
2547 			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
2548 				selector_spec->params.group_id_field_name);
2549 		else
2550 			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
2551 
2552 		if (selector_spec->params.selector_field_names &&
2553 		    selector_spec->params.n_selector_fields) {
2554 			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
2555 				selector_spec->name);
2556 			fprintf(f, "\t\t\t.n_selector_fields = "
2557 				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
2558 				selector_spec->name,
2559 				selector_spec->name);
2560 		} else {
2561 			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
2562 			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
2563 		}
2564 
2565 		if (selector_spec->params.member_id_field_name)
2566 			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
2567 				selector_spec->params.member_id_field_name);
2568 		else
2569 			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
2570 
2571 		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
2572 
2573 		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
2574 			selector_spec->params.n_members_per_group_max);
2575 
2576 		fprintf(f, "\t\t},\n");
2577 		fprintf(f, "\t},\n");
2578 	}
2579 
2580 	fprintf(f, "};\n\n");
2581 
2582 	/* learner. */
2583 	for (i = 0; i < s->n_learners; i++) {
2584 		struct learner_spec *learner_spec = &s->learners[i];
2585 		uint32_t j;
2586 
2587 		/* field_names. */
2588 		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
2589 			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
2590 				learner_spec->name);
2591 
2592 			for (j = 0; j < learner_spec->params.n_fields; j++) {
2593 				const char *field_name = learner_spec->params.field_names[j];
2594 
2595 				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
2596 			}
2597 
2598 			fprintf(f, "};\n\n");
2599 		}
2600 
2601 		/* action_names. */
2602 		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
2603 			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
2604 				learner_spec->name);
2605 
2606 			for (j = 0; j < learner_spec->params.n_actions; j++) {
2607 				const char *action_name = learner_spec->params.action_names[j];
2608 
2609 				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
2610 			}
2611 
2612 			fprintf(f, "};\n\n");
2613 		}
2614 
2615 		/* action_is_for_table_entries. */
2616 		if (learner_spec->params.action_is_for_table_entries &&
2617 		    learner_spec->params.n_actions) {
2618 			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
2619 				learner_spec->name);
2620 
2621 			for (j = 0; j < learner_spec->params.n_actions; j++) {
2622 				int value = learner_spec->params.action_is_for_table_entries[j];
2623 
2624 				fprintf(f, "\t[%d] = %d,\n", j, value);
2625 			}
2626 
2627 			fprintf(f, "};\n\n");
2628 		}
2629 
2630 		/* action_is_for_default_entry. */
2631 		if (learner_spec->params.action_is_for_default_entry &&
2632 		    learner_spec->params.n_actions) {
2633 			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
2634 				learner_spec->name);
2635 
2636 			for (j = 0; j < learner_spec->params.n_actions; j++) {
2637 				int value = learner_spec->params.action_is_for_default_entry[j];
2638 
2639 				fprintf(f, "\t[%d] = %d,\n", j, value);
2640 			}
2641 
2642 			fprintf(f, "};\n\n");
2643 		}
2644 
2645 		/* timeout. */
2646 		if (learner_spec->timeout && learner_spec->n_timeouts) {
2647 			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
2648 				learner_spec->name);
2649 
2650 			for (j = 0; j < learner_spec->n_timeouts; j++) {
2651 				uint32_t value = learner_spec->timeout[j];
2652 
2653 				fprintf(f, "\t[%d] = %u,\n", j, value);
2654 			}
2655 
2656 			fprintf(f, "};\n\n");
2657 		}
2658 	}
2659 
2660 	fprintf(f, "static struct learner_spec learners[] = {\n");
2661 
2662 	for (i = 0; i < s->n_learners; i++) {
2663 		struct learner_spec *learner_spec = &s->learners[i];
2664 
2665 		fprintf(f, "\t[%d] = {\n", i);
2666 		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
2667 
2668 		fprintf(f, "\t\t.params = {\n");
2669 
2670 		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
2671 			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
2672 				learner_spec->name);
2673 			fprintf(f, "\t\t\t.n_fields = "
2674 				"sizeof(learner_%s_field_names) / "
2675 				"sizeof(learner_%s_field_names[0]),\n",
2676 				learner_spec->name,
2677 				learner_spec->name);
2678 		} else {
2679 			fprintf(f, "\t\t\t.field_names = NULL,\n");
2680 			fprintf(f, "\t\t\t.n_fields = 0,\n");
2681 		}
2682 
2683 		if (learner_spec->params.action_names && learner_spec->params.n_actions)
2684 			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
2685 				learner_spec->name);
2686 		else
2687 			fprintf(f, "\t\t\t.action_names = NULL,\n");
2688 
2689 		if (learner_spec->params.action_is_for_table_entries &&
2690 		    learner_spec->params.n_actions)
2691 			fprintf(f, "\t\t\t.action_is_for_table_entries = "
2692 				"learner_%s_action_is_for_table_entries,\n",
2693 				learner_spec->name);
2694 		else
2695 			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
2696 
2697 		if (learner_spec->params.action_is_for_default_entry &&
2698 		    learner_spec->params.n_actions)
2699 			fprintf(f, "\t\t\t.action_is_for_default_entry = "
2700 				"learner_%s_action_is_for_default_entry,\n",
2701 				learner_spec->name);
2702 		else
2703 			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
2704 
2705 		if (learner_spec->params.action_names && learner_spec->params.n_actions)
2706 			fprintf(f, "\t\t\t.n_actions = "
2707 				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
2708 				learner_spec->name,
2709 				learner_spec->name);
2710 		else
2711 			fprintf(f, "\t\t\t.n_actions = NULL,\n");
2712 
2713 		if (learner_spec->params.default_action_name)
2714 			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
2715 				learner_spec->params.default_action_name);
2716 		else
2717 			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
2718 
2719 		if (learner_spec->params.default_action_args)
2720 			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
2721 				learner_spec->params.default_action_args);
2722 		else
2723 			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
2724 
2725 		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
2726 			learner_spec->params.default_action_is_const);
2727 
2728 		if (learner_spec->params.hash_func_name)
2729 			fprintf(f, "\t\t\t.hash_func_name = \"%s\",\n",
2730 				learner_spec->params.hash_func_name);
2731 		else
2732 			fprintf(f, "\t\t\t.hash_func_name = NULL,\n");
2733 
2734 		fprintf(f, "\t\t},\n");
2735 
2736 		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
2737 
2738 		if (learner_spec->timeout && learner_spec->n_timeouts) {
2739 			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
2740 			fprintf(f, "\t\t\t.n_timeouts = "
2741 				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
2742 				learner_spec->name,
2743 				learner_spec->name);
2744 		} else {
2745 			fprintf(f, "\t\t.timeout = NULL,\n");
2746 			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
2747 		}
2748 
2749 		fprintf(f, "\t},\n");
2750 	}
2751 
2752 	fprintf(f, "};\n\n");
2753 
2754 	/* apply. */
2755 	for (i = 0; i < s->n_apply; i++) {
2756 		struct apply_spec *apply_spec = &s->apply[i];
2757 		uint32_t j;
2758 
2759 		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
2760 
2761 		for (j = 0; j < apply_spec->n_instructions; j++) {
2762 			const char *instr = apply_spec->instructions[j];
2763 
2764 			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
2765 		}
2766 
2767 		fprintf(f, "};\n\n");
2768 	}
2769 
2770 	fprintf(f, "static struct apply_spec apply[] = {\n");
2771 
2772 	for (i = 0; i < s->n_apply; i++) {
2773 		fprintf(f, "\t[%d] = {\n", i);
2774 		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
2775 		fprintf(f, "\t.n_instructions = "
2776 			"sizeof(apply%u_initial_instructions) / "
2777 			"sizeof(apply%u_initial_instructions[0]),\n",
2778 			i,
2779 			i);
2780 		fprintf(f, "\t},\n");
2781 	}
2782 
2783 	fprintf(f, "};\n\n");
2784 
2785 	/* pipeline. */
2786 	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
2787 	fprintf(f, "\t.extobjs = extobjs,\n");
2788 	fprintf(f, "\t.structs = structs,\n");
2789 	fprintf(f, "\t.headers = headers,\n");
2790 	fprintf(f, "\t.metadata = metadata,\n");
2791 	fprintf(f, "\t.actions = actions,\n");
2792 	fprintf(f, "\t.tables = tables,\n");
2793 	fprintf(f, "\t.selectors = selectors,\n");
2794 	fprintf(f, "\t.learners = learners,\n");
2795 	fprintf(f, "\t.regarrays = regarrays,\n");
2796 	fprintf(f, "\t.metarrays = metarrays,\n");
2797 	fprintf(f, "\t.apply = apply,\n");
2798 	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
2799 	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
2800 	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
2801 	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
2802 	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
2803 	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
2804 	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
2805 	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
2806 	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
2807 	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
2808 	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
2809 	fprintf(f, "};\n");
2810 }
2811 
2812 struct pipeline_spec *
2813 pipeline_spec_parse(FILE *spec,
2814 		    uint32_t *err_line,
2815 		    const char **err_msg)
2816 {
2817 	struct extobj_spec extobj_spec = {0};
2818 	struct struct_spec struct_spec = {0};
2819 	struct header_spec header_spec = {0};
2820 	struct metadata_spec metadata_spec = {0};
2821 	struct action_spec action_spec = {0};
2822 	struct table_spec table_spec = {0};
2823 	struct selector_spec selector_spec = {0};
2824 	struct learner_spec learner_spec = {0};
2825 	struct regarray_spec regarray_spec = {0};
2826 	struct metarray_spec metarray_spec = {0};
2827 	struct apply_spec apply_spec = {0};
2828 	struct pipeline_spec *s = NULL;
2829 	uint32_t n_lines = 0;
2830 	uint32_t block_mask = 0;
2831 	int status = 0;
2832 
2833 	/* Check the input arguments. */
2834 	if (!spec) {
2835 		if (err_line)
2836 			*err_line = n_lines;
2837 		if (err_msg)
2838 			*err_msg = "Invalid input argument.";
2839 		status = -EINVAL;
2840 		goto error;
2841 	}
2842 
2843 	/* Memory allocation. */
2844 	s = calloc(sizeof(struct pipeline_spec), 1);
2845 	if (!s) {
2846 		if (err_line)
2847 			*err_line = n_lines;
2848 		if (err_msg)
2849 			*err_msg = "Memory allocation failed.";
2850 		status = -ENOMEM;
2851 		goto error;
2852 	}
2853 
2854 	for (n_lines = 1; ; n_lines++) {
2855 		char line[MAX_LINE_LENGTH];
2856 		char *tokens[MAX_TOKENS], *ptr = line;
2857 		uint32_t n_tokens = 0;
2858 
2859 		/* Read next line. */
2860 		if (!fgets(line, sizeof(line), spec))
2861 			break;
2862 
2863 		/* Parse the line into tokens. */
2864 		for ( ; ; ) {
2865 			char *token;
2866 
2867 			/* Get token. */
2868 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
2869 			if (!token)
2870 				break;
2871 
2872 			/* Handle comments. */
2873 			if ((token[0] == '#') ||
2874 			    (token[0] == ';') ||
2875 			    ((token[0] == '/') && (token[1] == '/'))) {
2876 				break;
2877 			}
2878 
2879 			/* Handle excessively long lines. */
2880 			if (n_tokens >= RTE_DIM(tokens)) {
2881 				if (err_line)
2882 					*err_line = n_lines;
2883 				if (err_msg)
2884 					*err_msg = "Too many tokens.";
2885 				status = -EINVAL;
2886 				goto error;
2887 			}
2888 
2889 			/* Handle excessively long tokens. */
2890 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2891 			    RTE_SWX_NAME_SIZE) {
2892 				if (err_line)
2893 					*err_line = n_lines;
2894 				if (err_msg)
2895 					*err_msg = "Token too big.";
2896 				status = -EINVAL;
2897 				goto error;
2898 			}
2899 
2900 			/* Save token. */
2901 			tokens[n_tokens] = token;
2902 			n_tokens++;
2903 		}
2904 
2905 		/* Handle empty lines. */
2906 		if (!n_tokens)
2907 			continue;
2908 
2909 		/* struct block. */
2910 		if (block_mask & (1 << STRUCT_BLOCK)) {
2911 			struct struct_spec *new_structs;
2912 
2913 			status = struct_block_parse(&struct_spec,
2914 						    &block_mask,
2915 						    tokens,
2916 						    n_tokens,
2917 						    n_lines,
2918 						    err_line,
2919 						    err_msg);
2920 			if (status)
2921 				goto error;
2922 
2923 			if (block_mask & (1 << STRUCT_BLOCK))
2924 				continue;
2925 
2926 			/* End of block. */
2927 			new_structs = realloc(s->structs,
2928 					      (s->n_structs + 1) * sizeof(struct struct_spec));
2929 			if (!new_structs) {
2930 				if (err_line)
2931 					*err_line = n_lines;
2932 				if (err_msg)
2933 					*err_msg = "Memory allocation failed.";
2934 				status = -ENOMEM;
2935 				goto error;
2936 			}
2937 
2938 			s->structs = new_structs;
2939 			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
2940 			s->n_structs++;
2941 			memset(&struct_spec, 0, sizeof(struct struct_spec));
2942 
2943 			continue;
2944 		}
2945 
2946 		/* action block. */
2947 		if (block_mask & (1 << ACTION_BLOCK)) {
2948 			struct action_spec *new_actions;
2949 
2950 			status = action_block_parse(&action_spec,
2951 						    &block_mask,
2952 						    tokens,
2953 						    n_tokens,
2954 						    n_lines,
2955 						    err_line,
2956 						    err_msg);
2957 			if (status)
2958 				goto error;
2959 
2960 			if (block_mask & (1 << ACTION_BLOCK))
2961 				continue;
2962 
2963 			/* End of block. */
2964 			new_actions = realloc(s->actions,
2965 					      (s->n_actions + 1) * sizeof(struct action_spec));
2966 			if (!new_actions) {
2967 				if (err_line)
2968 					*err_line = n_lines;
2969 				if (err_msg)
2970 					*err_msg = "Memory allocation failed.";
2971 				status = -ENOMEM;
2972 				goto error;
2973 			}
2974 
2975 			s->actions = new_actions;
2976 			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
2977 			s->n_actions++;
2978 			memset(&action_spec, 0, sizeof(struct action_spec));
2979 
2980 			continue;
2981 		}
2982 
2983 		/* table block. */
2984 		if (block_mask & (1 << TABLE_BLOCK)) {
2985 			struct table_spec *new_tables;
2986 
2987 			status = table_block_parse(&table_spec,
2988 						   &block_mask,
2989 						   tokens,
2990 						   n_tokens,
2991 						   n_lines,
2992 						   err_line,
2993 						   err_msg);
2994 			if (status)
2995 				goto error;
2996 
2997 			if (block_mask & (1 << TABLE_BLOCK))
2998 				continue;
2999 
3000 			/* End of block. */
3001 			new_tables = realloc(s->tables,
3002 					     (s->n_tables + 1) * sizeof(struct table_spec));
3003 			if (!new_tables) {
3004 				if (err_line)
3005 					*err_line = n_lines;
3006 				if (err_msg)
3007 					*err_msg = "Memory allocation failed.";
3008 				status = -ENOMEM;
3009 				goto error;
3010 			}
3011 
3012 			s->tables = new_tables;
3013 			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
3014 			s->n_tables++;
3015 			memset(&table_spec, 0, sizeof(struct table_spec));
3016 
3017 			continue;
3018 		}
3019 
3020 		/* selector block. */
3021 		if (block_mask & (1 << SELECTOR_BLOCK)) {
3022 			struct selector_spec *new_selectors;
3023 
3024 			status = selector_block_parse(&selector_spec,
3025 						      &block_mask,
3026 						      tokens,
3027 						      n_tokens,
3028 						      n_lines,
3029 						      err_line,
3030 						      err_msg);
3031 			if (status)
3032 				goto error;
3033 
3034 			if (block_mask & (1 << SELECTOR_BLOCK))
3035 				continue;
3036 
3037 			/* End of block. */
3038 			new_selectors = realloc(s->selectors,
3039 				(s->n_selectors + 1) * sizeof(struct selector_spec));
3040 			if (!new_selectors) {
3041 				if (err_line)
3042 					*err_line = n_lines;
3043 				if (err_msg)
3044 					*err_msg = "Memory allocation failed.";
3045 				status = -ENOMEM;
3046 				goto error;
3047 			}
3048 
3049 			s->selectors = new_selectors;
3050 			memcpy(&s->selectors[s->n_selectors],
3051 			       &selector_spec,
3052 			       sizeof(struct selector_spec));
3053 			s->n_selectors++;
3054 			memset(&selector_spec, 0, sizeof(struct selector_spec));
3055 
3056 			continue;
3057 		}
3058 
3059 		/* learner block. */
3060 		if (block_mask & (1 << LEARNER_BLOCK)) {
3061 			struct learner_spec *new_learners;
3062 
3063 			status = learner_block_parse(&learner_spec,
3064 						     &block_mask,
3065 						     tokens,
3066 						     n_tokens,
3067 						     n_lines,
3068 						     err_line,
3069 						     err_msg);
3070 			if (status)
3071 				goto error;
3072 
3073 			if (block_mask & (1 << LEARNER_BLOCK))
3074 				continue;
3075 
3076 			/* End of block. */
3077 			new_learners = realloc(s->learners,
3078 					       (s->n_learners + 1) * sizeof(struct learner_spec));
3079 			if (!new_learners) {
3080 				if (err_line)
3081 					*err_line = n_lines;
3082 				if (err_msg)
3083 					*err_msg = "Memory allocation failed.";
3084 				status = -ENOMEM;
3085 				goto error;
3086 			}
3087 
3088 			s->learners = new_learners;
3089 			memcpy(&s->learners[s->n_learners],
3090 			       &learner_spec,
3091 			       sizeof(struct learner_spec));
3092 			s->n_learners++;
3093 			memset(&learner_spec, 0, sizeof(struct learner_spec));
3094 
3095 			continue;
3096 		}
3097 
3098 		/* apply block. */
3099 		if (block_mask & (1 << APPLY_BLOCK)) {
3100 			struct apply_spec *new_apply;
3101 
3102 			status = apply_block_parse(&apply_spec,
3103 						   &block_mask,
3104 						   tokens,
3105 						   n_tokens,
3106 						   n_lines,
3107 						   err_line,
3108 						   err_msg);
3109 			if (status)
3110 				goto error;
3111 
3112 			if (block_mask & (1 << APPLY_BLOCK))
3113 				continue;
3114 
3115 			/* End of block. */
3116 			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
3117 			if (!new_apply) {
3118 				if (err_line)
3119 					*err_line = n_lines;
3120 				if (err_msg)
3121 					*err_msg = "Memory allocation failed.";
3122 				status = -ENOMEM;
3123 				goto error;
3124 			}
3125 
3126 			s->apply = new_apply;
3127 			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
3128 			s->n_apply++;
3129 			memset(&apply_spec, 0, sizeof(struct apply_spec));
3130 
3131 			continue;
3132 		}
3133 
3134 		/* extobj. */
3135 		if (!strcmp(tokens[0], "extobj")) {
3136 			struct extobj_spec *new_extobjs;
3137 
3138 			status = extobj_statement_parse(&extobj_spec,
3139 							tokens,
3140 							n_tokens,
3141 							n_lines,
3142 							err_line,
3143 							err_msg);
3144 			if (status)
3145 				goto error;
3146 
3147 			new_extobjs = realloc(s->extobjs,
3148 					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
3149 			if (!new_extobjs) {
3150 				if (err_line)
3151 					*err_line = n_lines;
3152 				if (err_msg)
3153 					*err_msg = "Memory allocation failed.";
3154 				status = -ENOMEM;
3155 				goto error;
3156 			}
3157 
3158 			s->extobjs = new_extobjs;
3159 			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
3160 			s->n_extobjs++;
3161 			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
3162 
3163 			continue;
3164 		}
3165 
3166 		/* struct. */
3167 		if (!strcmp(tokens[0], "struct")) {
3168 			status = struct_statement_parse(&struct_spec,
3169 							&block_mask,
3170 							tokens,
3171 							n_tokens,
3172 							n_lines,
3173 							err_line,
3174 							err_msg);
3175 			if (status)
3176 				goto error;
3177 
3178 			continue;
3179 		}
3180 
3181 		/* header. */
3182 		if (!strcmp(tokens[0], "header")) {
3183 			struct header_spec *new_headers;
3184 
3185 			status = header_statement_parse(&header_spec,
3186 							tokens,
3187 							n_tokens,
3188 							n_lines,
3189 							err_line,
3190 							err_msg);
3191 			if (status)
3192 				goto error;
3193 
3194 			new_headers = realloc(s->headers,
3195 					      (s->n_headers + 1) * sizeof(struct header_spec));
3196 			if (!new_headers) {
3197 				if (err_line)
3198 					*err_line = n_lines;
3199 				if (err_msg)
3200 					*err_msg = "Memory allocation failed.";
3201 				status = -ENOMEM;
3202 				goto error;
3203 			}
3204 
3205 			s->headers = new_headers;
3206 			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
3207 			s->n_headers++;
3208 			memset(&header_spec, 0, sizeof(struct header_spec));
3209 
3210 			continue;
3211 		}
3212 
3213 		/* metadata. */
3214 		if (!strcmp(tokens[0], "metadata")) {
3215 			struct metadata_spec *new_metadata;
3216 
3217 			status = metadata_statement_parse(&metadata_spec,
3218 							  tokens,
3219 							  n_tokens,
3220 							  n_lines,
3221 							  err_line,
3222 							  err_msg);
3223 			if (status)
3224 				goto error;
3225 
3226 			new_metadata = realloc(s->metadata,
3227 					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
3228 			if (!new_metadata) {
3229 				if (err_line)
3230 					*err_line = n_lines;
3231 				if (err_msg)
3232 					*err_msg = "Memory allocation failed.";
3233 				status = -ENOMEM;
3234 				goto error;
3235 			}
3236 
3237 			s->metadata = new_metadata;
3238 			memcpy(&s->metadata[s->n_metadata],
3239 			       &metadata_spec,
3240 			       sizeof(struct metadata_spec));
3241 			s->n_metadata++;
3242 			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
3243 
3244 			continue;
3245 		}
3246 
3247 		/* action. */
3248 		if (!strcmp(tokens[0], "action")) {
3249 			status = action_statement_parse(&action_spec,
3250 							&block_mask,
3251 							tokens,
3252 							n_tokens,
3253 							n_lines,
3254 							err_line,
3255 							err_msg);
3256 			if (status)
3257 				goto error;
3258 
3259 			continue;
3260 		}
3261 
3262 		/* table. */
3263 		if (!strcmp(tokens[0], "table")) {
3264 			status = table_statement_parse(&table_spec,
3265 						       &block_mask,
3266 						       tokens,
3267 						       n_tokens,
3268 						       n_lines,
3269 						       err_line,
3270 						       err_msg);
3271 			if (status)
3272 				goto error;
3273 
3274 			continue;
3275 		}
3276 
3277 		/* selector. */
3278 		if (!strcmp(tokens[0], "selector")) {
3279 			status = selector_statement_parse(&selector_spec,
3280 							  &block_mask,
3281 							  tokens,
3282 							  n_tokens,
3283 							  n_lines,
3284 							  err_line,
3285 							  err_msg);
3286 			if (status)
3287 				goto error;
3288 
3289 			continue;
3290 		}
3291 
3292 		/* learner. */
3293 		if (!strcmp(tokens[0], "learner")) {
3294 			status = learner_statement_parse(&learner_spec,
3295 							 &block_mask,
3296 							 tokens,
3297 							 n_tokens,
3298 							 n_lines,
3299 							 err_line,
3300 							 err_msg);
3301 			if (status)
3302 				goto error;
3303 
3304 			continue;
3305 		}
3306 
3307 		/* regarray. */
3308 		if (!strcmp(tokens[0], "regarray")) {
3309 			struct regarray_spec *new_regarrays;
3310 
3311 			status = regarray_statement_parse(&regarray_spec,
3312 							  tokens,
3313 							  n_tokens,
3314 							  n_lines,
3315 							  err_line,
3316 							  err_msg);
3317 			if (status)
3318 				goto error;
3319 
3320 			new_regarrays = realloc(s->regarrays,
3321 				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
3322 			if (!new_regarrays) {
3323 				if (err_line)
3324 					*err_line = n_lines;
3325 				if (err_msg)
3326 					*err_msg = "Memory allocation failed.";
3327 				status = -ENOMEM;
3328 				goto error;
3329 			}
3330 
3331 			s->regarrays = new_regarrays;
3332 			memcpy(&s->regarrays[s->n_regarrays],
3333 			       &regarray_spec,
3334 			       sizeof(struct regarray_spec));
3335 			s->n_regarrays++;
3336 			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
3337 
3338 			continue;
3339 		}
3340 
3341 		/* metarray. */
3342 		if (!strcmp(tokens[0], "metarray")) {
3343 			struct metarray_spec *new_metarrays;
3344 
3345 			status = metarray_statement_parse(&metarray_spec,
3346 							  tokens,
3347 							  n_tokens,
3348 							  n_lines,
3349 							  err_line,
3350 							  err_msg);
3351 			if (status)
3352 				goto error;
3353 
3354 			new_metarrays = realloc(s->metarrays,
3355 				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
3356 			if (!new_metarrays) {
3357 				if (err_line)
3358 					*err_line = n_lines;
3359 				if (err_msg)
3360 					*err_msg = "Memory allocation failed.";
3361 				status = -ENOMEM;
3362 				goto error;
3363 			}
3364 
3365 			s->metarrays = new_metarrays;
3366 			memcpy(&s->metarrays[s->n_metarrays],
3367 			       &metarray_spec,
3368 			       sizeof(struct metarray_spec));
3369 			s->n_metarrays++;
3370 			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
3371 
3372 			continue;
3373 		}
3374 
3375 		/* apply. */
3376 		if (!strcmp(tokens[0], "apply")) {
3377 			status = apply_statement_parse(&block_mask,
3378 						       tokens,
3379 						       n_tokens,
3380 						       n_lines,
3381 						       err_line,
3382 						       err_msg);
3383 			if (status)
3384 				goto error;
3385 
3386 			continue;
3387 		}
3388 
3389 		/* Anything else. */
3390 		if (err_line)
3391 			*err_line = n_lines;
3392 		if (err_msg)
3393 			*err_msg = "Unknown statement.";
3394 		status = -EINVAL;
3395 		goto error;
3396 	}
3397 
3398 	/* Handle unfinished block. */
3399 	if (block_mask) {
3400 		if (err_line)
3401 			*err_line = n_lines;
3402 		if (err_msg)
3403 			*err_msg = "Missing }.";
3404 		status = -EINVAL;
3405 		goto error;
3406 	}
3407 
3408 	return s;
3409 
3410 error:
3411 	extobj_spec_free(&extobj_spec);
3412 	struct_spec_free(&struct_spec);
3413 	header_spec_free(&header_spec);
3414 	metadata_spec_free(&metadata_spec);
3415 	action_spec_free(&action_spec);
3416 	table_spec_free(&table_spec);
3417 	selector_spec_free(&selector_spec);
3418 	learner_spec_free(&learner_spec);
3419 	regarray_spec_free(&regarray_spec);
3420 	metarray_spec_free(&metarray_spec);
3421 	apply_spec_free(&apply_spec);
3422 	pipeline_spec_free(s);
3423 
3424 	return NULL;
3425 }
3426 
3427 int
3428 pipeline_spec_configure(struct rte_swx_pipeline *p,
3429 			struct pipeline_spec *s,
3430 			const char **err_msg)
3431 {
3432 	uint32_t i;
3433 	int status = 0;
3434 
3435 	/* extobj. */
3436 	for (i = 0; i < s->n_extobjs; i++) {
3437 		struct extobj_spec *extobj_spec = &s->extobjs[i];
3438 
3439 		status = rte_swx_pipeline_extern_object_config(p,
3440 			extobj_spec->name,
3441 			extobj_spec->extern_type_name,
3442 			extobj_spec->pragma);
3443 		if (status) {
3444 			if (err_msg)
3445 				*err_msg = "Extern object configuration error.";
3446 			return status;
3447 		}
3448 	}
3449 
3450 	/* regarray. */
3451 	for (i = 0; i < s->n_regarrays; i++) {
3452 		struct regarray_spec *regarray_spec = &s->regarrays[i];
3453 
3454 		status = rte_swx_pipeline_regarray_config(p,
3455 			regarray_spec->name,
3456 			regarray_spec->size,
3457 			regarray_spec->init_val);
3458 		if (status) {
3459 			if (err_msg)
3460 				*err_msg = "Register array configuration error.";
3461 			return status;
3462 		}
3463 	}
3464 
3465 	/* metarray. */
3466 	for (i = 0; i < s->n_metarrays; i++) {
3467 		struct metarray_spec *metarray_spec = &s->metarrays[i];
3468 
3469 		status = rte_swx_pipeline_metarray_config(p,
3470 			metarray_spec->name,
3471 			metarray_spec->size);
3472 		if (status) {
3473 			if (err_msg)
3474 				*err_msg = "Meter array configuration error.";
3475 			return status;
3476 		}
3477 	}
3478 
3479 	/* struct. */
3480 	for (i = 0; i < s->n_structs; i++) {
3481 		struct struct_spec *struct_spec = &s->structs[i];
3482 
3483 		status = rte_swx_pipeline_struct_type_register(p,
3484 			struct_spec->name,
3485 			struct_spec->fields,
3486 			struct_spec->n_fields,
3487 			struct_spec->varbit);
3488 		if (status) {
3489 			if (err_msg)
3490 				*err_msg = "Struct type registration error.";
3491 			return status;
3492 		}
3493 	}
3494 
3495 	/* header. */
3496 	for (i = 0; i < s->n_headers; i++) {
3497 		struct header_spec *header_spec = &s->headers[i];
3498 
3499 		status = rte_swx_pipeline_packet_header_register(p,
3500 			header_spec->name,
3501 			header_spec->struct_type_name);
3502 		if (status) {
3503 			if (err_msg)
3504 				*err_msg = "Header configuration error.";
3505 			return status;
3506 		}
3507 	}
3508 
3509 	/* metadata. */
3510 	for (i = 0; i < s->n_metadata; i++) {
3511 		struct metadata_spec *metadata_spec = &s->metadata[i];
3512 
3513 		status = rte_swx_pipeline_packet_metadata_register(p,
3514 			metadata_spec->struct_type_name);
3515 		if (status) {
3516 			if (err_msg)
3517 				*err_msg = "Meta-data registration error.";
3518 			return status;
3519 		}
3520 	}
3521 
3522 	/* action. */
3523 	for (i = 0; i < s->n_actions; i++) {
3524 		struct action_spec *action_spec = &s->actions[i];
3525 
3526 		status = rte_swx_pipeline_action_config(p,
3527 			action_spec->name,
3528 			action_spec->args_struct_type_name,
3529 			action_spec->instructions,
3530 			action_spec->n_instructions);
3531 		if (status) {
3532 			if (err_msg)
3533 				*err_msg = "Action configuration error.";
3534 			return status;
3535 		}
3536 	}
3537 
3538 	/* table. */
3539 	for (i = 0; i < s->n_tables; i++) {
3540 		struct table_spec *table_spec = &s->tables[i];
3541 
3542 		status = rte_swx_pipeline_table_config(p,
3543 			table_spec->name,
3544 			&table_spec->params,
3545 			table_spec->recommended_table_type_name,
3546 			table_spec->args,
3547 			table_spec->size);
3548 		if (status) {
3549 			if (err_msg)
3550 				*err_msg = "Table configuration error.";
3551 			return status;
3552 		}
3553 	}
3554 
3555 	/* selector. */
3556 	for (i = 0; i < s->n_selectors; i++) {
3557 		struct selector_spec *selector_spec = &s->selectors[i];
3558 
3559 		status = rte_swx_pipeline_selector_config(p,
3560 			selector_spec->name,
3561 			&selector_spec->params);
3562 		if (status) {
3563 			if (err_msg)
3564 				*err_msg = "Selector table configuration error.";
3565 			return status;
3566 		}
3567 	}
3568 
3569 	/* learner. */
3570 	for (i = 0; i < s->n_learners; i++) {
3571 		struct learner_spec *learner_spec = &s->learners[i];
3572 
3573 		status = rte_swx_pipeline_learner_config(p,
3574 			learner_spec->name,
3575 			&learner_spec->params,
3576 			learner_spec->size,
3577 			learner_spec->timeout,
3578 			learner_spec->n_timeouts);
3579 		if (status) {
3580 			if (err_msg)
3581 				*err_msg = "Learner table configuration error.";
3582 			return status;
3583 		}
3584 	}
3585 
3586 	/* apply. */
3587 	for (i = 0; i < s->n_apply; i++) {
3588 		struct apply_spec *apply_spec = &s->apply[i];
3589 
3590 		status = rte_swx_pipeline_instructions_config(p,
3591 			apply_spec->instructions,
3592 			apply_spec->n_instructions);
3593 		if (status) {
3594 			if (err_msg)
3595 				*err_msg = "Pipeline instructions configuration error.";
3596 			return status;
3597 		}
3598 	}
3599 
3600 	return 0;
3601 }
3602 
3603 static void
3604 port_in_params_free(void *params, const char *port_type)
3605 {
3606 	uintptr_t dev_name;
3607 
3608 	if (!params || !port_type)
3609 		return;
3610 
3611 	if (!strcmp(port_type, "ethdev")) {
3612 		struct rte_swx_port_ethdev_reader_params *p = params;
3613 
3614 		dev_name = (uintptr_t)p->dev_name;
3615 	} else if (!strcmp(port_type, "ring")) {
3616 		struct rte_swx_port_ring_reader_params *p = params;
3617 
3618 		dev_name = (uintptr_t)p->name;
3619 	} else if (!strcmp(port_type, "source")) {
3620 		struct rte_swx_port_source_params *p = params;
3621 
3622 		dev_name = (uintptr_t)p->file_name;
3623 	} else
3624 		dev_name = (uintptr_t)NULL;
3625 
3626 	free((void *)dev_name);
3627 	free(params);
3628 }
3629 
3630 static void
3631 port_out_params_free(void *params, const char *port_type)
3632 {
3633 	uintptr_t dev_name;
3634 
3635 	if (!params || !port_type)
3636 		return;
3637 
3638 	if (!strcmp(port_type, "ethdev")) {
3639 		struct rte_swx_port_ethdev_writer_params *p = params;
3640 
3641 		dev_name = (uintptr_t)p->dev_name;
3642 	} else if (!strcmp(port_type, "ring")) {
3643 		struct rte_swx_port_ring_writer_params *p = params;
3644 
3645 		dev_name = (uintptr_t)p->name;
3646 	} else if (!strcmp(port_type, "sink")) {
3647 		struct rte_swx_port_sink_params *p = params;
3648 
3649 		dev_name = (uintptr_t)p->file_name;
3650 	} else
3651 		dev_name = (uintptr_t)NULL;
3652 
3653 	free((void *)dev_name);
3654 	free(params);
3655 }
3656 
3657 void
3658 pipeline_iospec_free(struct pipeline_iospec *s)
3659 {
3660 	uint32_t i;
3661 
3662 	if (!s)
3663 		return;
3664 
3665 	/* Input ports. */
3666 	for (i = 0; i < s->n_ports_in; i++) {
3667 		uintptr_t name = (uintptr_t)s->port_in_type[i];
3668 
3669 		port_in_params_free(s->port_in_params[i], s->port_in_type[i]);
3670 		free((void *)name);
3671 	}
3672 
3673 	free(s->port_in_type);
3674 	free(s->port_in_params);
3675 
3676 	/* Output ports. */
3677 	for (i = 0; i < s->n_ports_out; i++) {
3678 		uintptr_t name = (uintptr_t)s->port_out_type[i];
3679 
3680 		port_out_params_free(s->port_out_params[i], s->port_out_type[i]);
3681 		free((void *)name);
3682 	}
3683 
3684 	free(s->port_out_type);
3685 	free(s->port_out_params);
3686 
3687 	free(s);
3688 }
3689 
3690 static int
3691 mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,
3692 		char **tokens,
3693 		uint32_t n_tokens,
3694 		const char **err_msg)
3695 {
3696 	char *token;
3697 
3698 	if ((n_tokens != 4) || strcmp(tokens[0], "slots") || strcmp(tokens[2], "sessions")) {
3699 		if (err_msg)
3700 			*err_msg = "Invalid statement.";
3701 		return -EINVAL;
3702 	}
3703 
3704 	/* <n_slots>. */
3705 	token = tokens[1];
3706 	p->n_slots = strtoul(token, &token, 0);
3707 	if (token[0]) {
3708 		if (err_msg)
3709 			*err_msg = "Invalid <n_slots> parameter.";
3710 		return -EINVAL;
3711 	}
3712 
3713 	/* <n_sessions>. */
3714 	token = tokens[3];
3715 	p->n_sessions = strtoul(token, &token, 0);
3716 	if (token[0]) {
3717 		if (err_msg)
3718 			*err_msg = "Invalid <n_sessions> parameter.";
3719 		return -EINVAL;
3720 	}
3721 
3722 	return 0;
3723 }
3724 
3725 static void *
3726 port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3727 {
3728 	struct rte_swx_port_ethdev_reader_params *p = NULL;
3729 	char *token, *dev_name = NULL;
3730 	uint32_t queue_id, burst_size;
3731 
3732 	if ((n_tokens != 5) || strcmp(tokens[1], "rxq") || strcmp(tokens[3], "bsz")) {
3733 		if (err_msg)
3734 			*err_msg = "Invalid statement.";
3735 		return NULL;
3736 	}
3737 
3738 	/* <queue_id>. */
3739 	token = tokens[2];
3740 	queue_id = strtoul(token, &token, 0);
3741 	if (token[0]) {
3742 		if (err_msg)
3743 			*err_msg = "Invalid <queue_id> parameter.";
3744 		return NULL;
3745 	}
3746 
3747 	/* <burst_size>. */
3748 	token = tokens[4];
3749 	burst_size = strtoul(token, &token, 0);
3750 	if (token[0]) {
3751 		if (err_msg)
3752 			*err_msg = "Invalid <burst_size> parameter.";
3753 		return NULL;
3754 	}
3755 
3756 	/* Memory allocation. */
3757 	dev_name = strdup(tokens[0]);
3758 	p = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));
3759 	if (!dev_name || !p) {
3760 		free(dev_name);
3761 		free(p);
3762 
3763 		if (err_msg)
3764 			*err_msg = "Memory allocation failed.";
3765 		return NULL;
3766 	}
3767 
3768 	/* Initialization. */
3769 	p->dev_name = dev_name;
3770 	p->queue_id = queue_id;
3771 	p->burst_size = burst_size;
3772 
3773 	return p;
3774 }
3775 
3776 static void *
3777 port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3778 {
3779 	struct rte_swx_port_ring_reader_params *p = NULL;
3780 	char *token, *name = NULL;
3781 	uint32_t burst_size;
3782 
3783 	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
3784 		if (err_msg)
3785 			*err_msg = "Invalid statement.";
3786 		return NULL;
3787 	}
3788 
3789 	/* <burst_size>. */
3790 	token = tokens[2];
3791 	burst_size = strtoul(token, &token, 0);
3792 	if (token[0]) {
3793 		if (err_msg)
3794 			*err_msg = "Invalid <burst_size> parameter.";
3795 		return NULL;
3796 	}
3797 
3798 	/* Memory allocation. */
3799 	name = strdup(tokens[0]);
3800 	p = malloc(sizeof(struct rte_swx_port_ring_reader_params));
3801 	if (!name || !p) {
3802 		free(name);
3803 		free(p);
3804 
3805 		if (err_msg)
3806 			*err_msg = "Memory allocation failed.";
3807 		return NULL;
3808 	}
3809 
3810 	/* Initialization. */
3811 	p->name = name;
3812 	p->burst_size = burst_size;
3813 
3814 	return p;
3815 }
3816 
3817 static void *
3818 port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3819 {
3820 	struct rte_swx_port_source_params *p = NULL;
3821 	struct rte_mempool *pool = NULL;
3822 	char *token, *file_name = NULL;
3823 	uint32_t n_loops, n_pkts_max;
3824 
3825 	if ((n_tokens != 8) ||
3826 	    strcmp(tokens[0], "mempool") ||
3827 	    strcmp(tokens[2], "file") ||
3828 	    strcmp(tokens[4], "loop") ||
3829 	    strcmp(tokens[6], "packets")) {
3830 		if (err_msg)
3831 			*err_msg = "Invalid statement.";
3832 		return NULL;
3833 	}
3834 
3835 	/* <mempool_name>. */
3836 	pool = rte_mempool_lookup(tokens[1]);
3837 	if (!pool) {
3838 		if (err_msg)
3839 			*err_msg = "Invalid <mempool_name> parameter.";
3840 		return NULL;
3841 	}
3842 
3843 	/* <n_loops>. */
3844 	token = tokens[5];
3845 	n_loops = strtoul(token, &token, 0);
3846 	if (token[0]) {
3847 		if (err_msg)
3848 			*err_msg = "Invalid <n_loops> parameter.";
3849 		return NULL;
3850 	}
3851 
3852 	/* <n_pkts_max>. */
3853 	token = tokens[7];
3854 	n_pkts_max = strtoul(token, &token, 0);
3855 	if (token[0]) {
3856 		if (err_msg)
3857 			*err_msg = "Invalid <n_pkts_max> parameter.";
3858 		return NULL;
3859 	}
3860 
3861 	/* Memory allocation. */
3862 	file_name = strdup(tokens[3]);
3863 	p = malloc(sizeof(struct rte_swx_port_source_params));
3864 	if (!file_name || !p) {
3865 		free(file_name);
3866 		free(p);
3867 
3868 		if (err_msg)
3869 			*err_msg = "Memory allocation failed.";
3870 		return NULL;
3871 	}
3872 
3873 	/* Initialization. */
3874 	p->pool = pool;
3875 	p->file_name = file_name;
3876 	p->n_loops = n_loops;
3877 	p->n_pkts_max = n_pkts_max;
3878 
3879 	return p;
3880 }
3881 
3882 static void *
3883 port_in_fd_parse(char **tokens,
3884 		 uint32_t n_tokens,
3885 		 const char **err_msg)
3886 {
3887 	struct rte_swx_port_fd_reader_params *p = NULL;
3888 	struct rte_mempool *mempool = NULL;
3889 	char *token;
3890 	uint32_t mtu, burst_size;
3891 	int fd;
3892 
3893 	if ((n_tokens != 7) ||
3894 	    strcmp(tokens[1], "mtu") ||
3895 	    strcmp(tokens[3], "mempool") ||
3896 	    strcmp(tokens[5], "bsz")) {
3897 		if (err_msg)
3898 			*err_msg = "Invalid statement.";
3899 		return NULL;
3900 	}
3901 
3902 	/* <file_descriptor>. */
3903 	token = tokens[0];
3904 	fd = strtol(token, &token, 0);
3905 	if (token[0]) {
3906 		if (err_msg)
3907 			*err_msg = "Invalid <file_descriptor> parameter.";
3908 		return NULL;
3909 	}
3910 
3911 	/* <mtu>. */
3912 	token = tokens[2];
3913 	mtu = strtoul(token, &token, 0);
3914 	if (token[0]) {
3915 		if (err_msg)
3916 			*err_msg = "Invalid <mtu> parameter.";
3917 		return NULL;
3918 	}
3919 
3920 	/* <mempool_name>. */
3921 	mempool = rte_mempool_lookup(tokens[4]);
3922 	if (!mempool) {
3923 		if (err_msg)
3924 			*err_msg = "Invalid <mempool_name> parameter.";
3925 		return NULL;
3926 	}
3927 
3928 	/* <burst_size>. */
3929 	token = tokens[6];
3930 	burst_size = strtoul(token, &token, 0);
3931 	if (token[0]) {
3932 		if (err_msg)
3933 			*err_msg = "Invalid <burst_size> parameter.";
3934 		return NULL;
3935 	}
3936 
3937 	/* Memory allocation. */
3938 	p = malloc(sizeof(struct rte_swx_port_fd_reader_params));
3939 	if (!p) {
3940 		if (err_msg)
3941 			*err_msg = "Memory allocation failed.";
3942 		return NULL;
3943 	}
3944 
3945 	/* Initialization. */
3946 	p->fd = fd;
3947 	p->mtu = mtu;
3948 	p->mempool = mempool;
3949 	p->burst_size = burst_size;
3950 
3951 	return p;
3952 }
3953 
3954 static void *
3955 port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
3956 {
3957 	struct rte_swx_port_ethdev_writer_params *p = NULL;
3958 	char *token, *dev_name = NULL;
3959 	uint32_t queue_id, burst_size;
3960 
3961 	if ((n_tokens != 5) || strcmp(tokens[1], "txq") || strcmp(tokens[3], "bsz")) {
3962 		if (err_msg)
3963 			*err_msg = "Invalid statement.";
3964 		return NULL;
3965 	}
3966 
3967 	/* <queue_id>. */
3968 	token = tokens[2];
3969 	queue_id = strtoul(token, &token, 0);
3970 	if (token[0]) {
3971 		if (err_msg)
3972 			*err_msg = "Invalid <queue_id> parameter.";
3973 		return NULL;
3974 	}
3975 
3976 	/* <burst_size>. */
3977 	token = tokens[4];
3978 	burst_size = strtoul(token, &token, 0);
3979 	if (token[0]) {
3980 		if (err_msg)
3981 			*err_msg = "Invalid <burst_size> parameter.";
3982 		return NULL;
3983 	}
3984 
3985 	/* Memory allocation. */
3986 	dev_name = strdup(tokens[0]);
3987 	p = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));
3988 	if (!dev_name || !p) {
3989 		free(dev_name);
3990 		free(p);
3991 
3992 		if (err_msg)
3993 			*err_msg = "Memory allocation failed.";
3994 		return NULL;
3995 	}
3996 
3997 	/* Initialization. */
3998 	p->dev_name = dev_name;
3999 	p->queue_id = queue_id;
4000 	p->burst_size = burst_size;
4001 
4002 	return p;
4003 }
4004 
4005 static void *
4006 port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
4007 {
4008 	struct rte_swx_port_ring_writer_params *p = NULL;
4009 	char *token, *name = NULL;
4010 	uint32_t burst_size;
4011 
4012 	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
4013 		if (err_msg)
4014 			*err_msg = "Invalid statement.";
4015 		return NULL;
4016 	}
4017 
4018 	/* <burst_size>. */
4019 	token = tokens[2];
4020 	burst_size = strtoul(token, &token, 0);
4021 	if (token[0]) {
4022 		if (err_msg)
4023 			*err_msg = "Invalid <burst_size> parameter.";
4024 		return NULL;
4025 	}
4026 
4027 	/* Memory allocation. */
4028 	name = strdup(tokens[0]);
4029 	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
4030 	if (!name || !p) {
4031 		free(name);
4032 		free(p);
4033 
4034 		if (err_msg)
4035 			*err_msg = "Memory allocation failed.";
4036 		return NULL;
4037 	}
4038 
4039 	/* Initialization. */
4040 	p->name = name;
4041 	p->burst_size = burst_size;
4042 
4043 	return p;
4044 }
4045 
4046 static void *
4047 port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
4048 {
4049 	struct rte_swx_port_sink_params *p = NULL;
4050 	char *file_name = NULL;
4051 	int file_name_valid = 0;
4052 
4053 	if ((n_tokens != 2) || strcmp(tokens[0], "file")) {
4054 		if (err_msg)
4055 			*err_msg = "Invalid statement.";
4056 		return NULL;
4057 	}
4058 
4059 	/* Memory allocation. */
4060 	if (strcmp(tokens[1], "none")) {
4061 		file_name_valid = 1;
4062 		file_name = strdup(tokens[1]);
4063 	}
4064 
4065 	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
4066 	if ((file_name_valid && !file_name) || !p) {
4067 		free(file_name);
4068 		free(p);
4069 
4070 		if (err_msg)
4071 			*err_msg = "Memory allocation failed.";
4072 		return NULL;
4073 	}
4074 
4075 	/* Initialization. */
4076 	p->file_name = file_name;
4077 
4078 	return p;
4079 }
4080 
4081 static void *
4082 port_out_fd_parse(char **tokens,
4083 		  uint32_t n_tokens,
4084 		  const char **err_msg)
4085 {
4086 	struct rte_swx_port_fd_writer_params *p = NULL;
4087 	char *token;
4088 	uint32_t burst_size;
4089 	int fd;
4090 
4091 	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
4092 		if (err_msg)
4093 			*err_msg = "Invalid statement.";
4094 		return NULL;
4095 	}
4096 
4097 	/* <file_descriptor>. */
4098 	token = tokens[0];
4099 	fd = strtol(token, &token, 0);
4100 	if (token[0]) {
4101 		if (err_msg)
4102 			*err_msg = "Invalid <file_descriptor> parameter.";
4103 		return NULL;
4104 	}
4105 
4106 	/* <burst_size>. */
4107 	token = tokens[2];
4108 	burst_size = strtoul(token, &token, 0);
4109 	if (token[0]) {
4110 		if (err_msg)
4111 			*err_msg = "Invalid <burst_size> parameter.";
4112 		return NULL;
4113 	}
4114 
4115 	/* Memory allocation. */
4116 	p = malloc(sizeof(struct rte_swx_port_fd_writer_params));
4117 	if (!p) {
4118 		if (err_msg)
4119 			*err_msg = "Memory allocation failed.";
4120 		return NULL;
4121 	}
4122 
4123 	/* Initialization. */
4124 	p->fd = fd;
4125 	p->burst_size = burst_size;
4126 
4127 	return p;
4128 }
4129 
4130 struct pipeline_iospec *
4131 pipeline_iospec_parse(FILE *spec,
4132 		      uint32_t *err_line,
4133 		      const char **err_msg)
4134 {
4135 	struct pipeline_iospec *s = NULL;
4136 	uint32_t n_lines = 0;
4137 
4138 	/* Check the input arguments. */
4139 	if (!spec) {
4140 		if (err_line)
4141 			*err_line = n_lines;
4142 		if (err_msg)
4143 			*err_msg = "Invalid input argument.";
4144 		goto error;
4145 	}
4146 
4147 	/* Memory allocation. */
4148 	s = calloc(sizeof(struct pipeline_iospec), 1);
4149 	if (!s) {
4150 		if (err_line)
4151 			*err_line = n_lines;
4152 		if (err_msg)
4153 			*err_msg = "Memory allocation failed.";
4154 		goto error;
4155 	}
4156 
4157 	/* Initialize with the default values. */
4158 	s->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;
4159 	s->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;
4160 
4161 	for (n_lines = 1; ; n_lines++) {
4162 		char line[MAX_LINE_LENGTH];
4163 		char *tokens[MAX_TOKENS], *ptr = line;
4164 		uint32_t n_tokens = 0;
4165 
4166 		/* Read next line. */
4167 		if (!fgets(line, sizeof(line), spec))
4168 			break;
4169 
4170 		/* Parse the line into tokens. */
4171 		for ( ; ; ) {
4172 			char *token;
4173 
4174 			/* Get token. */
4175 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
4176 			if (!token)
4177 				break;
4178 
4179 			/* Handle comments. */
4180 			if ((token[0] == '#') ||
4181 			    (token[0] == ';') ||
4182 			    ((token[0] == '/') && (token[1] == '/'))) {
4183 				break;
4184 			}
4185 
4186 			/* Handle excessively long lines. */
4187 			if (n_tokens >= RTE_DIM(tokens)) {
4188 				if (err_line)
4189 					*err_line = n_lines;
4190 				if (err_msg)
4191 					*err_msg = "Too many tokens.";
4192 				goto error;
4193 			}
4194 
4195 			/* Handle excessively long tokens. */
4196 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
4197 			    RTE_SWX_NAME_SIZE) {
4198 				if (err_line)
4199 					*err_line = n_lines;
4200 				if (err_msg)
4201 					*err_msg = "Token too big.";
4202 				goto error;
4203 			}
4204 
4205 			/* Save token. */
4206 			tokens[n_tokens] = token;
4207 			n_tokens++;
4208 		}
4209 
4210 		/* Handle empty lines. */
4211 		if (!n_tokens)
4212 			continue;
4213 
4214 		/* mirroring. */
4215 		if ((n_tokens >= 1) && !strcmp(tokens[0], "mirroring")) {
4216 			int status = 0;
4217 
4218 			status = mirroring_parse(&s->mirroring_params,
4219 						 &tokens[1],
4220 						 n_tokens - 1,
4221 						 err_msg);
4222 			if (status) {
4223 				if (err_line)
4224 					*err_line = n_lines;
4225 				goto error;
4226 			}
4227 
4228 			continue;
4229 		}
4230 
4231 		/* port in. */
4232 		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "in")) {
4233 			char *token = tokens[2];
4234 			uint32_t *new_id = NULL;
4235 			const char **new_type = NULL, *port_type = NULL;
4236 			void **new_params = NULL, *p = NULL;
4237 			uint32_t port_id;
4238 
4239 			/* <port_id>. */
4240 			port_id = strtoul(token, &token, 0);
4241 			if (token[0]) {
4242 				if (err_line)
4243 					*err_line = n_lines;
4244 				if (err_msg)
4245 					*err_msg = "Invalid port ID.";
4246 				goto error;
4247 			}
4248 
4249 			/* <port_type>. */
4250 			if (!strcmp(tokens[3], "ethdev"))
4251 				p = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
4252 			else if (!strcmp(tokens[3], "ring"))
4253 				p = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);
4254 			else if (!strcmp(tokens[3], "source"))
4255 				p = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);
4256 			else if (!strcmp(tokens[3], "fd"))
4257 				p = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);
4258 			else {
4259 				p = NULL;
4260 				if (err_msg)
4261 					*err_msg = "Invalid port type.";
4262 			}
4263 
4264 			if (!p) {
4265 				if (err_line)
4266 					*err_line = n_lines;
4267 				goto error;
4268 			}
4269 
4270 			/* New port. */
4271 			port_type = strdup(tokens[3]);
4272 			new_id = realloc(s->port_in_id,
4273 					 (s->n_ports_in + 1) * sizeof(uint32_t));
4274 			new_type = realloc(s->port_in_type,
4275 					   (s->n_ports_in + 1) * sizeof(char *));
4276 			new_params = realloc(s->port_in_params,
4277 					     (s->n_ports_in + 1) * sizeof(void *));
4278 			if (!port_type || !new_id || !new_type || !new_params) {
4279 				uintptr_t pt = (uintptr_t)port_type;
4280 
4281 				port_in_params_free(p, tokens[3]);
4282 				free((void *)pt);
4283 				free(new_id);
4284 				free(new_type);
4285 				free(new_params);
4286 
4287 				if (err_line)
4288 					*err_line = n_lines;
4289 				if (err_msg)
4290 					*err_msg = "Memory allocation failed.";
4291 				goto error;
4292 			}
4293 
4294 			s->port_in_id = new_id;
4295 			s->port_in_type = new_type;
4296 			s->port_in_params = new_params;
4297 
4298 			s->port_in_id[s->n_ports_in] = port_id;
4299 			s->port_in_type[s->n_ports_in] = port_type;
4300 			s->port_in_params[s->n_ports_in] = p;
4301 			s->n_ports_in++;
4302 
4303 			continue;
4304 		}
4305 
4306 		/* port out. */
4307 		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "out")) {
4308 			char *token = tokens[2];
4309 			uint32_t *new_id = NULL;
4310 			const char **new_type = NULL, *port_type = NULL;
4311 			void **new_params = NULL, *p = NULL;
4312 			uint32_t port_id;
4313 
4314 			/* <port_id>. */
4315 			port_id = strtoul(token, &token, 0);
4316 			if (token[0]) {
4317 				if (err_line)
4318 					*err_line = n_lines;
4319 				if (err_msg)
4320 					*err_msg = "Invalid port ID.";
4321 				goto error;
4322 			}
4323 
4324 			/* <port_type>. */
4325 			if (!strcmp(tokens[3], "ethdev"))
4326 				p = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
4327 			else if (!strcmp(tokens[3], "ring"))
4328 				p = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);
4329 			else if (!strcmp(tokens[3], "sink"))
4330 				p = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);
4331 			else if (!strcmp(tokens[3], "fd"))
4332 				p = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);
4333 			else {
4334 				p = NULL;
4335 				if (err_msg)
4336 					*err_msg = "Invalid port type.";
4337 			}
4338 
4339 			if (!p) {
4340 				if (err_line)
4341 					*err_line = n_lines;
4342 				goto error;
4343 			}
4344 
4345 			/* New port. */
4346 			port_type = strdup(tokens[3]);
4347 			new_id = realloc(s->port_out_id,
4348 					 (s->n_ports_out + 1) * sizeof(uint32_t));
4349 			new_type = realloc(s->port_out_type,
4350 					   (s->n_ports_out + 1) * sizeof(char *));
4351 			new_params = realloc(s->port_out_params,
4352 					     (s->n_ports_out + 1) * sizeof(void *));
4353 			if (!port_type || !new_id || !new_type || !new_params) {
4354 				uintptr_t pt = (uintptr_t)port_type;
4355 
4356 				port_out_params_free(p, tokens[3]);
4357 				free((void *)pt);
4358 				free(new_id);
4359 				free(new_type);
4360 				free(new_params);
4361 
4362 				if (err_line)
4363 					*err_line = n_lines;
4364 				if (err_msg)
4365 					*err_msg = "Memory allocation failed.";
4366 				goto error;
4367 			}
4368 
4369 			s->port_out_id = new_id;
4370 			s->port_out_type = new_type;
4371 			s->port_out_params = new_params;
4372 
4373 			s->port_out_id[s->n_ports_out] = port_id;
4374 			s->port_out_type[s->n_ports_out] = port_type;
4375 			s->port_out_params[s->n_ports_out] = p;
4376 			s->n_ports_out++;
4377 
4378 			continue;
4379 		}
4380 
4381 		/* Anything else. */
4382 		if (err_line)
4383 			*err_line = n_lines;
4384 		if (err_msg)
4385 			*err_msg = "Unknown I/O statement.";
4386 		goto error;
4387 	}
4388 
4389 	return s;
4390 
4391 error:
4392 	pipeline_iospec_free(s);
4393 
4394 	return NULL;
4395 }
4396 
4397 int
4398 pipeline_iospec_configure(struct rte_swx_pipeline *p,
4399 			  struct pipeline_iospec *s,
4400 			  const char **err_msg)
4401 {
4402 	uint32_t i;
4403 	int status = 0;
4404 
4405 	/* Check input arguments. */
4406 	if (!p || !s) {
4407 		if (err_msg)
4408 			*err_msg = "Invalid input argument";
4409 		return -EINVAL;
4410 	}
4411 
4412 	/* Mirroring. */
4413 	status = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);
4414 	if (status) {
4415 		if (err_msg)
4416 			*err_msg = "Pipeline mirroring configuration error.";
4417 		return status;
4418 	}
4419 
4420 	/* Input ports. */
4421 	for (i = 0; i < s->n_ports_in; i++) {
4422 		status = rte_swx_pipeline_port_in_config(p,
4423 							 i,
4424 							 s->port_in_type[i],
4425 							 s->port_in_params[i]);
4426 		if (status) {
4427 			if (err_msg)
4428 				*err_msg = "Pipeline input port configuration error.";
4429 			return status;
4430 		}
4431 	}
4432 
4433 	/* Output ports. */
4434 	for (i = 0; i < s->n_ports_out; i++) {
4435 		status = rte_swx_pipeline_port_out_config(p,
4436 							  i,
4437 							  s->port_out_type[i],
4438 							  s->port_out_params[i]);
4439 		if (status) {
4440 			if (err_msg)
4441 				*err_msg = "Pipeline output port configuration error.";
4442 			return status;
4443 		}
4444 	}
4445 
4446 	return 0;
4447 }
4448