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
extobj_spec_free(struct extobj_spec * s)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
extobj_statement_parse(struct extobj_spec * s,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
struct_spec_free(struct struct_spec * s)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
struct_statement_parse(struct struct_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
struct_block_parse(struct struct_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
header_spec_free(struct header_spec * s)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
header_statement_parse(struct header_spec * s,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
metadata_spec_free(struct metadata_spec * s)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
metadata_statement_parse(struct metadata_spec * s,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
action_spec_free(struct action_spec * s)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
action_statement_parse(struct action_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
action_block_parse(struct action_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
table_spec_free(struct table_spec * s)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
table_key_statement_parse(uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
table_key_block_parse(struct table_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
table_actions_statement_parse(uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
table_actions_block_parse(struct table_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
table_statement_parse(struct table_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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
table_block_parse(struct table_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)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  * apply.
945  *
946  * apply {
947  *	INSTRUCTION
948  *	...
949  * }
950  */
951 struct apply_spec {
952 	const char **instructions;
953 	uint32_t n_instructions;
954 };
955 
956 static void
apply_spec_free(struct apply_spec * s)957 apply_spec_free(struct apply_spec *s)
958 {
959 	uint32_t i;
960 
961 	if (!s)
962 		return;
963 
964 	for (i = 0; i < s->n_instructions; i++) {
965 		uintptr_t instr = (uintptr_t)s->instructions[i];
966 
967 		free((void *)instr);
968 	}
969 
970 	free(s->instructions);
971 	s->instructions = NULL;
972 
973 	s->n_instructions = 0;
974 }
975 
976 static int
apply_statement_parse(uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)977 apply_statement_parse(uint32_t *block_mask,
978 		      char **tokens,
979 		      uint32_t n_tokens,
980 		      uint32_t n_lines,
981 		      uint32_t *err_line,
982 		      const char **err_msg)
983 {
984 	/* Check format. */
985 	if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
986 		if (err_line)
987 			*err_line = n_lines;
988 		if (err_msg)
989 			*err_msg = "Invalid apply statement.";
990 		return -EINVAL;
991 	}
992 
993 	/* block_mask. */
994 	*block_mask |= 1 << APPLY_BLOCK;
995 
996 	return 0;
997 }
998 
999 static int
apply_block_parse(struct apply_spec * s,uint32_t * block_mask,char ** tokens,uint32_t n_tokens,uint32_t n_lines,uint32_t * err_line,const char ** err_msg)1000 apply_block_parse(struct apply_spec *s,
1001 		  uint32_t *block_mask,
1002 		  char **tokens,
1003 		  uint32_t n_tokens,
1004 		  uint32_t n_lines,
1005 		  uint32_t *err_line,
1006 		  const char **err_msg)
1007 {
1008 	char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1009 	const char **new_instructions;
1010 	uint32_t i;
1011 
1012 	/* Handle end of block. */
1013 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1014 		*block_mask &= ~(1 << APPLY_BLOCK);
1015 		return 0;
1016 	}
1017 
1018 	/* spec. */
1019 	buffer[0] = 0;
1020 	for (i = 0; i < n_tokens; i++) {
1021 		if (i)
1022 			strcat(buffer, " ");
1023 		strcat(buffer, tokens[i]);
1024 	}
1025 
1026 	instr = strdup(buffer);
1027 	if (!instr) {
1028 		if (err_line)
1029 			*err_line = n_lines;
1030 		if (err_msg)
1031 			*err_msg = "Memory allocation failed.";
1032 		return -ENOMEM;
1033 	}
1034 
1035 	new_instructions = realloc(s->instructions,
1036 				   (s->n_instructions + 1) * sizeof(char *));
1037 	if (!new_instructions) {
1038 		free(instr);
1039 
1040 		if (err_line)
1041 			*err_line = n_lines;
1042 		if (err_msg)
1043 			*err_msg = "Memory allocation failed.";
1044 		return -ENOMEM;
1045 	}
1046 
1047 	s->instructions = new_instructions;
1048 	s->instructions[s->n_instructions] = instr;
1049 	s->n_instructions++;
1050 
1051 	return 0;
1052 }
1053 
1054 /*
1055  * Pipeline.
1056  */
1057 int
rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline * p,FILE * spec,uint32_t * err_line,const char ** err_msg)1058 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1059 				 FILE *spec,
1060 				 uint32_t *err_line,
1061 				 const char **err_msg)
1062 {
1063 	struct extobj_spec extobj_spec = {0};
1064 	struct struct_spec struct_spec = {0};
1065 	struct header_spec header_spec = {0};
1066 	struct metadata_spec metadata_spec = {0};
1067 	struct action_spec action_spec = {0};
1068 	struct table_spec table_spec = {0};
1069 	struct apply_spec apply_spec = {0};
1070 	uint32_t n_lines;
1071 	uint32_t block_mask = 0;
1072 	int status;
1073 
1074 	/* Check the input arguments. */
1075 	if (!p) {
1076 		if (err_line)
1077 			*err_line = 0;
1078 		if (err_msg)
1079 			*err_msg = "Null pipeline arument.";
1080 		status = -EINVAL;
1081 		goto error;
1082 	}
1083 
1084 	if (!spec) {
1085 		if (err_line)
1086 			*err_line = 0;
1087 		if (err_msg)
1088 			*err_msg = "Null specification file argument.";
1089 		status = -EINVAL;
1090 		goto error;
1091 	}
1092 
1093 	for (n_lines = 1; ; n_lines++) {
1094 		char line[MAX_LINE_LENGTH];
1095 		char *tokens[MAX_TOKENS], *ptr = line;
1096 		uint32_t n_tokens = 0;
1097 
1098 		/* Read next line. */
1099 		if (!fgets(line, sizeof(line), spec))
1100 			break;
1101 
1102 		/* Parse the line into tokens. */
1103 		for ( ; ; ) {
1104 			char *token;
1105 
1106 			/* Get token. */
1107 			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1108 			if (!token)
1109 				break;
1110 
1111 			/* Handle comments. */
1112 			if ((token[0] == '#') ||
1113 			    (token[0] == ';') ||
1114 			    ((token[0] == '/') && (token[1] == '/'))) {
1115 				break;
1116 			}
1117 
1118 			/* Handle excessively long lines. */
1119 			if (n_tokens >= MAX_TOKENS) {
1120 				if (err_line)
1121 					*err_line = n_lines;
1122 				if (err_msg)
1123 					*err_msg = "Too many tokens.";
1124 				status = -EINVAL;
1125 				goto error;
1126 			}
1127 
1128 			/* Handle excessively long tokens. */
1129 			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
1130 			    RTE_SWX_NAME_SIZE) {
1131 				if (err_line)
1132 					*err_line = n_lines;
1133 				if (err_msg)
1134 					*err_msg = "Token too big.";
1135 				status = -EINVAL;
1136 				goto error;
1137 			}
1138 
1139 			/* Save token. */
1140 			tokens[n_tokens] = token;
1141 			n_tokens++;
1142 		}
1143 
1144 		/* Handle empty lines. */
1145 		if (!n_tokens)
1146 			continue;
1147 
1148 		/* struct block. */
1149 		if (block_mask & (1 << STRUCT_BLOCK)) {
1150 			status = struct_block_parse(&struct_spec,
1151 						    &block_mask,
1152 						    tokens,
1153 						    n_tokens,
1154 						    n_lines,
1155 						    err_line,
1156 						    err_msg);
1157 			if (status)
1158 				goto error;
1159 
1160 			if (block_mask & (1 << STRUCT_BLOCK))
1161 				continue;
1162 
1163 			/* End of block. */
1164 			status = rte_swx_pipeline_struct_type_register(p,
1165 				struct_spec.name,
1166 				struct_spec.fields,
1167 				struct_spec.n_fields);
1168 			if (status) {
1169 				if (err_line)
1170 					*err_line = n_lines;
1171 				if (err_msg)
1172 					*err_msg = "Struct registration error.";
1173 				goto error;
1174 			}
1175 
1176 			struct_spec_free(&struct_spec);
1177 
1178 			continue;
1179 		}
1180 
1181 		/* action block. */
1182 		if (block_mask & (1 << ACTION_BLOCK)) {
1183 			status = action_block_parse(&action_spec,
1184 						    &block_mask,
1185 						    tokens,
1186 						    n_tokens,
1187 						    n_lines,
1188 						    err_line,
1189 						    err_msg);
1190 			if (status)
1191 				goto error;
1192 
1193 			if (block_mask & (1 << ACTION_BLOCK))
1194 				continue;
1195 
1196 			/* End of block. */
1197 			status = rte_swx_pipeline_action_config(p,
1198 				action_spec.name,
1199 				action_spec.args_struct_type_name,
1200 				action_spec.instructions,
1201 				action_spec.n_instructions);
1202 			if (status) {
1203 				if (err_line)
1204 					*err_line = n_lines;
1205 				if (err_msg)
1206 					*err_msg = "Action config error.";
1207 				goto error;
1208 			}
1209 
1210 			action_spec_free(&action_spec);
1211 
1212 			continue;
1213 		}
1214 
1215 		/* table block. */
1216 		if (block_mask & (1 << TABLE_BLOCK)) {
1217 			status = table_block_parse(&table_spec,
1218 						   &block_mask,
1219 						   tokens,
1220 						   n_tokens,
1221 						   n_lines,
1222 						   err_line,
1223 						   err_msg);
1224 			if (status)
1225 				goto error;
1226 
1227 			if (block_mask & (1 << TABLE_BLOCK))
1228 				continue;
1229 
1230 			/* End of block. */
1231 			status = rte_swx_pipeline_table_config(p,
1232 				table_spec.name,
1233 				&table_spec.params,
1234 				table_spec.recommended_table_type_name,
1235 				table_spec.args,
1236 				table_spec.size);
1237 			if (status) {
1238 				if (err_line)
1239 					*err_line = n_lines;
1240 				if (err_msg)
1241 					*err_msg = "Table configuration error.";
1242 				goto error;
1243 			}
1244 
1245 			table_spec_free(&table_spec);
1246 
1247 			continue;
1248 		}
1249 
1250 		/* apply block. */
1251 		if (block_mask & (1 << APPLY_BLOCK)) {
1252 			status = apply_block_parse(&apply_spec,
1253 						   &block_mask,
1254 						   tokens,
1255 						   n_tokens,
1256 						   n_lines,
1257 						   err_line,
1258 						   err_msg);
1259 			if (status)
1260 				goto error;
1261 
1262 			if (block_mask & (1 << APPLY_BLOCK))
1263 				continue;
1264 
1265 			/* End of block. */
1266 			status = rte_swx_pipeline_instructions_config(p,
1267 				apply_spec.instructions,
1268 				apply_spec.n_instructions);
1269 			if (status) {
1270 				if (err_line)
1271 					*err_line = n_lines;
1272 				if (err_msg)
1273 					*err_msg = "Pipeline instructions err.";
1274 				goto error;
1275 			}
1276 
1277 			apply_spec_free(&apply_spec);
1278 
1279 			continue;
1280 		}
1281 
1282 		/* extobj. */
1283 		if (!strcmp(tokens[0], "extobj")) {
1284 			status = extobj_statement_parse(&extobj_spec,
1285 							tokens,
1286 							n_tokens,
1287 							n_lines,
1288 							err_line,
1289 							err_msg);
1290 			if (status)
1291 				goto error;
1292 
1293 			status = rte_swx_pipeline_extern_object_config(p,
1294 				extobj_spec.name,
1295 				extobj_spec.extern_type_name,
1296 				extobj_spec.pragma);
1297 			if (status) {
1298 				if (err_line)
1299 					*err_line = n_lines;
1300 				if (err_msg)
1301 					*err_msg = "Extern object config err.";
1302 				goto error;
1303 			}
1304 
1305 			extobj_spec_free(&extobj_spec);
1306 
1307 			continue;
1308 		}
1309 
1310 		/* struct. */
1311 		if (!strcmp(tokens[0], "struct")) {
1312 			status = struct_statement_parse(&struct_spec,
1313 							&block_mask,
1314 							tokens,
1315 							n_tokens,
1316 							n_lines,
1317 							err_line,
1318 							err_msg);
1319 			if (status)
1320 				goto error;
1321 
1322 			continue;
1323 		}
1324 
1325 		/* header. */
1326 		if (!strcmp(tokens[0], "header")) {
1327 			status = header_statement_parse(&header_spec,
1328 							tokens,
1329 							n_tokens,
1330 							n_lines,
1331 							err_line,
1332 							err_msg);
1333 			if (status)
1334 				goto error;
1335 
1336 			status = rte_swx_pipeline_packet_header_register(p,
1337 				header_spec.name,
1338 				header_spec.struct_type_name);
1339 			if (status) {
1340 				if (err_line)
1341 					*err_line = n_lines;
1342 				if (err_msg)
1343 					*err_msg = "Header registration error.";
1344 				goto error;
1345 			}
1346 
1347 			header_spec_free(&header_spec);
1348 
1349 			continue;
1350 		}
1351 
1352 		/* metadata. */
1353 		if (!strcmp(tokens[0], "metadata")) {
1354 			status = metadata_statement_parse(&metadata_spec,
1355 							  tokens,
1356 							  n_tokens,
1357 							  n_lines,
1358 							  err_line,
1359 							  err_msg);
1360 			if (status)
1361 				goto error;
1362 
1363 			status = rte_swx_pipeline_packet_metadata_register(p,
1364 				metadata_spec.struct_type_name);
1365 			if (status) {
1366 				if (err_line)
1367 					*err_line = n_lines;
1368 				if (err_msg)
1369 					*err_msg = "Meta-data reg err.";
1370 				goto error;
1371 			}
1372 
1373 			metadata_spec_free(&metadata_spec);
1374 
1375 			continue;
1376 		}
1377 
1378 		/* action. */
1379 		if (!strcmp(tokens[0], "action")) {
1380 			status = action_statement_parse(&action_spec,
1381 							&block_mask,
1382 							tokens,
1383 							n_tokens,
1384 							n_lines,
1385 							err_line,
1386 							err_msg);
1387 			if (status)
1388 				goto error;
1389 
1390 			continue;
1391 		}
1392 
1393 		/* table. */
1394 		if (!strcmp(tokens[0], "table")) {
1395 			status = table_statement_parse(&table_spec,
1396 						       &block_mask,
1397 						       tokens,
1398 						       n_tokens,
1399 						       n_lines,
1400 						       err_line,
1401 						       err_msg);
1402 			if (status)
1403 				goto error;
1404 
1405 			continue;
1406 		}
1407 
1408 		/* apply. */
1409 		if (!strcmp(tokens[0], "apply")) {
1410 			status = apply_statement_parse(&block_mask,
1411 						       tokens,
1412 						       n_tokens,
1413 						       n_lines,
1414 						       err_line,
1415 						       err_msg);
1416 			if (status)
1417 				goto error;
1418 
1419 			continue;
1420 		}
1421 
1422 		/* Anything else. */
1423 		if (err_line)
1424 			*err_line = n_lines;
1425 		if (err_msg)
1426 			*err_msg = "Unknown statement.";
1427 		status = -EINVAL;
1428 		goto error;
1429 	}
1430 
1431 	/* Handle unfinished block. */
1432 	if (block_mask) {
1433 		if (err_line)
1434 			*err_line = n_lines;
1435 		if (err_msg)
1436 			*err_msg = "Missing }.";
1437 		status = -EINVAL;
1438 		goto error;
1439 	}
1440 
1441 	/* Pipeline build. */
1442 	status = rte_swx_pipeline_build(p);
1443 	if (status) {
1444 		if (err_line)
1445 			*err_line = n_lines;
1446 		if (err_msg)
1447 			*err_msg = "Pipeline build error.";
1448 		goto error;
1449 	}
1450 
1451 	return 0;
1452 
1453 error:
1454 	extobj_spec_free(&extobj_spec);
1455 	struct_spec_free(&struct_spec);
1456 	header_spec_free(&header_spec);
1457 	metadata_spec_free(&metadata_spec);
1458 	action_spec_free(&action_spec);
1459 	table_spec_free(&table_spec);
1460 	apply_spec_free(&apply_spec);
1461 	return status;
1462 }
1463