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