xref: /dpdk/lib/pipeline/rte_swx_pipeline_spec.c (revision a2258ea1beaac8f162fd38911a2d6691366dcd66)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
9 
10 #include "rte_swx_pipeline.h"
11 #include "rte_swx_ctl.h"
12 
13 #define MAX_LINE_LENGTH RTE_SWX_INSTRUCTION_SIZE
14 #define MAX_TOKENS RTE_SWX_INSTRUCTION_TOKENS_MAX
15 
16 #define STRUCT_BLOCK 0
17 #define ACTION_BLOCK 1
18 #define TABLE_BLOCK 2
19 #define TABLE_KEY_BLOCK 3
20 #define TABLE_ACTIONS_BLOCK 4
21 #define APPLY_BLOCK 5
22 
23 /*
24  * extobj.
25  *
26  * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
27  */
28 struct extobj_spec {
29 	char *name;
30 	char *extern_type_name;
31 	char *pragma;
32 };
33 
34 static void
35 extobj_spec_free(struct extobj_spec *s)
36 {
37 	if (!s)
38 		return;
39 
40 	free(s->name);
41 	s->name = NULL;
42 
43 	free(s->extern_type_name);
44 	s->extern_type_name = NULL;
45 
46 	free(s->pragma);
47 	s->pragma = NULL;
48 }
49 
50 static int
51 extobj_statement_parse(struct extobj_spec *s,
52 		       char **tokens,
53 		       uint32_t n_tokens,
54 		       uint32_t n_lines,
55 		       uint32_t *err_line,
56 		       const char **err_msg)
57 {
58 	/* Check format. */
59 	if (((n_tokens != 4) && (n_tokens != 6)) ||
60 	    ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
61 	    ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
62 				 strcmp(tokens[4], "pragma")))) {
63 		if (err_line)
64 			*err_line = n_lines;
65 		if (err_msg)
66 			*err_msg = "Invalid extobj statement.";
67 		return -EINVAL;
68 	}
69 
70 	/* spec. */
71 	s->name = strdup(tokens[1]);
72 	s->extern_type_name = strdup(tokens[3]);
73 	s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
74 
75 	if (!s->name ||
76 	    !s->extern_type_name ||
77 	    ((n_tokens == 6) && !s->pragma)) {
78 		free(s->name);
79 		free(s->extern_type_name);
80 		free(s->pragma);
81 
82 		if (err_line)
83 			*err_line = n_lines;
84 		if (err_msg)
85 			*err_msg = "Memory allocation failed.";
86 		return -ENOMEM;
87 	}
88 
89 	return 0;
90 }
91 
92 /*
93  * struct.
94  *
95  * struct STRUCT_TYPE_NAME {
96  *	bit<SIZE> FIELD_NAME
97  *	...
98  * }
99  */
100 struct struct_spec {
101 	char *name;
102 	struct rte_swx_field_params *fields;
103 	uint32_t n_fields;
104 };
105 
106 static void
107 struct_spec_free(struct struct_spec *s)
108 {
109 	uint32_t i;
110 
111 	if (!s)
112 		return;
113 
114 	free(s->name);
115 	s->name = NULL;
116 
117 	for (i = 0; i < s->n_fields; i++) {
118 		uintptr_t name = (uintptr_t)s->fields[i].name;
119 
120 		free((void *)name);
121 	}
122 
123 	free(s->fields);
124 	s->fields = NULL;
125 
126 	s->n_fields = 0;
127 }
128 
129 static int
130 struct_statement_parse(struct struct_spec *s,
131 		       uint32_t *block_mask,
132 		       char **tokens,
133 		       uint32_t n_tokens,
134 		       uint32_t n_lines,
135 		       uint32_t *err_line,
136 		       const char **err_msg)
137 {
138 	/* Check format. */
139 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
140 		if (err_line)
141 			*err_line = n_lines;
142 		if (err_msg)
143 			*err_msg = "Invalid struct statement.";
144 		return -EINVAL;
145 	}
146 
147 	/* spec. */
148 	s->name = strdup(tokens[1]);
149 	if (!s->name) {
150 		if (err_line)
151 			*err_line = n_lines;
152 		if (err_msg)
153 			*err_msg = "Memory allocation failed.";
154 		return -ENOMEM;
155 	}
156 
157 	/* block_mask. */
158 	*block_mask |= 1 << STRUCT_BLOCK;
159 
160 	return 0;
161 }
162 
163 static int
164 struct_block_parse(struct struct_spec *s,
165 		   uint32_t *block_mask,
166 		   char **tokens,
167 		   uint32_t n_tokens,
168 		   uint32_t n_lines,
169 		   uint32_t *err_line,
170 		   const char **err_msg)
171 {
172 	struct rte_swx_field_params *new_fields;
173 	char *p = tokens[0], *name;
174 	uint32_t n_bits;
175 
176 	/* Handle end of block. */
177 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
178 		*block_mask &= ~(1 << STRUCT_BLOCK);
179 		return 0;
180 	}
181 
182 	/* Check format. */
183 	if ((n_tokens != 2) ||
184 	    (strlen(p) < 6) ||
185 	    (p[0] != 'b') ||
186 	    (p[1] != 'i') ||
187 	    (p[2] != 't') ||
188 	    (p[3] != '<') ||
189 	    (p[strlen(p) - 1] != '>')) {
190 		if (err_line)
191 			*err_line = n_lines;
192 		if (err_msg)
193 			*err_msg = "Invalid struct field statement.";
194 		return -EINVAL;
195 	}
196 
197 	/* Remove the "bit<" and ">". */
198 	p[strlen(p) - 1] = 0;
199 	p += 4;
200 
201 	n_bits = strtoul(p, &p, 0);
202 	if ((p[0]) ||
203 	    !n_bits ||
204 	    (n_bits % 8) ||
205 	    (n_bits > 64)) {
206 		if (err_line)
207 			*err_line = n_lines;
208 		if (err_msg)
209 			*err_msg = "Invalid struct field size.";
210 		return -EINVAL;
211 	}
212 
213 	/* spec. */
214 	name = strdup(tokens[1]);
215 	if (!name) {
216 		if (err_line)
217 			*err_line = n_lines;
218 		if (err_msg)
219 			*err_msg = "Memory allocation failed.";
220 		return -ENOMEM;
221 	}
222 
223 	new_fields = realloc(s->fields,
224 			     (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
225 	if (!new_fields) {
226 		free(name);
227 
228 		if (err_line)
229 			*err_line = n_lines;
230 		if (err_msg)
231 			*err_msg = "Memory allocation failed.";
232 		return -ENOMEM;
233 	}
234 
235 	s->fields = new_fields;
236 	s->fields[s->n_fields].name = name;
237 	s->fields[s->n_fields].n_bits = n_bits;
238 	s->n_fields++;
239 
240 	return 0;
241 }
242 
243 /*
244  * header.
245  *
246  * header HEADER_NAME instanceof STRUCT_TYPE_NAME
247  */
248 struct header_spec {
249 	char *name;
250 	char *struct_type_name;
251 };
252 
253 static void
254 header_spec_free(struct header_spec *s)
255 {
256 	if (!s)
257 		return;
258 
259 	free(s->name);
260 	s->name = NULL;
261 
262 	free(s->struct_type_name);
263 	s->struct_type_name = NULL;
264 }
265 
266 static int
267 header_statement_parse(struct header_spec *s,
268 		       char **tokens,
269 		       uint32_t n_tokens,
270 		       uint32_t n_lines,
271 		       uint32_t *err_line,
272 		       const char **err_msg)
273 {
274 	/* Check format. */
275 	if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
276 		if (err_line)
277 			*err_line = n_lines;
278 		if (err_msg)
279 			*err_msg = "Invalid header statement.";
280 		return -EINVAL;
281 	}
282 
283 	/* spec. */
284 	s->name = strdup(tokens[1]);
285 	s->struct_type_name = strdup(tokens[3]);
286 
287 	if (!s->name || !s->struct_type_name) {
288 		free(s->name);
289 		free(s->struct_type_name);
290 
291 		if (err_line)
292 			*err_line = n_lines;
293 		if (err_msg)
294 			*err_msg = "Memory allocation failed.";
295 		return -ENOMEM;
296 	}
297 
298 	return 0;
299 }
300 
301 /*
302  * metadata.
303  *
304  * metadata instanceof STRUCT_TYPE_NAME
305  */
306 struct metadata_spec {
307 	char *struct_type_name;
308 };
309 
310 static void
311 metadata_spec_free(struct metadata_spec *s)
312 {
313 	if (!s)
314 		return;
315 
316 	free(s->struct_type_name);
317 	s->struct_type_name = NULL;
318 }
319 
320 static int
321 metadata_statement_parse(struct metadata_spec *s,
322 			 char **tokens,
323 			 uint32_t n_tokens,
324 			 uint32_t n_lines,
325 			 uint32_t *err_line,
326 			 const char **err_msg)
327 {
328 	/* Check format. */
329 	if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
330 		if (err_line)
331 			*err_line = n_lines;
332 		if (err_msg)
333 			*err_msg = "Invalid metadata statement.";
334 		return -EINVAL;
335 	}
336 
337 	/* spec. */
338 	s->struct_type_name = strdup(tokens[2]);
339 	if (!s->struct_type_name) {
340 		if (err_line)
341 			*err_line = n_lines;
342 		if (err_msg)
343 			*err_msg = "Memory allocation failed.";
344 		return -ENOMEM;
345 	}
346 
347 	return 0;
348 }
349 
350 /*
351  * action.
352  *
353  * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
354  *	INSTRUCTION
355  *	...
356  * }
357  */
358 struct action_spec {
359 	char *name;
360 	char *args_struct_type_name;
361 	const char **instructions;
362 	uint32_t n_instructions;
363 };
364 
365 static void
366 action_spec_free(struct action_spec *s)
367 {
368 	uint32_t i;
369 
370 	if (!s)
371 		return;
372 
373 	free(s->name);
374 	s->name = NULL;
375 
376 	free(s->args_struct_type_name);
377 	s->args_struct_type_name = NULL;
378 
379 	for (i = 0; i < s->n_instructions; i++) {
380 		uintptr_t instr = (uintptr_t)s->instructions[i];
381 
382 		free((void *)instr);
383 	}
384 
385 	free(s->instructions);
386 	s->instructions = NULL;
387 
388 	s->n_instructions = 0;
389 }
390 
391 static int
392 action_statement_parse(struct action_spec *s,
393 		       uint32_t *block_mask,
394 		       char **tokens,
395 		       uint32_t n_tokens,
396 		       uint32_t n_lines,
397 		       uint32_t *err_line,
398 		       const char **err_msg)
399 {
400 	/* Check format. */
401 	if (((n_tokens != 5) && (n_tokens != 6)) ||
402 	    ((n_tokens == 5) &&
403 	     (strcmp(tokens[2], "args") ||
404 	      strcmp(tokens[3], "none") ||
405 	      strcmp(tokens[4], "{"))) ||
406 	    ((n_tokens == 6) &&
407 	     (strcmp(tokens[2], "args") ||
408 	      strcmp(tokens[3], "instanceof") ||
409 	      strcmp(tokens[5], "{")))) {
410 		if (err_line)
411 			*err_line = n_lines;
412 		if (err_msg)
413 			*err_msg = "Invalid action statement.";
414 		return -EINVAL;
415 	}
416 
417 	/* spec. */
418 	s->name = strdup(tokens[1]);
419 	s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
420 
421 	if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
422 		if (err_line)
423 			*err_line = n_lines;
424 		if (err_msg)
425 			*err_msg = "Memory allocation failed.";
426 		return -ENOMEM;
427 	}
428 
429 	/* block_mask. */
430 	*block_mask |= 1 << ACTION_BLOCK;
431 
432 	return 0;
433 }
434 
435 static int
436 action_block_parse(struct action_spec *s,
437 		   uint32_t *block_mask,
438 		   char **tokens,
439 		   uint32_t n_tokens,
440 		   uint32_t n_lines,
441 		   uint32_t *err_line,
442 		   const char **err_msg)
443 {
444 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
445 	const char **new_instructions;
446 	uint32_t i;
447 
448 	/* Handle end of block. */
449 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
450 		*block_mask &= ~(1 << ACTION_BLOCK);
451 		return 0;
452 	}
453 
454 	/* spec. */
455 	buffer[0] = 0;
456 	for (i = 0; i < n_tokens; i++) {
457 		if (i)
458 			strcat(buffer, " ");
459 		strcat(buffer, tokens[i]);
460 	}
461 
462 	instr = strdup(buffer);
463 	if (!instr) {
464 		if (err_line)
465 			*err_line = n_lines;
466 		if (err_msg)
467 			*err_msg = "Memory allocation failed.";
468 		return -ENOMEM;
469 	}
470 
471 	new_instructions = realloc(s->instructions,
472 				   (s->n_instructions + 1) * sizeof(char *));
473 	if (!new_instructions) {
474 		free(instr);
475 
476 		if (err_line)
477 			*err_line = n_lines;
478 		if (err_msg)
479 			*err_msg = "Memory allocation failed.";
480 		return -ENOMEM;
481 	}
482 
483 	s->instructions = new_instructions;
484 	s->instructions[s->n_instructions] = instr;
485 	s->n_instructions++;
486 
487 	return 0;
488 }
489 
490 /*
491  * table.
492  *
493  * table {
494  *	key {
495  *		MATCH_FIELD_NAME exact | wildcard | lpm
496  *		...
497  *	}
498  *	actions {
499  *		ACTION_NAME
500  *		...
501  *	}
502  *	default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
503  *	instanceof TABLE_TYPE_NAME
504  *	pragma ARGS
505  *	size SIZE
506  * }
507  */
508 struct table_spec {
509 	char *name;
510 	struct rte_swx_pipeline_table_params params;
511 	char *recommended_table_type_name;
512 	char *args;
513 	uint32_t size;
514 };
515 
516 static void
517 table_spec_free(struct table_spec *s)
518 {
519 	uintptr_t default_action_name;
520 	uint32_t i;
521 
522 	if (!s)
523 		return;
524 
525 	free(s->name);
526 	s->name = NULL;
527 
528 	for (i = 0; i < s->params.n_fields; i++) {
529 		uintptr_t name = (uintptr_t)s->params.fields[i].name;
530 
531 		free((void *)name);
532 	}
533 
534 	free(s->params.fields);
535 	s->params.fields = NULL;
536 
537 	s->params.n_fields = 0;
538 
539 	for (i = 0; i < s->params.n_actions; i++) {
540 		uintptr_t name = (uintptr_t)s->params.action_names[i];
541 
542 		free((void *)name);
543 	}
544 
545 	free(s->params.action_names);
546 	s->params.action_names = NULL;
547 
548 	s->params.n_actions = 0;
549 
550 	default_action_name = (uintptr_t)s->params.default_action_name;
551 	free((void *)default_action_name);
552 	s->params.default_action_name = NULL;
553 
554 	free(s->params.default_action_data);
555 	s->params.default_action_data = 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;
691 	char *name;
692 
693 	/* Handle end of block. */
694 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
695 		*block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
696 		return 0;
697 	}
698 
699 	/* Check input arguments. */
700 	if (n_tokens != 1) {
701 		if (err_line)
702 			*err_line = n_lines;
703 		if (err_msg)
704 			*err_msg = "Invalid action name statement.";
705 		return -EINVAL;
706 	}
707 
708 	name = strdup(tokens[0]);
709 	if (!name) {
710 		if (err_line)
711 			*err_line = n_lines;
712 		if (err_msg)
713 			*err_msg = "Memory allocation failed.";
714 		return -ENOMEM;
715 	}
716 
717 	new_action_names = realloc(s->params.action_names,
718 				   (s->params.n_actions + 1) * sizeof(char *));
719 	if (!new_action_names) {
720 		free(name);
721 
722 		if (err_line)
723 			*err_line = n_lines;
724 		if (err_msg)
725 			*err_msg = "Memory allocation failed.";
726 		return -ENOMEM;
727 	}
728 
729 	s->params.action_names = new_action_names;
730 	s->params.action_names[s->params.n_actions] = name;
731 	s->params.n_actions++;
732 
733 	return 0;
734 }
735 
736 static int
737 table_statement_parse(struct table_spec *s,
738 		      uint32_t *block_mask,
739 		      char **tokens,
740 		      uint32_t n_tokens,
741 		      uint32_t n_lines,
742 		      uint32_t *err_line,
743 		      const char **err_msg)
744 {
745 	/* Check format. */
746 	if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
747 		if (err_line)
748 			*err_line = n_lines;
749 		if (err_msg)
750 			*err_msg = "Invalid table statement.";
751 		return -EINVAL;
752 	}
753 
754 	/* spec. */
755 	s->name = strdup(tokens[1]);
756 	if (!s->name) {
757 		if (err_line)
758 			*err_line = n_lines;
759 		if (err_msg)
760 			*err_msg = "Memory allocation failed.";
761 		return -ENOMEM;
762 	}
763 
764 	/* block_mask. */
765 	*block_mask |= 1 << TABLE_BLOCK;
766 
767 	return 0;
768 }
769 
770 static int
771 table_block_parse(struct table_spec *s,
772 		  uint32_t *block_mask,
773 		  char **tokens,
774 		  uint32_t n_tokens,
775 		  uint32_t n_lines,
776 		  uint32_t *err_line,
777 		  const char **err_msg)
778 {
779 	if (*block_mask & (1 << TABLE_KEY_BLOCK))
780 		return table_key_block_parse(s,
781 					     block_mask,
782 					     tokens,
783 					     n_tokens,
784 					     n_lines,
785 					     err_line,
786 					     err_msg);
787 
788 	if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
789 		return table_actions_block_parse(s,
790 						 block_mask,
791 						 tokens,
792 						 n_tokens,
793 						 n_lines,
794 						 err_line,
795 						 err_msg);
796 
797 	/* Handle end of block. */
798 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
799 		*block_mask &= ~(1 << TABLE_BLOCK);
800 		return 0;
801 	}
802 
803 	if (!strcmp(tokens[0], "key"))
804 		return table_key_statement_parse(block_mask,
805 						 tokens,
806 						 n_tokens,
807 						 n_lines,
808 						 err_line,
809 						 err_msg);
810 
811 	if (!strcmp(tokens[0], "actions"))
812 		return table_actions_statement_parse(block_mask,
813 						     tokens,
814 						     n_tokens,
815 						     n_lines,
816 						     err_line,
817 						     err_msg);
818 
819 	if (!strcmp(tokens[0], "default_action")) {
820 		if (((n_tokens != 4) && (n_tokens != 5)) ||
821 		    strcmp(tokens[2], "args") ||
822 		    strcmp(tokens[3], "none") ||
823 		    ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
824 			if (err_line)
825 				*err_line = n_lines;
826 			if (err_msg)
827 				*err_msg = "Invalid default_action statement.";
828 			return -EINVAL;
829 		}
830 
831 		if (s->params.default_action_name) {
832 			if (err_line)
833 				*err_line = n_lines;
834 			if (err_msg)
835 				*err_msg = "Duplicate default_action stmt.";
836 			return -EINVAL;
837 		}
838 
839 		s->params.default_action_name = strdup(tokens[1]);
840 		if (!s->params.default_action_name) {
841 			if (err_line)
842 				*err_line = n_lines;
843 			if (err_msg)
844 				*err_msg = "Memory allocation failed.";
845 			return -ENOMEM;
846 		}
847 
848 		if (n_tokens == 5)
849 			s->params.default_action_is_const = 1;
850 
851 		return 0;
852 	}
853 
854 	if (!strcmp(tokens[0], "instanceof")) {
855 		if (n_tokens != 2) {
856 			if (err_line)
857 				*err_line = n_lines;
858 			if (err_msg)
859 				*err_msg = "Invalid instanceof statement.";
860 			return -EINVAL;
861 		}
862 
863 		if (s->recommended_table_type_name) {
864 			if (err_line)
865 				*err_line = n_lines;
866 			if (err_msg)
867 				*err_msg = "Duplicate instanceof statement.";
868 			return -EINVAL;
869 		}
870 
871 		s->recommended_table_type_name = strdup(tokens[1]);
872 		if (!s->recommended_table_type_name) {
873 			if (err_line)
874 				*err_line = n_lines;
875 			if (err_msg)
876 				*err_msg = "Memory allocation failed.";
877 			return -ENOMEM;
878 		}
879 
880 		return 0;
881 	}
882 
883 	if (!strcmp(tokens[0], "pragma")) {
884 		if (n_tokens != 2) {
885 			if (err_line)
886 				*err_line = n_lines;
887 			if (err_msg)
888 				*err_msg = "Invalid pragma statement.";
889 			return -EINVAL;
890 		}
891 
892 		if (s->args) {
893 			if (err_line)
894 				*err_line = n_lines;
895 			if (err_msg)
896 				*err_msg = "Duplicate pragma statement.";
897 			return -EINVAL;
898 		}
899 
900 		s->args = strdup(tokens[1]);
901 		if (!s->args) {
902 			if (err_line)
903 				*err_line = n_lines;
904 			if (err_msg)
905 				*err_msg = "Memory allocation failed.";
906 			return -ENOMEM;
907 		}
908 
909 		return 0;
910 	}
911 
912 	if (!strcmp(tokens[0], "size")) {
913 		char *p = tokens[1];
914 
915 		if (n_tokens != 2) {
916 			if (err_line)
917 				*err_line = n_lines;
918 			if (err_msg)
919 				*err_msg = "Invalid pragma statement.";
920 			return -EINVAL;
921 		}
922 
923 		s->size = strtoul(p, &p, 0);
924 		if (p[0]) {
925 			if (err_line)
926 				*err_line = n_lines;
927 			if (err_msg)
928 				*err_msg = "Invalid size argument.";
929 			return -EINVAL;
930 		}
931 
932 		return 0;
933 	}
934 
935 	/* Anything else. */
936 	if (err_line)
937 		*err_line = n_lines;
938 	if (err_msg)
939 		*err_msg = "Invalid statement.";
940 	return -EINVAL;
941 }
942 
943 /*
944  * regarray.
945  *
946  * regarray NAME size SIZE initval INITVAL
947  */
948 struct regarray_spec {
949 	char *name;
950 	uint64_t init_val;
951 	uint32_t size;
952 };
953 
954 static void
955 regarray_spec_free(struct regarray_spec *s)
956 {
957 	if (!s)
958 		return;
959 
960 	free(s->name);
961 	s->name = NULL;
962 }
963 
964 static int
965 regarray_statement_parse(struct regarray_spec *s,
966 			 char **tokens,
967 			 uint32_t n_tokens,
968 			 uint32_t n_lines,
969 			 uint32_t *err_line,
970 			 const char **err_msg)
971 {
972 	char *p;
973 
974 	/* Check format. */
975 	if ((n_tokens != 6) ||
976 	     strcmp(tokens[2], "size") ||
977 	     strcmp(tokens[4], "initval")) {
978 		if (err_line)
979 			*err_line = n_lines;
980 		if (err_msg)
981 			*err_msg = "Invalid regarray statement.";
982 		return -EINVAL;
983 	}
984 
985 	/* spec. */
986 	s->name = strdup(tokens[1]);
987 	if (!s->name) {
988 		if (err_line)
989 			*err_line = n_lines;
990 		if (err_msg)
991 			*err_msg = "Memory allocation failed.";
992 		return -ENOMEM;
993 	}
994 
995 	p = tokens[3];
996 	s->size = strtoul(p, &p, 0);
997 	if (p[0] || !s->size) {
998 		if (err_line)
999 			*err_line = n_lines;
1000 		if (err_msg)
1001 			*err_msg = "Invalid size argument.";
1002 		return -EINVAL;
1003 	}
1004 
1005 	p = tokens[5];
1006 	s->init_val = strtoull(p, &p, 0);
1007 	if (p[0]) {
1008 		if (err_line)
1009 			*err_line = n_lines;
1010 		if (err_msg)
1011 			*err_msg = "Invalid initval argument.";
1012 		return -EINVAL;
1013 	}
1014 
1015 	return 0;
1016 }
1017 
1018 /*
1019  * metarray.
1020  *
1021  * metarray NAME size SIZE
1022  */
1023 struct metarray_spec {
1024 	char *name;
1025 	uint32_t size;
1026 };
1027 
1028 static void
1029 metarray_spec_free(struct metarray_spec *s)
1030 {
1031 	if (!s)
1032 		return;
1033 
1034 	free(s->name);
1035 	s->name = NULL;
1036 }
1037 
1038 static int
1039 metarray_statement_parse(struct metarray_spec *s,
1040 			 char **tokens,
1041 			 uint32_t n_tokens,
1042 			 uint32_t n_lines,
1043 			 uint32_t *err_line,
1044 			 const char **err_msg)
1045 {
1046 	char *p;
1047 
1048 	/* Check format. */
1049 	if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
1050 		if (err_line)
1051 			*err_line = n_lines;
1052 		if (err_msg)
1053 			*err_msg = "Invalid metarray statement.";
1054 		return -EINVAL;
1055 	}
1056 
1057 	/* spec. */
1058 	s->name = strdup(tokens[1]);
1059 	if (!s->name) {
1060 		if (err_line)
1061 			*err_line = n_lines;
1062 		if (err_msg)
1063 			*err_msg = "Memory allocation failed.";
1064 		return -ENOMEM;
1065 	}
1066 
1067 	p = tokens[3];
1068 	s->size = strtoul(p, &p, 0);
1069 	if (p[0] || !s->size) {
1070 		if (err_line)
1071 			*err_line = n_lines;
1072 		if (err_msg)
1073 			*err_msg = "Invalid size argument.";
1074 		return -EINVAL;
1075 	}
1076 
1077 	return 0;
1078 }
1079 
1080 /*
1081  * apply.
1082  *
1083  * apply {
1084  *	INSTRUCTION
1085  *	...
1086  * }
1087  */
1088 struct apply_spec {
1089 	const char **instructions;
1090 	uint32_t n_instructions;
1091 };
1092 
1093 static void
1094 apply_spec_free(struct apply_spec *s)
1095 {
1096 	uint32_t i;
1097 
1098 	if (!s)
1099 		return;
1100 
1101 	for (i = 0; i < s->n_instructions; i++) {
1102 		uintptr_t instr = (uintptr_t)s->instructions[i];
1103 
1104 		free((void *)instr);
1105 	}
1106 
1107 	free(s->instructions);
1108 	s->instructions = NULL;
1109 
1110 	s->n_instructions = 0;
1111 }
1112 
1113 static int
1114 apply_statement_parse(uint32_t *block_mask,
1115 		      char **tokens,
1116 		      uint32_t n_tokens,
1117 		      uint32_t n_lines,
1118 		      uint32_t *err_line,
1119 		      const char **err_msg)
1120 {
1121 	/* Check format. */
1122 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1123 		if (err_line)
1124 			*err_line = n_lines;
1125 		if (err_msg)
1126 			*err_msg = "Invalid apply statement.";
1127 		return -EINVAL;
1128 	}
1129 
1130 	/* block_mask. */
1131 	*block_mask |= 1 << APPLY_BLOCK;
1132 
1133 	return 0;
1134 }
1135 
1136 static int
1137 apply_block_parse(struct apply_spec *s,
1138 		  uint32_t *block_mask,
1139 		  char **tokens,
1140 		  uint32_t n_tokens,
1141 		  uint32_t n_lines,
1142 		  uint32_t *err_line,
1143 		  const char **err_msg)
1144 {
1145 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1146 	const char **new_instructions;
1147 	uint32_t i;
1148 
1149 	/* Handle end of block. */
1150 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1151 		*block_mask &= ~(1 << APPLY_BLOCK);
1152 		return 0;
1153 	}
1154 
1155 	/* spec. */
1156 	buffer[0] = 0;
1157 	for (i = 0; i < n_tokens; i++) {
1158 		if (i)
1159 			strcat(buffer, " ");
1160 		strcat(buffer, tokens[i]);
1161 	}
1162 
1163 	instr = strdup(buffer);
1164 	if (!instr) {
1165 		if (err_line)
1166 			*err_line = n_lines;
1167 		if (err_msg)
1168 			*err_msg = "Memory allocation failed.";
1169 		return -ENOMEM;
1170 	}
1171 
1172 	new_instructions = realloc(s->instructions,
1173 				   (s->n_instructions + 1) * sizeof(char *));
1174 	if (!new_instructions) {
1175 		free(instr);
1176 
1177 		if (err_line)
1178 			*err_line = n_lines;
1179 		if (err_msg)
1180 			*err_msg = "Memory allocation failed.";
1181 		return -ENOMEM;
1182 	}
1183 
1184 	s->instructions = new_instructions;
1185 	s->instructions[s->n_instructions] = instr;
1186 	s->n_instructions++;
1187 
1188 	return 0;
1189 }
1190 
1191 /*
1192  * Pipeline.
1193  */
1194 int
1195 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1196 				 FILE *spec,
1197 				 uint32_t *err_line,
1198 				 const char **err_msg)
1199 {
1200 	struct extobj_spec extobj_spec = {0};
1201 	struct struct_spec struct_spec = {0};
1202 	struct header_spec header_spec = {0};
1203 	struct metadata_spec metadata_spec = {0};
1204 	struct action_spec action_spec = {0};
1205 	struct table_spec table_spec = {0};
1206 	struct regarray_spec regarray_spec = {0};
1207 	struct metarray_spec metarray_spec = {0};
1208 	struct apply_spec apply_spec = {0};
1209 	uint32_t n_lines;
1210 	uint32_t block_mask = 0;
1211 	int status;
1212 
1213 	/* Check the input arguments. */
1214 	if (!p) {
1215 		if (err_line)
1216 			*err_line = 0;
1217 		if (err_msg)
1218 			*err_msg = "Null pipeline arument.";
1219 		status = -EINVAL;
1220 		goto error;
1221 	}
1222 
1223 	if (!spec) {
1224 		if (err_line)
1225 			*err_line = 0;
1226 		if (err_msg)
1227 			*err_msg = "Null specification file argument.";
1228 		status = -EINVAL;
1229 		goto error;
1230 	}
1231 
1232 	for (n_lines = 1; ; n_lines++) {
1233 		char line[MAX_LINE_LENGTH];
1234 		char *tokens[MAX_TOKENS], *ptr = line;
1235 		uint32_t n_tokens = 0;
1236 
1237 		/* Read next line. */
1238 		if (!fgets(line, sizeof(line), spec))
1239 			break;
1240 
1241 		/* Parse the line into tokens. */
1242 		for ( ; ; ) {
1243 			char *token;
1244 
1245 			/* Get token. */
1246 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1247 			if (!token)
1248 				break;
1249 
1250 			/* Handle comments. */
1251 			if ((token[0] == '#') ||
1252 			    (token[0] == ';') ||
1253 			    ((token[0] == '/') && (token[1] == '/'))) {
1254 				break;
1255 			}
1256 
1257 			/* Handle excessively long lines. */
1258 			if (n_tokens >= MAX_TOKENS) {
1259 				if (err_line)
1260 					*err_line = n_lines;
1261 				if (err_msg)
1262 					*err_msg = "Too many tokens.";
1263 				status = -EINVAL;
1264 				goto error;
1265 			}
1266 
1267 			/* Handle excessively long tokens. */
1268 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
1269 			    RTE_SWX_NAME_SIZE) {
1270 				if (err_line)
1271 					*err_line = n_lines;
1272 				if (err_msg)
1273 					*err_msg = "Token too big.";
1274 				status = -EINVAL;
1275 				goto error;
1276 			}
1277 
1278 			/* Save token. */
1279 			tokens[n_tokens] = token;
1280 			n_tokens++;
1281 		}
1282 
1283 		/* Handle empty lines. */
1284 		if (!n_tokens)
1285 			continue;
1286 
1287 		/* struct block. */
1288 		if (block_mask & (1 << STRUCT_BLOCK)) {
1289 			status = struct_block_parse(&struct_spec,
1290 						    &block_mask,
1291 						    tokens,
1292 						    n_tokens,
1293 						    n_lines,
1294 						    err_line,
1295 						    err_msg);
1296 			if (status)
1297 				goto error;
1298 
1299 			if (block_mask & (1 << STRUCT_BLOCK))
1300 				continue;
1301 
1302 			/* End of block. */
1303 			status = rte_swx_pipeline_struct_type_register(p,
1304 				struct_spec.name,
1305 				struct_spec.fields,
1306 				struct_spec.n_fields);
1307 			if (status) {
1308 				if (err_line)
1309 					*err_line = n_lines;
1310 				if (err_msg)
1311 					*err_msg = "Struct registration error.";
1312 				goto error;
1313 			}
1314 
1315 			struct_spec_free(&struct_spec);
1316 
1317 			continue;
1318 		}
1319 
1320 		/* action block. */
1321 		if (block_mask & (1 << ACTION_BLOCK)) {
1322 			status = action_block_parse(&action_spec,
1323 						    &block_mask,
1324 						    tokens,
1325 						    n_tokens,
1326 						    n_lines,
1327 						    err_line,
1328 						    err_msg);
1329 			if (status)
1330 				goto error;
1331 
1332 			if (block_mask & (1 << ACTION_BLOCK))
1333 				continue;
1334 
1335 			/* End of block. */
1336 			status = rte_swx_pipeline_action_config(p,
1337 				action_spec.name,
1338 				action_spec.args_struct_type_name,
1339 				action_spec.instructions,
1340 				action_spec.n_instructions);
1341 			if (status) {
1342 				if (err_line)
1343 					*err_line = n_lines;
1344 				if (err_msg)
1345 					*err_msg = "Action config error.";
1346 				goto error;
1347 			}
1348 
1349 			action_spec_free(&action_spec);
1350 
1351 			continue;
1352 		}
1353 
1354 		/* table block. */
1355 		if (block_mask & (1 << TABLE_BLOCK)) {
1356 			status = table_block_parse(&table_spec,
1357 						   &block_mask,
1358 						   tokens,
1359 						   n_tokens,
1360 						   n_lines,
1361 						   err_line,
1362 						   err_msg);
1363 			if (status)
1364 				goto error;
1365 
1366 			if (block_mask & (1 << TABLE_BLOCK))
1367 				continue;
1368 
1369 			/* End of block. */
1370 			status = rte_swx_pipeline_table_config(p,
1371 				table_spec.name,
1372 				&table_spec.params,
1373 				table_spec.recommended_table_type_name,
1374 				table_spec.args,
1375 				table_spec.size);
1376 			if (status) {
1377 				if (err_line)
1378 					*err_line = n_lines;
1379 				if (err_msg)
1380 					*err_msg = "Table configuration error.";
1381 				goto error;
1382 			}
1383 
1384 			table_spec_free(&table_spec);
1385 
1386 			continue;
1387 		}
1388 
1389 		/* apply block. */
1390 		if (block_mask & (1 << APPLY_BLOCK)) {
1391 			status = apply_block_parse(&apply_spec,
1392 						   &block_mask,
1393 						   tokens,
1394 						   n_tokens,
1395 						   n_lines,
1396 						   err_line,
1397 						   err_msg);
1398 			if (status)
1399 				goto error;
1400 
1401 			if (block_mask & (1 << APPLY_BLOCK))
1402 				continue;
1403 
1404 			/* End of block. */
1405 			status = rte_swx_pipeline_instructions_config(p,
1406 				apply_spec.instructions,
1407 				apply_spec.n_instructions);
1408 			if (status) {
1409 				if (err_line)
1410 					*err_line = n_lines;
1411 				if (err_msg)
1412 					*err_msg = "Pipeline instructions err.";
1413 				goto error;
1414 			}
1415 
1416 			apply_spec_free(&apply_spec);
1417 
1418 			continue;
1419 		}
1420 
1421 		/* extobj. */
1422 		if (!strcmp(tokens[0], "extobj")) {
1423 			status = extobj_statement_parse(&extobj_spec,
1424 							tokens,
1425 							n_tokens,
1426 							n_lines,
1427 							err_line,
1428 							err_msg);
1429 			if (status)
1430 				goto error;
1431 
1432 			status = rte_swx_pipeline_extern_object_config(p,
1433 				extobj_spec.name,
1434 				extobj_spec.extern_type_name,
1435 				extobj_spec.pragma);
1436 			if (status) {
1437 				if (err_line)
1438 					*err_line = n_lines;
1439 				if (err_msg)
1440 					*err_msg = "Extern object config err.";
1441 				goto error;
1442 			}
1443 
1444 			extobj_spec_free(&extobj_spec);
1445 
1446 			continue;
1447 		}
1448 
1449 		/* struct. */
1450 		if (!strcmp(tokens[0], "struct")) {
1451 			status = struct_statement_parse(&struct_spec,
1452 							&block_mask,
1453 							tokens,
1454 							n_tokens,
1455 							n_lines,
1456 							err_line,
1457 							err_msg);
1458 			if (status)
1459 				goto error;
1460 
1461 			continue;
1462 		}
1463 
1464 		/* header. */
1465 		if (!strcmp(tokens[0], "header")) {
1466 			status = header_statement_parse(&header_spec,
1467 							tokens,
1468 							n_tokens,
1469 							n_lines,
1470 							err_line,
1471 							err_msg);
1472 			if (status)
1473 				goto error;
1474 
1475 			status = rte_swx_pipeline_packet_header_register(p,
1476 				header_spec.name,
1477 				header_spec.struct_type_name);
1478 			if (status) {
1479 				if (err_line)
1480 					*err_line = n_lines;
1481 				if (err_msg)
1482 					*err_msg = "Header registration error.";
1483 				goto error;
1484 			}
1485 
1486 			header_spec_free(&header_spec);
1487 
1488 			continue;
1489 		}
1490 
1491 		/* metadata. */
1492 		if (!strcmp(tokens[0], "metadata")) {
1493 			status = metadata_statement_parse(&metadata_spec,
1494 							  tokens,
1495 							  n_tokens,
1496 							  n_lines,
1497 							  err_line,
1498 							  err_msg);
1499 			if (status)
1500 				goto error;
1501 
1502 			status = rte_swx_pipeline_packet_metadata_register(p,
1503 				metadata_spec.struct_type_name);
1504 			if (status) {
1505 				if (err_line)
1506 					*err_line = n_lines;
1507 				if (err_msg)
1508 					*err_msg = "Meta-data reg err.";
1509 				goto error;
1510 			}
1511 
1512 			metadata_spec_free(&metadata_spec);
1513 
1514 			continue;
1515 		}
1516 
1517 		/* action. */
1518 		if (!strcmp(tokens[0], "action")) {
1519 			status = action_statement_parse(&action_spec,
1520 							&block_mask,
1521 							tokens,
1522 							n_tokens,
1523 							n_lines,
1524 							err_line,
1525 							err_msg);
1526 			if (status)
1527 				goto error;
1528 
1529 			continue;
1530 		}
1531 
1532 		/* table. */
1533 		if (!strcmp(tokens[0], "table")) {
1534 			status = table_statement_parse(&table_spec,
1535 						       &block_mask,
1536 						       tokens,
1537 						       n_tokens,
1538 						       n_lines,
1539 						       err_line,
1540 						       err_msg);
1541 			if (status)
1542 				goto error;
1543 
1544 			continue;
1545 		}
1546 
1547 		/* regarray. */
1548 		if (!strcmp(tokens[0], "regarray")) {
1549 			status = regarray_statement_parse(&regarray_spec,
1550 							  tokens,
1551 							  n_tokens,
1552 							  n_lines,
1553 							  err_line,
1554 							  err_msg);
1555 			if (status)
1556 				goto error;
1557 
1558 			status = rte_swx_pipeline_regarray_config(p,
1559 				regarray_spec.name,
1560 				regarray_spec.size,
1561 				regarray_spec.init_val);
1562 			if (status) {
1563 				if (err_line)
1564 					*err_line = n_lines;
1565 				if (err_msg)
1566 					*err_msg = "Register array configuration error.";
1567 				goto error;
1568 			}
1569 
1570 			regarray_spec_free(&regarray_spec);
1571 
1572 			continue;
1573 		}
1574 
1575 		/* metarray. */
1576 		if (!strcmp(tokens[0], "metarray")) {
1577 			status = metarray_statement_parse(&metarray_spec,
1578 							  tokens,
1579 							  n_tokens,
1580 							  n_lines,
1581 							  err_line,
1582 							  err_msg);
1583 			if (status)
1584 				goto error;
1585 
1586 			status = rte_swx_pipeline_metarray_config(p,
1587 				metarray_spec.name,
1588 				metarray_spec.size);
1589 			if (status) {
1590 				if (err_line)
1591 					*err_line = n_lines;
1592 				if (err_msg)
1593 					*err_msg = "Meter array configuration error.";
1594 				goto error;
1595 			}
1596 
1597 			metarray_spec_free(&metarray_spec);
1598 
1599 			continue;
1600 		}
1601 
1602 		/* apply. */
1603 		if (!strcmp(tokens[0], "apply")) {
1604 			status = apply_statement_parse(&block_mask,
1605 						       tokens,
1606 						       n_tokens,
1607 						       n_lines,
1608 						       err_line,
1609 						       err_msg);
1610 			if (status)
1611 				goto error;
1612 
1613 			continue;
1614 		}
1615 
1616 		/* Anything else. */
1617 		if (err_line)
1618 			*err_line = n_lines;
1619 		if (err_msg)
1620 			*err_msg = "Unknown statement.";
1621 		status = -EINVAL;
1622 		goto error;
1623 	}
1624 
1625 	/* Handle unfinished block. */
1626 	if (block_mask) {
1627 		if (err_line)
1628 			*err_line = n_lines;
1629 		if (err_msg)
1630 			*err_msg = "Missing }.";
1631 		status = -EINVAL;
1632 		goto error;
1633 	}
1634 
1635 	/* Pipeline build. */
1636 	status = rte_swx_pipeline_build(p);
1637 	if (status) {
1638 		if (err_line)
1639 			*err_line = n_lines;
1640 		if (err_msg)
1641 			*err_msg = "Pipeline build error.";
1642 		goto error;
1643 	}
1644 
1645 	return 0;
1646 
1647 error:
1648 	extobj_spec_free(&extobj_spec);
1649 	struct_spec_free(&struct_spec);
1650 	header_spec_free(&header_spec);
1651 	metadata_spec_free(&metadata_spec);
1652 	action_spec_free(&action_spec);
1653 	table_spec_free(&table_spec);
1654 	regarray_spec_free(&regarray_spec);
1655 	metarray_spec_free(&metarray_spec);
1656 	apply_spec_free(&apply_spec);
1657 	return status;
1658 }
1659