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