xref: /dpdk/lib/pipeline/rte_swx_pipeline.c (revision 3b78aa7b2317fb385ed7fa5f5535f60050ede618)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <errno.h>
7 #include <dlfcn.h>
8 
9 #include <rte_swx_port_ethdev.h>
10 #include <rte_swx_port_fd.h>
11 #include <rte_swx_port_ring.h>
12 #include "rte_swx_port_source_sink.h"
13 
14 #include <rte_swx_table_em.h>
15 #include <rte_swx_table_wm.h>
16 
17 #include "rte_swx_pipeline_internal.h"
18 
19 #define CHECK(condition, err_code)                                             \
20 do {                                                                           \
21 	if (!(condition))                                                      \
22 		return -(err_code);                                            \
23 } while (0)
24 
25 #define CHECK_NAME(name, err_code)                                             \
26 	CHECK((name) &&                                                        \
27 	      (name)[0] &&                                                     \
28 	      (strnlen((name), RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE),        \
29 	      err_code)
30 
31 #define CHECK_INSTRUCTION(instr, err_code)                                     \
32 	CHECK((instr) &&                                                       \
33 	      (instr)[0] &&                                                    \
34 	      (strnlen((instr), RTE_SWX_INSTRUCTION_SIZE) <                    \
35 	       RTE_SWX_INSTRUCTION_SIZE),                                      \
36 	      err_code)
37 
38 /*
39  * Environment.
40  */
41 #ifndef RTE_SWX_PIPELINE_HUGE_PAGES_DISABLE
42 
43 #include <rte_malloc.h>
44 
45 static void *
46 env_malloc(size_t size, size_t alignment, int numa_node)
47 {
48 	return rte_zmalloc_socket(NULL, size, alignment, numa_node);
49 }
50 
51 static void
52 env_free(void *start, size_t size __rte_unused)
53 {
54 	rte_free(start);
55 }
56 
57 #else
58 
59 #include <numa.h>
60 
61 static void *
62 env_malloc(size_t size, size_t alignment __rte_unused, int numa_node)
63 {
64 	void *start;
65 
66 	if (numa_available() == -1)
67 		return NULL;
68 
69 	start = numa_alloc_onnode(size, numa_node);
70 	if (!start)
71 		return NULL;
72 
73 	memset(start, 0, size);
74 	return start;
75 }
76 
77 static void
78 env_free(void *start, size_t size)
79 {
80 	if (numa_available() == -1)
81 		return;
82 
83 	numa_free(start, size);
84 }
85 
86 #endif
87 
88 /*
89  * Struct.
90  */
91 static struct struct_type *
92 struct_type_find(struct rte_swx_pipeline *p, const char *name)
93 {
94 	struct struct_type *elem;
95 
96 	TAILQ_FOREACH(elem, &p->struct_types, node)
97 		if (strcmp(elem->name, name) == 0)
98 			return elem;
99 
100 	return NULL;
101 }
102 
103 static struct field *
104 struct_type_field_find(struct struct_type *st, const char *name)
105 {
106 	uint32_t i;
107 
108 	for (i = 0; i < st->n_fields; i++) {
109 		struct field *f = &st->fields[i];
110 
111 		if (strcmp(f->name, name) == 0)
112 			return f;
113 	}
114 
115 	return NULL;
116 }
117 
118 int
119 rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
120 				      const char *name,
121 				      struct rte_swx_field_params *fields,
122 				      uint32_t n_fields,
123 				      int last_field_has_variable_size)
124 {
125 	struct struct_type *st;
126 	uint32_t i;
127 
128 	CHECK(p, EINVAL);
129 	CHECK_NAME(name, EINVAL);
130 	CHECK(fields, EINVAL);
131 	CHECK(n_fields, EINVAL);
132 
133 	for (i = 0; i < n_fields; i++) {
134 		struct rte_swx_field_params *f = &fields[i];
135 		int var_size = ((i == n_fields - 1) && last_field_has_variable_size) ? 1 : 0;
136 		uint32_t j;
137 
138 		CHECK_NAME(f->name, EINVAL);
139 		CHECK(f->n_bits, EINVAL);
140 		CHECK((f->n_bits <= 64) || var_size, EINVAL);
141 		CHECK((f->n_bits & 7) == 0, EINVAL);
142 
143 		for (j = 0; j < i; j++) {
144 			struct rte_swx_field_params *f_prev = &fields[j];
145 
146 			CHECK(strcmp(f->name, f_prev->name), EINVAL);
147 		}
148 	}
149 
150 	CHECK(!struct_type_find(p, name), EEXIST);
151 
152 	/* Node allocation. */
153 	st = calloc(1, sizeof(struct struct_type));
154 	CHECK(st, ENOMEM);
155 
156 	st->fields = calloc(n_fields, sizeof(struct field));
157 	if (!st->fields) {
158 		free(st);
159 		CHECK(0, ENOMEM);
160 	}
161 
162 	/* Node initialization. */
163 	strcpy(st->name, name);
164 	for (i = 0; i < n_fields; i++) {
165 		struct field *dst = &st->fields[i];
166 		struct rte_swx_field_params *src = &fields[i];
167 		int var_size = ((i == n_fields - 1) && last_field_has_variable_size) ? 1 : 0;
168 
169 		strcpy(dst->name, src->name);
170 		dst->n_bits = src->n_bits;
171 		dst->offset = st->n_bits;
172 		dst->var_size = var_size;
173 
174 		st->n_bits += src->n_bits;
175 		st->n_bits_min += var_size ? 0 : src->n_bits;
176 	}
177 	st->n_fields = n_fields;
178 	st->var_size = last_field_has_variable_size;
179 
180 	/* Node add to tailq. */
181 	TAILQ_INSERT_TAIL(&p->struct_types, st, node);
182 
183 	return 0;
184 }
185 
186 static int
187 struct_build(struct rte_swx_pipeline *p)
188 {
189 	uint32_t i;
190 
191 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
192 		struct thread *t = &p->threads[i];
193 
194 		t->structs = calloc(p->n_structs, sizeof(uint8_t *));
195 		CHECK(t->structs, ENOMEM);
196 	}
197 
198 	return 0;
199 }
200 
201 static void
202 struct_build_free(struct rte_swx_pipeline *p)
203 {
204 	uint32_t i;
205 
206 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
207 		struct thread *t = &p->threads[i];
208 
209 		free(t->structs);
210 		t->structs = NULL;
211 	}
212 }
213 
214 static void
215 struct_free(struct rte_swx_pipeline *p)
216 {
217 	struct_build_free(p);
218 
219 	/* Struct types. */
220 	for ( ; ; ) {
221 		struct struct_type *elem;
222 
223 		elem = TAILQ_FIRST(&p->struct_types);
224 		if (!elem)
225 			break;
226 
227 		TAILQ_REMOVE(&p->struct_types, elem, node);
228 		free(elem->fields);
229 		free(elem);
230 	}
231 }
232 
233 /*
234  * Input port.
235  */
236 static struct port_in_type *
237 port_in_type_find(struct rte_swx_pipeline *p, const char *name)
238 {
239 	struct port_in_type *elem;
240 
241 	if (!name)
242 		return NULL;
243 
244 	TAILQ_FOREACH(elem, &p->port_in_types, node)
245 		if (strcmp(elem->name, name) == 0)
246 			return elem;
247 
248 	return NULL;
249 }
250 
251 int
252 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
253 				       const char *name,
254 				       struct rte_swx_port_in_ops *ops)
255 {
256 	struct port_in_type *elem;
257 
258 	CHECK(p, EINVAL);
259 	CHECK_NAME(name, EINVAL);
260 	CHECK(ops, EINVAL);
261 	CHECK(ops->create, EINVAL);
262 	CHECK(ops->free, EINVAL);
263 	CHECK(ops->pkt_rx, EINVAL);
264 	CHECK(ops->stats_read, EINVAL);
265 
266 	CHECK(!port_in_type_find(p, name), EEXIST);
267 
268 	/* Node allocation. */
269 	elem = calloc(1, sizeof(struct port_in_type));
270 	CHECK(elem, ENOMEM);
271 
272 	/* Node initialization. */
273 	strcpy(elem->name, name);
274 	memcpy(&elem->ops, ops, sizeof(*ops));
275 
276 	/* Node add to tailq. */
277 	TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
278 
279 	return 0;
280 }
281 
282 static struct port_in *
283 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
284 {
285 	struct port_in *port;
286 
287 	TAILQ_FOREACH(port, &p->ports_in, node)
288 		if (port->id == port_id)
289 			return port;
290 
291 	return NULL;
292 }
293 
294 int
295 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
296 				uint32_t port_id,
297 				const char *port_type_name,
298 				void *args)
299 {
300 	struct port_in_type *type = NULL;
301 	struct port_in *port = NULL;
302 	void *obj = NULL;
303 
304 	CHECK(p, EINVAL);
305 
306 	CHECK(!port_in_find(p, port_id), EINVAL);
307 
308 	CHECK_NAME(port_type_name, EINVAL);
309 	type = port_in_type_find(p, port_type_name);
310 	CHECK(type, EINVAL);
311 
312 	obj = type->ops.create(args);
313 	CHECK(obj, ENODEV);
314 
315 	/* Node allocation. */
316 	port = calloc(1, sizeof(struct port_in));
317 	CHECK(port, ENOMEM);
318 
319 	/* Node initialization. */
320 	port->type = type;
321 	port->obj = obj;
322 	port->id = port_id;
323 
324 	/* Node add to tailq. */
325 	TAILQ_INSERT_TAIL(&p->ports_in, port, node);
326 	if (p->n_ports_in < port_id + 1)
327 		p->n_ports_in = port_id + 1;
328 
329 	return 0;
330 }
331 
332 static int
333 port_in_build(struct rte_swx_pipeline *p)
334 {
335 	struct port_in *port;
336 	uint32_t i;
337 
338 	CHECK(p->n_ports_in, EINVAL);
339 	CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
340 
341 	for (i = 0; i < p->n_ports_in; i++)
342 		CHECK(port_in_find(p, i), EINVAL);
343 
344 	p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
345 	CHECK(p->in, ENOMEM);
346 
347 	TAILQ_FOREACH(port, &p->ports_in, node) {
348 		struct port_in_runtime *in = &p->in[port->id];
349 
350 		in->pkt_rx = port->type->ops.pkt_rx;
351 		in->obj = port->obj;
352 	}
353 
354 	return 0;
355 }
356 
357 static void
358 port_in_build_free(struct rte_swx_pipeline *p)
359 {
360 	free(p->in);
361 	p->in = NULL;
362 }
363 
364 static void
365 port_in_free(struct rte_swx_pipeline *p)
366 {
367 	port_in_build_free(p);
368 
369 	/* Input ports. */
370 	for ( ; ; ) {
371 		struct port_in *port;
372 
373 		port = TAILQ_FIRST(&p->ports_in);
374 		if (!port)
375 			break;
376 
377 		TAILQ_REMOVE(&p->ports_in, port, node);
378 		port->type->ops.free(port->obj);
379 		free(port);
380 	}
381 
382 	/* Input port types. */
383 	for ( ; ; ) {
384 		struct port_in_type *elem;
385 
386 		elem = TAILQ_FIRST(&p->port_in_types);
387 		if (!elem)
388 			break;
389 
390 		TAILQ_REMOVE(&p->port_in_types, elem, node);
391 		free(elem);
392 	}
393 }
394 
395 /*
396  * Output port.
397  */
398 static struct port_out_type *
399 port_out_type_find(struct rte_swx_pipeline *p, const char *name)
400 {
401 	struct port_out_type *elem;
402 
403 	if (!name)
404 		return NULL;
405 
406 	TAILQ_FOREACH(elem, &p->port_out_types, node)
407 		if (!strcmp(elem->name, name))
408 			return elem;
409 
410 	return NULL;
411 }
412 
413 int
414 rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p,
415 					const char *name,
416 					struct rte_swx_port_out_ops *ops)
417 {
418 	struct port_out_type *elem;
419 
420 	CHECK(p, EINVAL);
421 	CHECK_NAME(name, EINVAL);
422 	CHECK(ops, EINVAL);
423 	CHECK(ops->create, EINVAL);
424 	CHECK(ops->free, EINVAL);
425 	CHECK(ops->pkt_tx, EINVAL);
426 	CHECK(ops->stats_read, EINVAL);
427 
428 	CHECK(!port_out_type_find(p, name), EEXIST);
429 
430 	/* Node allocation. */
431 	elem = calloc(1, sizeof(struct port_out_type));
432 	CHECK(elem, ENOMEM);
433 
434 	/* Node initialization. */
435 	strcpy(elem->name, name);
436 	memcpy(&elem->ops, ops, sizeof(*ops));
437 
438 	/* Node add to tailq. */
439 	TAILQ_INSERT_TAIL(&p->port_out_types, elem, node);
440 
441 	return 0;
442 }
443 
444 static struct port_out *
445 port_out_find(struct rte_swx_pipeline *p, uint32_t port_id)
446 {
447 	struct port_out *port;
448 
449 	TAILQ_FOREACH(port, &p->ports_out, node)
450 		if (port->id == port_id)
451 			return port;
452 
453 	return NULL;
454 }
455 
456 int
457 rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
458 				 uint32_t port_id,
459 				 const char *port_type_name,
460 				 void *args)
461 {
462 	struct port_out_type *type = NULL;
463 	struct port_out *port = NULL;
464 	void *obj = NULL;
465 
466 	CHECK(p, EINVAL);
467 
468 	CHECK(!port_out_find(p, port_id), EINVAL);
469 
470 	CHECK_NAME(port_type_name, EINVAL);
471 	type = port_out_type_find(p, port_type_name);
472 	CHECK(type, EINVAL);
473 
474 	obj = type->ops.create(args);
475 	CHECK(obj, ENODEV);
476 
477 	/* Node allocation. */
478 	port = calloc(1, sizeof(struct port_out));
479 	CHECK(port, ENOMEM);
480 
481 	/* Node initialization. */
482 	port->type = type;
483 	port->obj = obj;
484 	port->id = port_id;
485 
486 	/* Node add to tailq. */
487 	TAILQ_INSERT_TAIL(&p->ports_out, port, node);
488 	if (p->n_ports_out < port_id + 1)
489 		p->n_ports_out = port_id + 1;
490 
491 	return 0;
492 }
493 
494 static int
495 port_out_build(struct rte_swx_pipeline *p)
496 {
497 	struct port_out *port;
498 	uint32_t i;
499 
500 	CHECK(p->n_ports_out, EINVAL);
501 
502 	for (i = 0; i < p->n_ports_out; i++)
503 		CHECK(port_out_find(p, i), EINVAL);
504 
505 	p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime));
506 	CHECK(p->out, ENOMEM);
507 
508 	TAILQ_FOREACH(port, &p->ports_out, node) {
509 		struct port_out_runtime *out = &p->out[port->id];
510 
511 		out->pkt_tx = port->type->ops.pkt_tx;
512 		out->flush = port->type->ops.flush;
513 		out->obj = port->obj;
514 	}
515 
516 	return 0;
517 }
518 
519 static void
520 port_out_build_free(struct rte_swx_pipeline *p)
521 {
522 	free(p->out);
523 	p->out = NULL;
524 }
525 
526 static void
527 port_out_free(struct rte_swx_pipeline *p)
528 {
529 	port_out_build_free(p);
530 
531 	/* Output ports. */
532 	for ( ; ; ) {
533 		struct port_out *port;
534 
535 		port = TAILQ_FIRST(&p->ports_out);
536 		if (!port)
537 			break;
538 
539 		TAILQ_REMOVE(&p->ports_out, port, node);
540 		port->type->ops.free(port->obj);
541 		free(port);
542 	}
543 
544 	/* Output port types. */
545 	for ( ; ; ) {
546 		struct port_out_type *elem;
547 
548 		elem = TAILQ_FIRST(&p->port_out_types);
549 		if (!elem)
550 			break;
551 
552 		TAILQ_REMOVE(&p->port_out_types, elem, node);
553 		free(elem);
554 	}
555 }
556 
557 /*
558  * Extern object.
559  */
560 static struct extern_type *
561 extern_type_find(struct rte_swx_pipeline *p, const char *name)
562 {
563 	struct extern_type *elem;
564 
565 	TAILQ_FOREACH(elem, &p->extern_types, node)
566 		if (strcmp(elem->name, name) == 0)
567 			return elem;
568 
569 	return NULL;
570 }
571 
572 static struct extern_type_member_func *
573 extern_type_member_func_find(struct extern_type *type, const char *name)
574 {
575 	struct extern_type_member_func *elem;
576 
577 	TAILQ_FOREACH(elem, &type->funcs, node)
578 		if (strcmp(elem->name, name) == 0)
579 			return elem;
580 
581 	return NULL;
582 }
583 
584 static struct extern_obj *
585 extern_obj_find(struct rte_swx_pipeline *p, const char *name)
586 {
587 	struct extern_obj *elem;
588 
589 	TAILQ_FOREACH(elem, &p->extern_objs, node)
590 		if (strcmp(elem->name, name) == 0)
591 			return elem;
592 
593 	return NULL;
594 }
595 
596 static struct extern_type_member_func *
597 extern_obj_member_func_parse(struct rte_swx_pipeline *p,
598 			     const char *name,
599 			     struct extern_obj **obj)
600 {
601 	struct extern_obj *object;
602 	struct extern_type_member_func *func;
603 	char *object_name, *func_name;
604 
605 	if (name[0] != 'e' || name[1] != '.')
606 		return NULL;
607 
608 	object_name = strdup(&name[2]);
609 	if (!object_name)
610 		return NULL;
611 
612 	func_name = strchr(object_name, '.');
613 	if (!func_name) {
614 		free(object_name);
615 		return NULL;
616 	}
617 
618 	*func_name = 0;
619 	func_name++;
620 
621 	object = extern_obj_find(p, object_name);
622 	if (!object) {
623 		free(object_name);
624 		return NULL;
625 	}
626 
627 	func = extern_type_member_func_find(object->type, func_name);
628 	if (!func) {
629 		free(object_name);
630 		return NULL;
631 	}
632 
633 	if (obj)
634 		*obj = object;
635 
636 	free(object_name);
637 	return func;
638 }
639 
640 static struct field *
641 extern_obj_mailbox_field_parse(struct rte_swx_pipeline *p,
642 			       const char *name,
643 			       struct extern_obj **object)
644 {
645 	struct extern_obj *obj;
646 	struct field *f;
647 	char *obj_name, *field_name;
648 
649 	if ((name[0] != 'e') || (name[1] != '.'))
650 		return NULL;
651 
652 	obj_name = strdup(&name[2]);
653 	if (!obj_name)
654 		return NULL;
655 
656 	field_name = strchr(obj_name, '.');
657 	if (!field_name) {
658 		free(obj_name);
659 		return NULL;
660 	}
661 
662 	*field_name = 0;
663 	field_name++;
664 
665 	obj = extern_obj_find(p, obj_name);
666 	if (!obj) {
667 		free(obj_name);
668 		return NULL;
669 	}
670 
671 	f = struct_type_field_find(obj->type->mailbox_struct_type, field_name);
672 	if (!f) {
673 		free(obj_name);
674 		return NULL;
675 	}
676 
677 	if (object)
678 		*object = obj;
679 
680 	free(obj_name);
681 	return f;
682 }
683 
684 int
685 rte_swx_pipeline_extern_type_register(struct rte_swx_pipeline *p,
686 	const char *name,
687 	const char *mailbox_struct_type_name,
688 	rte_swx_extern_type_constructor_t constructor,
689 	rte_swx_extern_type_destructor_t destructor)
690 {
691 	struct extern_type *elem;
692 	struct struct_type *mailbox_struct_type;
693 
694 	CHECK(p, EINVAL);
695 
696 	CHECK_NAME(name, EINVAL);
697 	CHECK(!extern_type_find(p, name), EEXIST);
698 
699 	CHECK_NAME(mailbox_struct_type_name, EINVAL);
700 	mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
701 	CHECK(mailbox_struct_type, EINVAL);
702 	CHECK(!mailbox_struct_type->var_size, EINVAL);
703 
704 	CHECK(constructor, EINVAL);
705 	CHECK(destructor, EINVAL);
706 
707 	/* Node allocation. */
708 	elem = calloc(1, sizeof(struct extern_type));
709 	CHECK(elem, ENOMEM);
710 
711 	/* Node initialization. */
712 	strcpy(elem->name, name);
713 	elem->mailbox_struct_type = mailbox_struct_type;
714 	elem->constructor = constructor;
715 	elem->destructor = destructor;
716 	TAILQ_INIT(&elem->funcs);
717 
718 	/* Node add to tailq. */
719 	TAILQ_INSERT_TAIL(&p->extern_types, elem, node);
720 
721 	return 0;
722 }
723 
724 int
725 rte_swx_pipeline_extern_type_member_func_register(struct rte_swx_pipeline *p,
726 	const char *extern_type_name,
727 	const char *name,
728 	rte_swx_extern_type_member_func_t member_func)
729 {
730 	struct extern_type *type;
731 	struct extern_type_member_func *type_member;
732 
733 	CHECK(p, EINVAL);
734 
735 	CHECK_NAME(extern_type_name, EINVAL);
736 	type = extern_type_find(p, extern_type_name);
737 	CHECK(type, EINVAL);
738 	CHECK(type->n_funcs < RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX, ENOSPC);
739 
740 	CHECK_NAME(name, EINVAL);
741 	CHECK(!extern_type_member_func_find(type, name), EEXIST);
742 
743 	CHECK(member_func, EINVAL);
744 
745 	/* Node allocation. */
746 	type_member = calloc(1, sizeof(struct extern_type_member_func));
747 	CHECK(type_member, ENOMEM);
748 
749 	/* Node initialization. */
750 	strcpy(type_member->name, name);
751 	type_member->func = member_func;
752 	type_member->id = type->n_funcs;
753 
754 	/* Node add to tailq. */
755 	TAILQ_INSERT_TAIL(&type->funcs, type_member, node);
756 	type->n_funcs++;
757 
758 	return 0;
759 }
760 
761 int
762 rte_swx_pipeline_extern_object_config(struct rte_swx_pipeline *p,
763 				      const char *extern_type_name,
764 				      const char *name,
765 				      const char *args)
766 {
767 	struct extern_type *type;
768 	struct extern_obj *obj;
769 	void *obj_handle;
770 
771 	CHECK(p, EINVAL);
772 
773 	CHECK_NAME(extern_type_name, EINVAL);
774 	type = extern_type_find(p, extern_type_name);
775 	CHECK(type, EINVAL);
776 
777 	CHECK_NAME(name, EINVAL);
778 	CHECK(!extern_obj_find(p, name), EEXIST);
779 
780 	/* Node allocation. */
781 	obj = calloc(1, sizeof(struct extern_obj));
782 	CHECK(obj, ENOMEM);
783 
784 	/* Object construction. */
785 	obj_handle = type->constructor(args);
786 	if (!obj_handle) {
787 		free(obj);
788 		CHECK(0, ENODEV);
789 	}
790 
791 	/* Node initialization. */
792 	strcpy(obj->name, name);
793 	obj->type = type;
794 	obj->obj = obj_handle;
795 	obj->struct_id = p->n_structs;
796 	obj->id = p->n_extern_objs;
797 
798 	/* Node add to tailq. */
799 	TAILQ_INSERT_TAIL(&p->extern_objs, obj, node);
800 	p->n_extern_objs++;
801 	p->n_structs++;
802 
803 	return 0;
804 }
805 
806 static int
807 extern_obj_build(struct rte_swx_pipeline *p)
808 {
809 	uint32_t i;
810 
811 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
812 		struct thread *t = &p->threads[i];
813 		struct extern_obj *obj;
814 
815 		t->extern_objs = calloc(p->n_extern_objs,
816 					sizeof(struct extern_obj_runtime));
817 		CHECK(t->extern_objs, ENOMEM);
818 
819 		TAILQ_FOREACH(obj, &p->extern_objs, node) {
820 			struct extern_obj_runtime *r =
821 				&t->extern_objs[obj->id];
822 			struct extern_type_member_func *func;
823 			uint32_t mailbox_size =
824 				obj->type->mailbox_struct_type->n_bits / 8;
825 
826 			r->obj = obj->obj;
827 
828 			r->mailbox = calloc(1, mailbox_size);
829 			CHECK(r->mailbox, ENOMEM);
830 
831 			TAILQ_FOREACH(func, &obj->type->funcs, node)
832 				r->funcs[func->id] = func->func;
833 
834 			t->structs[obj->struct_id] = r->mailbox;
835 		}
836 	}
837 
838 	return 0;
839 }
840 
841 static void
842 extern_obj_build_free(struct rte_swx_pipeline *p)
843 {
844 	uint32_t i;
845 
846 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
847 		struct thread *t = &p->threads[i];
848 		uint32_t j;
849 
850 		if (!t->extern_objs)
851 			continue;
852 
853 		for (j = 0; j < p->n_extern_objs; j++) {
854 			struct extern_obj_runtime *r = &t->extern_objs[j];
855 
856 			free(r->mailbox);
857 		}
858 
859 		free(t->extern_objs);
860 		t->extern_objs = NULL;
861 	}
862 }
863 
864 static void
865 extern_obj_free(struct rte_swx_pipeline *p)
866 {
867 	extern_obj_build_free(p);
868 
869 	/* Extern objects. */
870 	for ( ; ; ) {
871 		struct extern_obj *elem;
872 
873 		elem = TAILQ_FIRST(&p->extern_objs);
874 		if (!elem)
875 			break;
876 
877 		TAILQ_REMOVE(&p->extern_objs, elem, node);
878 		if (elem->obj)
879 			elem->type->destructor(elem->obj);
880 		free(elem);
881 	}
882 
883 	/* Extern types. */
884 	for ( ; ; ) {
885 		struct extern_type *elem;
886 
887 		elem = TAILQ_FIRST(&p->extern_types);
888 		if (!elem)
889 			break;
890 
891 		TAILQ_REMOVE(&p->extern_types, elem, node);
892 
893 		for ( ; ; ) {
894 			struct extern_type_member_func *func;
895 
896 			func = TAILQ_FIRST(&elem->funcs);
897 			if (!func)
898 				break;
899 
900 			TAILQ_REMOVE(&elem->funcs, func, node);
901 			free(func);
902 		}
903 
904 		free(elem);
905 	}
906 }
907 
908 /*
909  * Extern function.
910  */
911 static struct extern_func *
912 extern_func_find(struct rte_swx_pipeline *p, const char *name)
913 {
914 	struct extern_func *elem;
915 
916 	TAILQ_FOREACH(elem, &p->extern_funcs, node)
917 		if (strcmp(elem->name, name) == 0)
918 			return elem;
919 
920 	return NULL;
921 }
922 
923 static struct extern_func *
924 extern_func_parse(struct rte_swx_pipeline *p,
925 		  const char *name)
926 {
927 	if (name[0] != 'f' || name[1] != '.')
928 		return NULL;
929 
930 	return extern_func_find(p, &name[2]);
931 }
932 
933 static struct field *
934 extern_func_mailbox_field_parse(struct rte_swx_pipeline *p,
935 				const char *name,
936 				struct extern_func **function)
937 {
938 	struct extern_func *func;
939 	struct field *f;
940 	char *func_name, *field_name;
941 
942 	if ((name[0] != 'f') || (name[1] != '.'))
943 		return NULL;
944 
945 	func_name = strdup(&name[2]);
946 	if (!func_name)
947 		return NULL;
948 
949 	field_name = strchr(func_name, '.');
950 	if (!field_name) {
951 		free(func_name);
952 		return NULL;
953 	}
954 
955 	*field_name = 0;
956 	field_name++;
957 
958 	func = extern_func_find(p, func_name);
959 	if (!func) {
960 		free(func_name);
961 		return NULL;
962 	}
963 
964 	f = struct_type_field_find(func->mailbox_struct_type, field_name);
965 	if (!f) {
966 		free(func_name);
967 		return NULL;
968 	}
969 
970 	if (function)
971 		*function = func;
972 
973 	free(func_name);
974 	return f;
975 }
976 
977 int
978 rte_swx_pipeline_extern_func_register(struct rte_swx_pipeline *p,
979 				      const char *name,
980 				      const char *mailbox_struct_type_name,
981 				      rte_swx_extern_func_t func)
982 {
983 	struct extern_func *f;
984 	struct struct_type *mailbox_struct_type;
985 
986 	CHECK(p, EINVAL);
987 
988 	CHECK_NAME(name, EINVAL);
989 	CHECK(!extern_func_find(p, name), EEXIST);
990 
991 	CHECK_NAME(mailbox_struct_type_name, EINVAL);
992 	mailbox_struct_type = struct_type_find(p, mailbox_struct_type_name);
993 	CHECK(mailbox_struct_type, EINVAL);
994 	CHECK(!mailbox_struct_type->var_size, EINVAL);
995 
996 	CHECK(func, EINVAL);
997 
998 	/* Node allocation. */
999 	f = calloc(1, sizeof(struct extern_func));
1000 	CHECK(func, ENOMEM);
1001 
1002 	/* Node initialization. */
1003 	strcpy(f->name, name);
1004 	f->mailbox_struct_type = mailbox_struct_type;
1005 	f->func = func;
1006 	f->struct_id = p->n_structs;
1007 	f->id = p->n_extern_funcs;
1008 
1009 	/* Node add to tailq. */
1010 	TAILQ_INSERT_TAIL(&p->extern_funcs, f, node);
1011 	p->n_extern_funcs++;
1012 	p->n_structs++;
1013 
1014 	return 0;
1015 }
1016 
1017 static int
1018 extern_func_build(struct rte_swx_pipeline *p)
1019 {
1020 	uint32_t i;
1021 
1022 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1023 		struct thread *t = &p->threads[i];
1024 		struct extern_func *func;
1025 
1026 		/* Memory allocation. */
1027 		t->extern_funcs = calloc(p->n_extern_funcs,
1028 					 sizeof(struct extern_func_runtime));
1029 		CHECK(t->extern_funcs, ENOMEM);
1030 
1031 		/* Extern function. */
1032 		TAILQ_FOREACH(func, &p->extern_funcs, node) {
1033 			struct extern_func_runtime *r =
1034 				&t->extern_funcs[func->id];
1035 			uint32_t mailbox_size =
1036 				func->mailbox_struct_type->n_bits / 8;
1037 
1038 			r->func = func->func;
1039 
1040 			r->mailbox = calloc(1, mailbox_size);
1041 			CHECK(r->mailbox, ENOMEM);
1042 
1043 			t->structs[func->struct_id] = r->mailbox;
1044 		}
1045 	}
1046 
1047 	return 0;
1048 }
1049 
1050 static void
1051 extern_func_build_free(struct rte_swx_pipeline *p)
1052 {
1053 	uint32_t i;
1054 
1055 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1056 		struct thread *t = &p->threads[i];
1057 		uint32_t j;
1058 
1059 		if (!t->extern_funcs)
1060 			continue;
1061 
1062 		for (j = 0; j < p->n_extern_funcs; j++) {
1063 			struct extern_func_runtime *r = &t->extern_funcs[j];
1064 
1065 			free(r->mailbox);
1066 		}
1067 
1068 		free(t->extern_funcs);
1069 		t->extern_funcs = NULL;
1070 	}
1071 }
1072 
1073 static void
1074 extern_func_free(struct rte_swx_pipeline *p)
1075 {
1076 	extern_func_build_free(p);
1077 
1078 	for ( ; ; ) {
1079 		struct extern_func *elem;
1080 
1081 		elem = TAILQ_FIRST(&p->extern_funcs);
1082 		if (!elem)
1083 			break;
1084 
1085 		TAILQ_REMOVE(&p->extern_funcs, elem, node);
1086 		free(elem);
1087 	}
1088 }
1089 
1090 /*
1091  * Header.
1092  */
1093 static struct header *
1094 header_find(struct rte_swx_pipeline *p, const char *name)
1095 {
1096 	struct header *elem;
1097 
1098 	TAILQ_FOREACH(elem, &p->headers, node)
1099 		if (strcmp(elem->name, name) == 0)
1100 			return elem;
1101 
1102 	return NULL;
1103 }
1104 
1105 static struct header *
1106 header_find_by_struct_id(struct rte_swx_pipeline *p, uint32_t struct_id)
1107 {
1108 	struct header *elem;
1109 
1110 	TAILQ_FOREACH(elem, &p->headers, node)
1111 		if (elem->struct_id == struct_id)
1112 			return elem;
1113 
1114 	return NULL;
1115 }
1116 
1117 static struct header *
1118 header_parse(struct rte_swx_pipeline *p,
1119 	     const char *name)
1120 {
1121 	if (name[0] != 'h' || name[1] != '.')
1122 		return NULL;
1123 
1124 	return header_find(p, &name[2]);
1125 }
1126 
1127 static struct field *
1128 header_field_parse(struct rte_swx_pipeline *p,
1129 		   const char *name,
1130 		   struct header **header)
1131 {
1132 	struct header *h;
1133 	struct field *f;
1134 	char *header_name, *field_name;
1135 
1136 	if ((name[0] != 'h') || (name[1] != '.'))
1137 		return NULL;
1138 
1139 	header_name = strdup(&name[2]);
1140 	if (!header_name)
1141 		return NULL;
1142 
1143 	field_name = strchr(header_name, '.');
1144 	if (!field_name) {
1145 		free(header_name);
1146 		return NULL;
1147 	}
1148 
1149 	*field_name = 0;
1150 	field_name++;
1151 
1152 	h = header_find(p, header_name);
1153 	if (!h) {
1154 		free(header_name);
1155 		return NULL;
1156 	}
1157 
1158 	f = struct_type_field_find(h->st, field_name);
1159 	if (!f) {
1160 		free(header_name);
1161 		return NULL;
1162 	}
1163 
1164 	if (header)
1165 		*header = h;
1166 
1167 	free(header_name);
1168 	return f;
1169 }
1170 
1171 int
1172 rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
1173 					const char *name,
1174 					const char *struct_type_name)
1175 {
1176 	struct struct_type *st;
1177 	struct header *h;
1178 	size_t n_headers_max;
1179 
1180 	CHECK(p, EINVAL);
1181 	CHECK_NAME(name, EINVAL);
1182 	CHECK_NAME(struct_type_name, EINVAL);
1183 
1184 	CHECK(!header_find(p, name), EEXIST);
1185 
1186 	st = struct_type_find(p, struct_type_name);
1187 	CHECK(st, EINVAL);
1188 
1189 	n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
1190 	CHECK(p->n_headers < n_headers_max, ENOSPC);
1191 
1192 	/* Node allocation. */
1193 	h = calloc(1, sizeof(struct header));
1194 	CHECK(h, ENOMEM);
1195 
1196 	/* Node initialization. */
1197 	strcpy(h->name, name);
1198 	h->st = st;
1199 	h->struct_id = p->n_structs;
1200 	h->id = p->n_headers;
1201 
1202 	/* Node add to tailq. */
1203 	TAILQ_INSERT_TAIL(&p->headers, h, node);
1204 	p->n_headers++;
1205 	p->n_structs++;
1206 
1207 	return 0;
1208 }
1209 
1210 static int
1211 header_build(struct rte_swx_pipeline *p)
1212 {
1213 	struct header *h;
1214 	uint32_t n_bytes = 0, i;
1215 
1216 	TAILQ_FOREACH(h, &p->headers, node) {
1217 		n_bytes += h->st->n_bits / 8;
1218 	}
1219 
1220 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1221 		struct thread *t = &p->threads[i];
1222 		uint32_t offset = 0;
1223 
1224 		t->headers = calloc(p->n_headers,
1225 				    sizeof(struct header_runtime));
1226 		CHECK(t->headers, ENOMEM);
1227 
1228 		t->headers_out = calloc(p->n_headers,
1229 					sizeof(struct header_out_runtime));
1230 		CHECK(t->headers_out, ENOMEM);
1231 
1232 		t->header_storage = calloc(1, n_bytes);
1233 		CHECK(t->header_storage, ENOMEM);
1234 
1235 		t->header_out_storage = calloc(1, n_bytes);
1236 		CHECK(t->header_out_storage, ENOMEM);
1237 
1238 		TAILQ_FOREACH(h, &p->headers, node) {
1239 			uint8_t *header_storage;
1240 			uint32_t n_bytes =  h->st->n_bits / 8;
1241 
1242 			header_storage = &t->header_storage[offset];
1243 			offset += n_bytes;
1244 
1245 			t->headers[h->id].ptr0 = header_storage;
1246 			t->headers[h->id].n_bytes = n_bytes;
1247 
1248 			t->structs[h->struct_id] = header_storage;
1249 		}
1250 	}
1251 
1252 	return 0;
1253 }
1254 
1255 static void
1256 header_build_free(struct rte_swx_pipeline *p)
1257 {
1258 	uint32_t i;
1259 
1260 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1261 		struct thread *t = &p->threads[i];
1262 
1263 		free(t->headers_out);
1264 		t->headers_out = NULL;
1265 
1266 		free(t->headers);
1267 		t->headers = NULL;
1268 
1269 		free(t->header_out_storage);
1270 		t->header_out_storage = NULL;
1271 
1272 		free(t->header_storage);
1273 		t->header_storage = NULL;
1274 	}
1275 }
1276 
1277 static void
1278 header_free(struct rte_swx_pipeline *p)
1279 {
1280 	header_build_free(p);
1281 
1282 	for ( ; ; ) {
1283 		struct header *elem;
1284 
1285 		elem = TAILQ_FIRST(&p->headers);
1286 		if (!elem)
1287 			break;
1288 
1289 		TAILQ_REMOVE(&p->headers, elem, node);
1290 		free(elem);
1291 	}
1292 }
1293 
1294 /*
1295  * Meta-data.
1296  */
1297 static struct field *
1298 metadata_field_parse(struct rte_swx_pipeline *p, const char *name)
1299 {
1300 	if (!p->metadata_st)
1301 		return NULL;
1302 
1303 	if (name[0] != 'm' || name[1] != '.')
1304 		return NULL;
1305 
1306 	return struct_type_field_find(p->metadata_st, &name[2]);
1307 }
1308 
1309 int
1310 rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
1311 					  const char *struct_type_name)
1312 {
1313 	struct struct_type *st = NULL;
1314 
1315 	CHECK(p, EINVAL);
1316 
1317 	CHECK_NAME(struct_type_name, EINVAL);
1318 	st  = struct_type_find(p, struct_type_name);
1319 	CHECK(st, EINVAL);
1320 	CHECK(!st->var_size, EINVAL);
1321 	CHECK(!p->metadata_st, EINVAL);
1322 
1323 	p->metadata_st = st;
1324 	p->metadata_struct_id = p->n_structs;
1325 
1326 	p->n_structs++;
1327 
1328 	return 0;
1329 }
1330 
1331 static int
1332 metadata_build(struct rte_swx_pipeline *p)
1333 {
1334 	uint32_t n_bytes = p->metadata_st->n_bits / 8;
1335 	uint32_t i;
1336 
1337 	/* Thread-level initialization. */
1338 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1339 		struct thread *t = &p->threads[i];
1340 		uint8_t *metadata;
1341 
1342 		metadata = calloc(1, n_bytes);
1343 		CHECK(metadata, ENOMEM);
1344 
1345 		t->metadata = metadata;
1346 		t->structs[p->metadata_struct_id] = metadata;
1347 	}
1348 
1349 	return 0;
1350 }
1351 
1352 static void
1353 metadata_build_free(struct rte_swx_pipeline *p)
1354 {
1355 	uint32_t i;
1356 
1357 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
1358 		struct thread *t = &p->threads[i];
1359 
1360 		free(t->metadata);
1361 		t->metadata = NULL;
1362 	}
1363 }
1364 
1365 static void
1366 metadata_free(struct rte_swx_pipeline *p)
1367 {
1368 	metadata_build_free(p);
1369 }
1370 
1371 /*
1372  * Instruction.
1373  */
1374 static int
1375 instruction_is_tx(enum instruction_type type)
1376 {
1377 	switch (type) {
1378 	case INSTR_TX:
1379 	case INSTR_TX_I:
1380 	case INSTR_DROP:
1381 		return 1;
1382 
1383 	default:
1384 		return 0;
1385 	}
1386 }
1387 
1388 static int
1389 instruction_does_tx(struct instruction *instr)
1390 {
1391 	switch (instr->type) {
1392 	case INSTR_TX:
1393 	case INSTR_TX_I:
1394 	case INSTR_DROP:
1395 	case INSTR_HDR_EMIT_TX:
1396 	case INSTR_HDR_EMIT2_TX:
1397 	case INSTR_HDR_EMIT3_TX:
1398 	case INSTR_HDR_EMIT4_TX:
1399 	case INSTR_HDR_EMIT5_TX:
1400 	case INSTR_HDR_EMIT6_TX:
1401 	case INSTR_HDR_EMIT7_TX:
1402 	case INSTR_HDR_EMIT8_TX:
1403 		return 1;
1404 	default:
1405 		return 0;
1406 	}
1407 }
1408 
1409 static int
1410 instruction_is_jmp(struct instruction *instr)
1411 {
1412 	switch (instr->type) {
1413 	case INSTR_JMP:
1414 	case INSTR_JMP_VALID:
1415 	case INSTR_JMP_INVALID:
1416 	case INSTR_JMP_HIT:
1417 	case INSTR_JMP_MISS:
1418 	case INSTR_JMP_ACTION_HIT:
1419 	case INSTR_JMP_ACTION_MISS:
1420 	case INSTR_JMP_EQ:
1421 	case INSTR_JMP_EQ_MH:
1422 	case INSTR_JMP_EQ_HM:
1423 	case INSTR_JMP_EQ_HH:
1424 	case INSTR_JMP_EQ_I:
1425 	case INSTR_JMP_NEQ:
1426 	case INSTR_JMP_NEQ_MH:
1427 	case INSTR_JMP_NEQ_HM:
1428 	case INSTR_JMP_NEQ_HH:
1429 	case INSTR_JMP_NEQ_I:
1430 	case INSTR_JMP_LT:
1431 	case INSTR_JMP_LT_MH:
1432 	case INSTR_JMP_LT_HM:
1433 	case INSTR_JMP_LT_HH:
1434 	case INSTR_JMP_LT_MI:
1435 	case INSTR_JMP_LT_HI:
1436 	case INSTR_JMP_GT:
1437 	case INSTR_JMP_GT_MH:
1438 	case INSTR_JMP_GT_HM:
1439 	case INSTR_JMP_GT_HH:
1440 	case INSTR_JMP_GT_MI:
1441 	case INSTR_JMP_GT_HI:
1442 		return 1;
1443 
1444 	default:
1445 		return 0;
1446 	}
1447 }
1448 
1449 static int
1450 instruction_does_thread_yield(struct instruction *instr)
1451 {
1452 	switch (instr->type) {
1453 	case INSTR_RX:
1454 	case INSTR_TABLE:
1455 	case INSTR_TABLE_AF:
1456 	case INSTR_SELECTOR:
1457 	case INSTR_LEARNER:
1458 	case INSTR_LEARNER_AF:
1459 	case INSTR_EXTERN_OBJ:
1460 	case INSTR_EXTERN_FUNC:
1461 		return 1;
1462 	default:
1463 		return 0;
1464 	}
1465 }
1466 
1467 static struct field *
1468 action_field_parse(struct action *action, const char *name);
1469 
1470 static struct field *
1471 struct_field_parse(struct rte_swx_pipeline *p,
1472 		   struct action *action,
1473 		   const char *name,
1474 		   uint32_t *struct_id)
1475 {
1476 	struct field *f;
1477 
1478 	switch (name[0]) {
1479 	case 'h':
1480 	{
1481 		struct header *header;
1482 
1483 		f = header_field_parse(p, name, &header);
1484 		if (!f)
1485 			return NULL;
1486 
1487 		*struct_id = header->struct_id;
1488 		return f;
1489 	}
1490 
1491 	case 'm':
1492 	{
1493 		f = metadata_field_parse(p, name);
1494 		if (!f)
1495 			return NULL;
1496 
1497 		*struct_id = p->metadata_struct_id;
1498 		return f;
1499 	}
1500 
1501 	case 't':
1502 	{
1503 		if (!action)
1504 			return NULL;
1505 
1506 		f = action_field_parse(action, name);
1507 		if (!f)
1508 			return NULL;
1509 
1510 		*struct_id = 0;
1511 		return f;
1512 	}
1513 
1514 	case 'e':
1515 	{
1516 		struct extern_obj *obj;
1517 
1518 		f = extern_obj_mailbox_field_parse(p, name, &obj);
1519 		if (!f)
1520 			return NULL;
1521 
1522 		*struct_id = obj->struct_id;
1523 		return f;
1524 	}
1525 
1526 	case 'f':
1527 	{
1528 		struct extern_func *func;
1529 
1530 		f = extern_func_mailbox_field_parse(p, name, &func);
1531 		if (!f)
1532 			return NULL;
1533 
1534 		*struct_id = func->struct_id;
1535 		return f;
1536 	}
1537 
1538 	default:
1539 		return NULL;
1540 	}
1541 }
1542 
1543 /*
1544  * rx.
1545  */
1546 static int
1547 instr_rx_translate(struct rte_swx_pipeline *p,
1548 		   struct action *action,
1549 		   char **tokens,
1550 		   int n_tokens,
1551 		   struct instruction *instr,
1552 		   struct instruction_data *data __rte_unused)
1553 {
1554 	struct field *f;
1555 
1556 	CHECK(!action, EINVAL);
1557 	CHECK(n_tokens == 2, EINVAL);
1558 
1559 	f = metadata_field_parse(p, tokens[1]);
1560 	CHECK(f, EINVAL);
1561 
1562 	instr->type = INSTR_RX;
1563 	instr->io.io.offset = f->offset / 8;
1564 	instr->io.io.n_bits = f->n_bits;
1565 	return 0;
1566 }
1567 
1568 /*
1569  * tx.
1570  */
1571 static int
1572 instr_tx_translate(struct rte_swx_pipeline *p,
1573 		   struct action *action __rte_unused,
1574 		   char **tokens,
1575 		   int n_tokens,
1576 		   struct instruction *instr,
1577 		   struct instruction_data *data __rte_unused)
1578 {
1579 	char *port = tokens[1];
1580 	struct field *f;
1581 	uint32_t port_val;
1582 
1583 	CHECK(n_tokens == 2, EINVAL);
1584 
1585 	f = metadata_field_parse(p, port);
1586 	if (f) {
1587 		instr->type = INSTR_TX;
1588 		instr->io.io.offset = f->offset / 8;
1589 		instr->io.io.n_bits = f->n_bits;
1590 		return 0;
1591 	}
1592 
1593 	/* TX_I. */
1594 	port_val = strtoul(port, &port, 0);
1595 	CHECK(!port[0], EINVAL);
1596 
1597 	instr->type = INSTR_TX_I;
1598 	instr->io.io.val = port_val;
1599 	return 0;
1600 }
1601 
1602 static int
1603 instr_drop_translate(struct rte_swx_pipeline *p __rte_unused,
1604 		     struct action *action __rte_unused,
1605 		     char **tokens __rte_unused,
1606 		     int n_tokens,
1607 		     struct instruction *instr,
1608 		     struct instruction_data *data __rte_unused)
1609 {
1610 	CHECK(n_tokens == 1, EINVAL);
1611 
1612 	/* DROP. */
1613 	instr->type = INSTR_DROP;
1614 	return 0;
1615 }
1616 
1617 static inline void
1618 instr_tx_exec(struct rte_swx_pipeline *p)
1619 {
1620 	struct thread *t = &p->threads[p->thread_id];
1621 	struct instruction *ip = t->ip;
1622 
1623 	__instr_tx_exec(p, t, ip);
1624 
1625 	/* Thread. */
1626 	thread_ip_reset(p, t);
1627 	instr_rx_exec(p);
1628 }
1629 
1630 static inline void
1631 instr_tx_i_exec(struct rte_swx_pipeline *p)
1632 {
1633 	struct thread *t = &p->threads[p->thread_id];
1634 	struct instruction *ip = t->ip;
1635 
1636 	__instr_tx_i_exec(p, t, ip);
1637 
1638 	/* Thread. */
1639 	thread_ip_reset(p, t);
1640 	instr_rx_exec(p);
1641 }
1642 
1643 static inline void
1644 instr_drop_exec(struct rte_swx_pipeline *p)
1645 {
1646 	struct thread *t = &p->threads[p->thread_id];
1647 	struct instruction *ip = t->ip;
1648 
1649 	__instr_drop_exec(p, t, ip);
1650 
1651 	/* Thread. */
1652 	thread_ip_reset(p, t);
1653 	instr_rx_exec(p);
1654 }
1655 
1656 /*
1657  * extract.
1658  */
1659 static int
1660 instr_hdr_extract_translate(struct rte_swx_pipeline *p,
1661 			    struct action *action,
1662 			    char **tokens,
1663 			    int n_tokens,
1664 			    struct instruction *instr,
1665 			    struct instruction_data *data __rte_unused)
1666 {
1667 	struct header *h;
1668 
1669 	CHECK(!action, EINVAL);
1670 	CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL);
1671 
1672 	h = header_parse(p, tokens[1]);
1673 	CHECK(h, EINVAL);
1674 
1675 	if (n_tokens == 2) {
1676 		CHECK(!h->st->var_size, EINVAL);
1677 
1678 		instr->type = INSTR_HDR_EXTRACT;
1679 		instr->io.hdr.header_id[0] = h->id;
1680 		instr->io.hdr.struct_id[0] = h->struct_id;
1681 		instr->io.hdr.n_bytes[0] = h->st->n_bits / 8;
1682 	} else {
1683 		struct field *mf;
1684 
1685 		CHECK(h->st->var_size, EINVAL);
1686 
1687 		mf = metadata_field_parse(p, tokens[2]);
1688 		CHECK(mf, EINVAL);
1689 		CHECK(!mf->var_size, EINVAL);
1690 
1691 		instr->type = INSTR_HDR_EXTRACT_M;
1692 		instr->io.io.offset = mf->offset / 8;
1693 		instr->io.io.n_bits = mf->n_bits;
1694 		instr->io.hdr.header_id[0] = h->id;
1695 		instr->io.hdr.struct_id[0] = h->struct_id;
1696 		instr->io.hdr.n_bytes[0] = h->st->n_bits_min / 8;
1697 	}
1698 
1699 	return 0;
1700 }
1701 
1702 static int
1703 instr_hdr_lookahead_translate(struct rte_swx_pipeline *p,
1704 			      struct action *action,
1705 			      char **tokens,
1706 			      int n_tokens,
1707 			      struct instruction *instr,
1708 			      struct instruction_data *data __rte_unused)
1709 {
1710 	struct header *h;
1711 
1712 	CHECK(!action, EINVAL);
1713 	CHECK(n_tokens == 2, EINVAL);
1714 
1715 	h = header_parse(p, tokens[1]);
1716 	CHECK(h, EINVAL);
1717 	CHECK(!h->st->var_size, EINVAL);
1718 
1719 	instr->type = INSTR_HDR_LOOKAHEAD;
1720 	instr->io.hdr.header_id[0] = h->id;
1721 	instr->io.hdr.struct_id[0] = h->struct_id;
1722 	instr->io.hdr.n_bytes[0] = 0; /* Unused. */
1723 
1724 	return 0;
1725 }
1726 
1727 static inline void
1728 instr_hdr_extract_exec(struct rte_swx_pipeline *p)
1729 {
1730 	struct thread *t = &p->threads[p->thread_id];
1731 	struct instruction *ip = t->ip;
1732 
1733 	__instr_hdr_extract_exec(p, t, ip);
1734 
1735 	/* Thread. */
1736 	thread_ip_inc(p);
1737 }
1738 
1739 static inline void
1740 instr_hdr_extract2_exec(struct rte_swx_pipeline *p)
1741 {
1742 	struct thread *t = &p->threads[p->thread_id];
1743 	struct instruction *ip = t->ip;
1744 
1745 	__instr_hdr_extract2_exec(p, t, ip);
1746 
1747 	/* Thread. */
1748 	thread_ip_inc(p);
1749 }
1750 
1751 static inline void
1752 instr_hdr_extract3_exec(struct rte_swx_pipeline *p)
1753 {
1754 	struct thread *t = &p->threads[p->thread_id];
1755 	struct instruction *ip = t->ip;
1756 
1757 	__instr_hdr_extract3_exec(p, t, ip);
1758 
1759 	/* Thread. */
1760 	thread_ip_inc(p);
1761 }
1762 
1763 static inline void
1764 instr_hdr_extract4_exec(struct rte_swx_pipeline *p)
1765 {
1766 	struct thread *t = &p->threads[p->thread_id];
1767 	struct instruction *ip = t->ip;
1768 
1769 	__instr_hdr_extract4_exec(p, t, ip);
1770 
1771 	/* Thread. */
1772 	thread_ip_inc(p);
1773 }
1774 
1775 static inline void
1776 instr_hdr_extract5_exec(struct rte_swx_pipeline *p)
1777 {
1778 	struct thread *t = &p->threads[p->thread_id];
1779 	struct instruction *ip = t->ip;
1780 
1781 	__instr_hdr_extract5_exec(p, t, ip);
1782 
1783 	/* Thread. */
1784 	thread_ip_inc(p);
1785 }
1786 
1787 static inline void
1788 instr_hdr_extract6_exec(struct rte_swx_pipeline *p)
1789 {
1790 	struct thread *t = &p->threads[p->thread_id];
1791 	struct instruction *ip = t->ip;
1792 
1793 	__instr_hdr_extract6_exec(p, t, ip);
1794 
1795 	/* Thread. */
1796 	thread_ip_inc(p);
1797 }
1798 
1799 static inline void
1800 instr_hdr_extract7_exec(struct rte_swx_pipeline *p)
1801 {
1802 	struct thread *t = &p->threads[p->thread_id];
1803 	struct instruction *ip = t->ip;
1804 
1805 	__instr_hdr_extract7_exec(p, t, ip);
1806 
1807 	/* Thread. */
1808 	thread_ip_inc(p);
1809 }
1810 
1811 static inline void
1812 instr_hdr_extract8_exec(struct rte_swx_pipeline *p)
1813 {
1814 	struct thread *t = &p->threads[p->thread_id];
1815 	struct instruction *ip = t->ip;
1816 
1817 	__instr_hdr_extract8_exec(p, t, ip);
1818 
1819 	/* Thread. */
1820 	thread_ip_inc(p);
1821 }
1822 
1823 static inline void
1824 instr_hdr_extract_m_exec(struct rte_swx_pipeline *p)
1825 {
1826 	struct thread *t = &p->threads[p->thread_id];
1827 	struct instruction *ip = t->ip;
1828 
1829 	__instr_hdr_extract_m_exec(p, t, ip);
1830 
1831 	/* Thread. */
1832 	thread_ip_inc(p);
1833 }
1834 
1835 static inline void
1836 instr_hdr_lookahead_exec(struct rte_swx_pipeline *p)
1837 {
1838 	struct thread *t = &p->threads[p->thread_id];
1839 	struct instruction *ip = t->ip;
1840 
1841 	__instr_hdr_lookahead_exec(p, t, ip);
1842 
1843 	/* Thread. */
1844 	thread_ip_inc(p);
1845 }
1846 
1847 /*
1848  * emit.
1849  */
1850 static int
1851 instr_hdr_emit_translate(struct rte_swx_pipeline *p,
1852 			 struct action *action __rte_unused,
1853 			 char **tokens,
1854 			 int n_tokens,
1855 			 struct instruction *instr,
1856 			 struct instruction_data *data __rte_unused)
1857 {
1858 	struct header *h;
1859 
1860 	CHECK(n_tokens == 2, EINVAL);
1861 
1862 	h = header_parse(p, tokens[1]);
1863 	CHECK(h, EINVAL);
1864 
1865 	instr->type = INSTR_HDR_EMIT;
1866 	instr->io.hdr.header_id[0] = h->id;
1867 	instr->io.hdr.struct_id[0] = h->struct_id;
1868 	instr->io.hdr.n_bytes[0] = h->st->n_bits / 8;
1869 	return 0;
1870 }
1871 
1872 static inline void
1873 instr_hdr_emit_exec(struct rte_swx_pipeline *p)
1874 {
1875 	struct thread *t = &p->threads[p->thread_id];
1876 	struct instruction *ip = t->ip;
1877 
1878 	__instr_hdr_emit_exec(p, t, ip);
1879 
1880 	/* Thread. */
1881 	thread_ip_inc(p);
1882 }
1883 
1884 static inline void
1885 instr_hdr_emit_tx_exec(struct rte_swx_pipeline *p)
1886 {
1887 	struct thread *t = &p->threads[p->thread_id];
1888 	struct instruction *ip = t->ip;
1889 
1890 	__instr_hdr_emit_tx_exec(p, t, ip);
1891 
1892 	/* Thread. */
1893 	thread_ip_reset(p, t);
1894 	instr_rx_exec(p);
1895 }
1896 
1897 static inline void
1898 instr_hdr_emit2_tx_exec(struct rte_swx_pipeline *p)
1899 {
1900 	struct thread *t = &p->threads[p->thread_id];
1901 	struct instruction *ip = t->ip;
1902 
1903 	__instr_hdr_emit2_tx_exec(p, t, ip);
1904 
1905 	/* Thread. */
1906 	thread_ip_reset(p, t);
1907 	instr_rx_exec(p);
1908 }
1909 
1910 static inline void
1911 instr_hdr_emit3_tx_exec(struct rte_swx_pipeline *p)
1912 {
1913 	struct thread *t = &p->threads[p->thread_id];
1914 	struct instruction *ip = t->ip;
1915 
1916 	__instr_hdr_emit3_tx_exec(p, t, ip);
1917 
1918 	/* Thread. */
1919 	thread_ip_reset(p, t);
1920 	instr_rx_exec(p);
1921 }
1922 
1923 static inline void
1924 instr_hdr_emit4_tx_exec(struct rte_swx_pipeline *p)
1925 {
1926 	struct thread *t = &p->threads[p->thread_id];
1927 	struct instruction *ip = t->ip;
1928 
1929 	__instr_hdr_emit4_tx_exec(p, t, ip);
1930 
1931 	/* Thread. */
1932 	thread_ip_reset(p, t);
1933 	instr_rx_exec(p);
1934 }
1935 
1936 static inline void
1937 instr_hdr_emit5_tx_exec(struct rte_swx_pipeline *p)
1938 {
1939 	struct thread *t = &p->threads[p->thread_id];
1940 	struct instruction *ip = t->ip;
1941 
1942 	__instr_hdr_emit5_tx_exec(p, t, ip);
1943 
1944 	/* Thread. */
1945 	thread_ip_reset(p, t);
1946 	instr_rx_exec(p);
1947 }
1948 
1949 static inline void
1950 instr_hdr_emit6_tx_exec(struct rte_swx_pipeline *p)
1951 {
1952 	struct thread *t = &p->threads[p->thread_id];
1953 	struct instruction *ip = t->ip;
1954 
1955 	__instr_hdr_emit6_tx_exec(p, t, ip);
1956 
1957 	/* Thread. */
1958 	thread_ip_reset(p, t);
1959 	instr_rx_exec(p);
1960 }
1961 
1962 static inline void
1963 instr_hdr_emit7_tx_exec(struct rte_swx_pipeline *p)
1964 {
1965 	struct thread *t = &p->threads[p->thread_id];
1966 	struct instruction *ip = t->ip;
1967 
1968 	__instr_hdr_emit7_tx_exec(p, t, ip);
1969 
1970 	/* Thread. */
1971 	thread_ip_reset(p, t);
1972 	instr_rx_exec(p);
1973 }
1974 
1975 static inline void
1976 instr_hdr_emit8_tx_exec(struct rte_swx_pipeline *p)
1977 {
1978 	struct thread *t = &p->threads[p->thread_id];
1979 	struct instruction *ip = t->ip;
1980 
1981 	__instr_hdr_emit8_tx_exec(p, t, ip);
1982 
1983 	/* Thread. */
1984 	thread_ip_reset(p, t);
1985 	instr_rx_exec(p);
1986 }
1987 
1988 /*
1989  * validate.
1990  */
1991 static int
1992 instr_hdr_validate_translate(struct rte_swx_pipeline *p,
1993 			     struct action *action __rte_unused,
1994 			     char **tokens,
1995 			     int n_tokens,
1996 			     struct instruction *instr,
1997 			     struct instruction_data *data __rte_unused)
1998 {
1999 	struct header *h;
2000 
2001 	CHECK(n_tokens == 2, EINVAL);
2002 
2003 	h = header_parse(p, tokens[1]);
2004 	CHECK(h, EINVAL);
2005 
2006 	instr->type = INSTR_HDR_VALIDATE;
2007 	instr->valid.header_id = h->id;
2008 	return 0;
2009 }
2010 
2011 static inline void
2012 instr_hdr_validate_exec(struct rte_swx_pipeline *p)
2013 {
2014 	struct thread *t = &p->threads[p->thread_id];
2015 	struct instruction *ip = t->ip;
2016 
2017 	__instr_hdr_validate_exec(p, t, ip);
2018 
2019 	/* Thread. */
2020 	thread_ip_inc(p);
2021 }
2022 
2023 /*
2024  * invalidate.
2025  */
2026 static int
2027 instr_hdr_invalidate_translate(struct rte_swx_pipeline *p,
2028 			       struct action *action __rte_unused,
2029 			       char **tokens,
2030 			       int n_tokens,
2031 			       struct instruction *instr,
2032 			       struct instruction_data *data __rte_unused)
2033 {
2034 	struct header *h;
2035 
2036 	CHECK(n_tokens == 2, EINVAL);
2037 
2038 	h = header_parse(p, tokens[1]);
2039 	CHECK(h, EINVAL);
2040 
2041 	instr->type = INSTR_HDR_INVALIDATE;
2042 	instr->valid.header_id = h->id;
2043 	return 0;
2044 }
2045 
2046 static inline void
2047 instr_hdr_invalidate_exec(struct rte_swx_pipeline *p)
2048 {
2049 	struct thread *t = &p->threads[p->thread_id];
2050 	struct instruction *ip = t->ip;
2051 
2052 	__instr_hdr_invalidate_exec(p, t, ip);
2053 
2054 	/* Thread. */
2055 	thread_ip_inc(p);
2056 }
2057 
2058 /*
2059  * table.
2060  */
2061 static struct table *
2062 table_find(struct rte_swx_pipeline *p, const char *name);
2063 
2064 static struct selector *
2065 selector_find(struct rte_swx_pipeline *p, const char *name);
2066 
2067 static struct learner *
2068 learner_find(struct rte_swx_pipeline *p, const char *name);
2069 
2070 static int
2071 instr_table_translate(struct rte_swx_pipeline *p,
2072 		      struct action *action,
2073 		      char **tokens,
2074 		      int n_tokens,
2075 		      struct instruction *instr,
2076 		      struct instruction_data *data __rte_unused)
2077 {
2078 	struct table *t;
2079 	struct selector *s;
2080 	struct learner *l;
2081 
2082 	CHECK(!action, EINVAL);
2083 	CHECK(n_tokens == 2, EINVAL);
2084 
2085 	t = table_find(p, tokens[1]);
2086 	if (t) {
2087 		instr->type = INSTR_TABLE;
2088 		instr->table.table_id = t->id;
2089 		return 0;
2090 	}
2091 
2092 	s = selector_find(p, tokens[1]);
2093 	if (s) {
2094 		instr->type = INSTR_SELECTOR;
2095 		instr->table.table_id = s->id;
2096 		return 0;
2097 	}
2098 
2099 	l = learner_find(p, tokens[1]);
2100 	if (l) {
2101 		instr->type = INSTR_LEARNER;
2102 		instr->table.table_id = l->id;
2103 		return 0;
2104 	}
2105 
2106 	CHECK(0, EINVAL);
2107 }
2108 
2109 static inline void
2110 instr_table_exec(struct rte_swx_pipeline *p)
2111 {
2112 	struct thread *t = &p->threads[p->thread_id];
2113 	struct instruction *ip = t->ip;
2114 	uint32_t table_id = ip->table.table_id;
2115 	struct rte_swx_table_state *ts = &t->table_state[table_id];
2116 	struct table_runtime *table = &t->tables[table_id];
2117 	struct table_statistics *stats = &p->table_stats[table_id];
2118 	uint64_t action_id, n_pkts_hit, n_pkts_action;
2119 	uint8_t *action_data;
2120 	int done, hit;
2121 
2122 	/* Table. */
2123 	done = table->func(ts->obj,
2124 			   table->mailbox,
2125 			   table->key,
2126 			   &action_id,
2127 			   &action_data,
2128 			   &hit);
2129 	if (!done) {
2130 		/* Thread. */
2131 		TRACE("[Thread %2u] table %u (not finalized)\n",
2132 		      p->thread_id,
2133 		      table_id);
2134 
2135 		thread_yield(p);
2136 		return;
2137 	}
2138 
2139 	action_id = hit ? action_id : ts->default_action_id;
2140 	action_data = hit ? action_data : ts->default_action_data;
2141 	n_pkts_hit = stats->n_pkts_hit[hit];
2142 	n_pkts_action = stats->n_pkts_action[action_id];
2143 
2144 	TRACE("[Thread %2u] table %u (%s, action %u)\n",
2145 	      p->thread_id,
2146 	      table_id,
2147 	      hit ? "hit" : "miss",
2148 	      (uint32_t)action_id);
2149 
2150 	t->action_id = action_id;
2151 	t->structs[0] = action_data;
2152 	t->hit = hit;
2153 	stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2154 	stats->n_pkts_action[action_id] = n_pkts_action + 1;
2155 
2156 	/* Thread. */
2157 	thread_ip_action_call(p, t, action_id);
2158 }
2159 
2160 static inline void
2161 instr_table_af_exec(struct rte_swx_pipeline *p)
2162 {
2163 	struct thread *t = &p->threads[p->thread_id];
2164 	struct instruction *ip = t->ip;
2165 	uint32_t table_id = ip->table.table_id;
2166 	struct rte_swx_table_state *ts = &t->table_state[table_id];
2167 	struct table_runtime *table = &t->tables[table_id];
2168 	struct table_statistics *stats = &p->table_stats[table_id];
2169 	uint64_t action_id, n_pkts_hit, n_pkts_action;
2170 	uint8_t *action_data;
2171 	action_func_t action_func;
2172 	int done, hit;
2173 
2174 	/* Table. */
2175 	done = table->func(ts->obj,
2176 			   table->mailbox,
2177 			   table->key,
2178 			   &action_id,
2179 			   &action_data,
2180 			   &hit);
2181 	if (!done) {
2182 		/* Thread. */
2183 		TRACE("[Thread %2u] table %u (not finalized)\n",
2184 		      p->thread_id,
2185 		      table_id);
2186 
2187 		thread_yield(p);
2188 		return;
2189 	}
2190 
2191 	action_id = hit ? action_id : ts->default_action_id;
2192 	action_data = hit ? action_data : ts->default_action_data;
2193 	action_func = p->action_funcs[action_id];
2194 	n_pkts_hit = stats->n_pkts_hit[hit];
2195 	n_pkts_action = stats->n_pkts_action[action_id];
2196 
2197 	TRACE("[Thread %2u] table %u (%s, action %u)\n",
2198 	      p->thread_id,
2199 	      table_id,
2200 	      hit ? "hit" : "miss",
2201 	      (uint32_t)action_id);
2202 
2203 	t->action_id = action_id;
2204 	t->structs[0] = action_data;
2205 	t->hit = hit;
2206 	stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2207 	stats->n_pkts_action[action_id] = n_pkts_action + 1;
2208 
2209 	/* Thread. */
2210 	thread_ip_inc(p);
2211 
2212 	/* Action. */
2213 	action_func(p);
2214 }
2215 
2216 static inline void
2217 instr_selector_exec(struct rte_swx_pipeline *p)
2218 {
2219 	struct thread *t = &p->threads[p->thread_id];
2220 	struct instruction *ip = t->ip;
2221 	uint32_t selector_id = ip->table.table_id;
2222 	struct rte_swx_table_state *ts = &t->table_state[p->n_tables + selector_id];
2223 	struct selector_runtime *selector = &t->selectors[selector_id];
2224 	struct selector_statistics *stats = &p->selector_stats[selector_id];
2225 	uint64_t n_pkts = stats->n_pkts;
2226 	int done;
2227 
2228 	/* Table. */
2229 	done = rte_swx_table_selector_select(ts->obj,
2230 			   selector->mailbox,
2231 			   selector->group_id_buffer,
2232 			   selector->selector_buffer,
2233 			   selector->member_id_buffer);
2234 	if (!done) {
2235 		/* Thread. */
2236 		TRACE("[Thread %2u] selector %u (not finalized)\n",
2237 		      p->thread_id,
2238 		      selector_id);
2239 
2240 		thread_yield(p);
2241 		return;
2242 	}
2243 
2244 
2245 	TRACE("[Thread %2u] selector %u\n",
2246 	      p->thread_id,
2247 	      selector_id);
2248 
2249 	stats->n_pkts = n_pkts + 1;
2250 
2251 	/* Thread. */
2252 	thread_ip_inc(p);
2253 }
2254 
2255 static inline void
2256 instr_learner_exec(struct rte_swx_pipeline *p)
2257 {
2258 	struct thread *t = &p->threads[p->thread_id];
2259 	struct instruction *ip = t->ip;
2260 	uint32_t learner_id = ip->table.table_id;
2261 	struct rte_swx_table_state *ts = &t->table_state[p->n_tables +
2262 		p->n_selectors + learner_id];
2263 	struct learner_runtime *l = &t->learners[learner_id];
2264 	struct learner_statistics *stats = &p->learner_stats[learner_id];
2265 	uint64_t action_id, n_pkts_hit, n_pkts_action, time;
2266 	uint8_t *action_data;
2267 	int done, hit;
2268 
2269 	/* Table. */
2270 	time = rte_get_tsc_cycles();
2271 
2272 	done = rte_swx_table_learner_lookup(ts->obj,
2273 					    l->mailbox,
2274 					    time,
2275 					    l->key,
2276 					    &action_id,
2277 					    &action_data,
2278 					    &hit);
2279 	if (!done) {
2280 		/* Thread. */
2281 		TRACE("[Thread %2u] learner %u (not finalized)\n",
2282 		      p->thread_id,
2283 		      learner_id);
2284 
2285 		thread_yield(p);
2286 		return;
2287 	}
2288 
2289 	action_id = hit ? action_id : ts->default_action_id;
2290 	action_data = hit ? action_data : ts->default_action_data;
2291 	n_pkts_hit = stats->n_pkts_hit[hit];
2292 	n_pkts_action = stats->n_pkts_action[action_id];
2293 
2294 	TRACE("[Thread %2u] learner %u (%s, action %u)\n",
2295 	      p->thread_id,
2296 	      learner_id,
2297 	      hit ? "hit" : "miss",
2298 	      (uint32_t)action_id);
2299 
2300 	t->action_id = action_id;
2301 	t->structs[0] = action_data;
2302 	t->hit = hit;
2303 	t->learner_id = learner_id;
2304 	t->time = time;
2305 	stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2306 	stats->n_pkts_action[action_id] = n_pkts_action + 1;
2307 
2308 	/* Thread. */
2309 	thread_ip_action_call(p, t, action_id);
2310 }
2311 
2312 static inline void
2313 instr_learner_af_exec(struct rte_swx_pipeline *p)
2314 {
2315 	struct thread *t = &p->threads[p->thread_id];
2316 	struct instruction *ip = t->ip;
2317 	uint32_t learner_id = ip->table.table_id;
2318 	struct rte_swx_table_state *ts = &t->table_state[p->n_tables +
2319 		p->n_selectors + learner_id];
2320 	struct learner_runtime *l = &t->learners[learner_id];
2321 	struct learner_statistics *stats = &p->learner_stats[learner_id];
2322 	uint64_t action_id, n_pkts_hit, n_pkts_action, time;
2323 	uint8_t *action_data;
2324 	action_func_t action_func;
2325 	int done, hit;
2326 
2327 	/* Table. */
2328 	time = rte_get_tsc_cycles();
2329 
2330 	done = rte_swx_table_learner_lookup(ts->obj,
2331 					    l->mailbox,
2332 					    time,
2333 					    l->key,
2334 					    &action_id,
2335 					    &action_data,
2336 					    &hit);
2337 	if (!done) {
2338 		/* Thread. */
2339 		TRACE("[Thread %2u] learner %u (not finalized)\n",
2340 		      p->thread_id,
2341 		      learner_id);
2342 
2343 		thread_yield(p);
2344 		return;
2345 	}
2346 
2347 	action_id = hit ? action_id : ts->default_action_id;
2348 	action_data = hit ? action_data : ts->default_action_data;
2349 	action_func = p->action_funcs[action_id];
2350 	n_pkts_hit = stats->n_pkts_hit[hit];
2351 	n_pkts_action = stats->n_pkts_action[action_id];
2352 
2353 	TRACE("[Thread %2u] learner %u (%s, action %u)\n",
2354 	      p->thread_id,
2355 	      learner_id,
2356 	      hit ? "hit" : "miss",
2357 	      (uint32_t)action_id);
2358 
2359 	t->action_id = action_id;
2360 	t->structs[0] = action_data;
2361 	t->hit = hit;
2362 	t->learner_id = learner_id;
2363 	t->time = time;
2364 	stats->n_pkts_hit[hit] = n_pkts_hit + 1;
2365 	stats->n_pkts_action[action_id] = n_pkts_action + 1;
2366 
2367 	/* Thread. */
2368 	thread_ip_action_call(p, t, action_id);
2369 
2370 	/* Action */
2371 	action_func(p);
2372 }
2373 
2374 /*
2375  * learn.
2376  */
2377 static struct action *
2378 action_find(struct rte_swx_pipeline *p, const char *name);
2379 
2380 static int
2381 action_has_nbo_args(struct action *a);
2382 
2383 static int
2384 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name);
2385 
2386 static int
2387 instr_learn_translate(struct rte_swx_pipeline *p,
2388 		      struct action *action,
2389 		      char **tokens,
2390 		      int n_tokens,
2391 		      struct instruction *instr,
2392 		      struct instruction_data *data __rte_unused)
2393 {
2394 	struct action *a;
2395 	const char *mf_name;
2396 	uint32_t mf_offset = 0;
2397 
2398 	CHECK(action, EINVAL);
2399 	CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL);
2400 
2401 	a = action_find(p, tokens[1]);
2402 	CHECK(a, EINVAL);
2403 	CHECK(!action_has_nbo_args(a), EINVAL);
2404 
2405 	mf_name = (n_tokens > 2) ? tokens[2] : NULL;
2406 	CHECK(!learner_action_args_check(p, a, mf_name), EINVAL);
2407 
2408 	if (mf_name) {
2409 		struct field *mf;
2410 
2411 		mf = metadata_field_parse(p, mf_name);
2412 		CHECK(mf, EINVAL);
2413 
2414 		mf_offset = mf->offset / 8;
2415 	}
2416 
2417 	instr->type = INSTR_LEARNER_LEARN;
2418 	instr->learn.action_id = a->id;
2419 	instr->learn.mf_offset = mf_offset;
2420 
2421 	return 0;
2422 }
2423 
2424 static inline void
2425 instr_learn_exec(struct rte_swx_pipeline *p)
2426 {
2427 	struct thread *t = &p->threads[p->thread_id];
2428 	struct instruction *ip = t->ip;
2429 
2430 	__instr_learn_exec(p, t, ip);
2431 
2432 	/* Thread. */
2433 	thread_ip_inc(p);
2434 }
2435 
2436 /*
2437  * forget.
2438  */
2439 static int
2440 instr_forget_translate(struct rte_swx_pipeline *p __rte_unused,
2441 		       struct action *action,
2442 		       char **tokens __rte_unused,
2443 		       int n_tokens,
2444 		       struct instruction *instr,
2445 		       struct instruction_data *data __rte_unused)
2446 {
2447 	CHECK(action, EINVAL);
2448 	CHECK(n_tokens == 1, EINVAL);
2449 
2450 	instr->type = INSTR_LEARNER_FORGET;
2451 
2452 	return 0;
2453 }
2454 
2455 static inline void
2456 instr_forget_exec(struct rte_swx_pipeline *p)
2457 {
2458 	struct thread *t = &p->threads[p->thread_id];
2459 	struct instruction *ip = t->ip;
2460 
2461 	__instr_forget_exec(p, t, ip);
2462 
2463 	/* Thread. */
2464 	thread_ip_inc(p);
2465 }
2466 
2467 /*
2468  * extern.
2469  */
2470 static int
2471 instr_extern_translate(struct rte_swx_pipeline *p,
2472 		       struct action *action __rte_unused,
2473 		       char **tokens,
2474 		       int n_tokens,
2475 		       struct instruction *instr,
2476 		       struct instruction_data *data __rte_unused)
2477 {
2478 	char *token = tokens[1];
2479 
2480 	CHECK(n_tokens == 2, EINVAL);
2481 
2482 	if (token[0] == 'e') {
2483 		struct extern_obj *obj;
2484 		struct extern_type_member_func *func;
2485 
2486 		func = extern_obj_member_func_parse(p, token, &obj);
2487 		CHECK(func, EINVAL);
2488 
2489 		instr->type = INSTR_EXTERN_OBJ;
2490 		instr->ext_obj.ext_obj_id = obj->id;
2491 		instr->ext_obj.func_id = func->id;
2492 
2493 		return 0;
2494 	}
2495 
2496 	if (token[0] == 'f') {
2497 		struct extern_func *func;
2498 
2499 		func = extern_func_parse(p, token);
2500 		CHECK(func, EINVAL);
2501 
2502 		instr->type = INSTR_EXTERN_FUNC;
2503 		instr->ext_func.ext_func_id = func->id;
2504 
2505 		return 0;
2506 	}
2507 
2508 	CHECK(0, EINVAL);
2509 }
2510 
2511 static inline void
2512 instr_extern_obj_exec(struct rte_swx_pipeline *p)
2513 {
2514 	struct thread *t = &p->threads[p->thread_id];
2515 	struct instruction *ip = t->ip;
2516 	uint32_t done;
2517 
2518 	/* Extern object member function execute. */
2519 	done = __instr_extern_obj_exec(p, t, ip);
2520 
2521 	/* Thread. */
2522 	thread_ip_inc_cond(t, done);
2523 	thread_yield_cond(p, done ^ 1);
2524 }
2525 
2526 static inline void
2527 instr_extern_func_exec(struct rte_swx_pipeline *p)
2528 {
2529 	struct thread *t = &p->threads[p->thread_id];
2530 	struct instruction *ip = t->ip;
2531 	uint32_t done;
2532 
2533 	/* Extern function execute. */
2534 	done = __instr_extern_func_exec(p, t, ip);
2535 
2536 	/* Thread. */
2537 	thread_ip_inc_cond(t, done);
2538 	thread_yield_cond(p, done ^ 1);
2539 }
2540 
2541 /*
2542  * mov.
2543  */
2544 static int
2545 instr_mov_translate(struct rte_swx_pipeline *p,
2546 		    struct action *action,
2547 		    char **tokens,
2548 		    int n_tokens,
2549 		    struct instruction *instr,
2550 		    struct instruction_data *data __rte_unused)
2551 {
2552 	char *dst = tokens[1], *src = tokens[2];
2553 	struct field *fdst, *fsrc;
2554 	uint64_t src_val;
2555 	uint32_t dst_struct_id = 0, src_struct_id = 0;
2556 
2557 	CHECK(n_tokens == 3, EINVAL);
2558 
2559 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2560 	CHECK(fdst, EINVAL);
2561 	CHECK(!fdst->var_size, EINVAL);
2562 
2563 	/* MOV, MOV_MH, MOV_HM or MOV_HH. */
2564 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
2565 	if (fsrc) {
2566 		CHECK(!fsrc->var_size, EINVAL);
2567 
2568 		instr->type = INSTR_MOV;
2569 		if (dst[0] != 'h' && src[0] == 'h')
2570 			instr->type = INSTR_MOV_MH;
2571 		if (dst[0] == 'h' && src[0] != 'h')
2572 			instr->type = INSTR_MOV_HM;
2573 		if (dst[0] == 'h' && src[0] == 'h')
2574 			instr->type = INSTR_MOV_HH;
2575 
2576 		instr->mov.dst.struct_id = (uint8_t)dst_struct_id;
2577 		instr->mov.dst.n_bits = fdst->n_bits;
2578 		instr->mov.dst.offset = fdst->offset / 8;
2579 		instr->mov.src.struct_id = (uint8_t)src_struct_id;
2580 		instr->mov.src.n_bits = fsrc->n_bits;
2581 		instr->mov.src.offset = fsrc->offset / 8;
2582 		return 0;
2583 	}
2584 
2585 	/* MOV_I. */
2586 	src_val = strtoull(src, &src, 0);
2587 	CHECK(!src[0], EINVAL);
2588 
2589 	if (dst[0] == 'h')
2590 		src_val = hton64(src_val) >> (64 - fdst->n_bits);
2591 
2592 	instr->type = INSTR_MOV_I;
2593 	instr->mov.dst.struct_id = (uint8_t)dst_struct_id;
2594 	instr->mov.dst.n_bits = fdst->n_bits;
2595 	instr->mov.dst.offset = fdst->offset / 8;
2596 	instr->mov.src_val = src_val;
2597 	return 0;
2598 }
2599 
2600 static inline void
2601 instr_mov_exec(struct rte_swx_pipeline *p)
2602 {
2603 	struct thread *t = &p->threads[p->thread_id];
2604 	struct instruction *ip = t->ip;
2605 
2606 	__instr_mov_exec(p, t, ip);
2607 
2608 	/* Thread. */
2609 	thread_ip_inc(p);
2610 }
2611 
2612 static inline void
2613 instr_mov_mh_exec(struct rte_swx_pipeline *p)
2614 {
2615 	struct thread *t = &p->threads[p->thread_id];
2616 	struct instruction *ip = t->ip;
2617 
2618 	__instr_mov_mh_exec(p, t, ip);
2619 
2620 	/* Thread. */
2621 	thread_ip_inc(p);
2622 }
2623 
2624 static inline void
2625 instr_mov_hm_exec(struct rte_swx_pipeline *p)
2626 {
2627 	struct thread *t = &p->threads[p->thread_id];
2628 	struct instruction *ip = t->ip;
2629 
2630 	__instr_mov_hm_exec(p, t, ip);
2631 
2632 	/* Thread. */
2633 	thread_ip_inc(p);
2634 }
2635 
2636 static inline void
2637 instr_mov_hh_exec(struct rte_swx_pipeline *p)
2638 {
2639 	struct thread *t = &p->threads[p->thread_id];
2640 	struct instruction *ip = t->ip;
2641 
2642 	__instr_mov_hh_exec(p, t, ip);
2643 
2644 	/* Thread. */
2645 	thread_ip_inc(p);
2646 }
2647 
2648 static inline void
2649 instr_mov_i_exec(struct rte_swx_pipeline *p)
2650 {
2651 	struct thread *t = &p->threads[p->thread_id];
2652 	struct instruction *ip = t->ip;
2653 
2654 	__instr_mov_i_exec(p, t, ip);
2655 
2656 	/* Thread. */
2657 	thread_ip_inc(p);
2658 }
2659 
2660 /*
2661  * dma.
2662  */
2663 static inline void
2664 instr_dma_ht_exec(struct rte_swx_pipeline *p)
2665 {
2666 	struct thread *t = &p->threads[p->thread_id];
2667 	struct instruction *ip = t->ip;
2668 
2669 	__instr_dma_ht_exec(p, t, ip);
2670 
2671 	/* Thread. */
2672 	thread_ip_inc(p);
2673 }
2674 
2675 static inline void
2676 instr_dma_ht2_exec(struct rte_swx_pipeline *p)
2677 {
2678 	struct thread *t = &p->threads[p->thread_id];
2679 	struct instruction *ip = t->ip;
2680 
2681 	__instr_dma_ht2_exec(p, t, ip);
2682 
2683 	/* Thread. */
2684 	thread_ip_inc(p);
2685 }
2686 
2687 static inline void
2688 instr_dma_ht3_exec(struct rte_swx_pipeline *p)
2689 {
2690 	struct thread *t = &p->threads[p->thread_id];
2691 	struct instruction *ip = t->ip;
2692 
2693 	__instr_dma_ht3_exec(p, t, ip);
2694 
2695 	/* Thread. */
2696 	thread_ip_inc(p);
2697 }
2698 
2699 static inline void
2700 instr_dma_ht4_exec(struct rte_swx_pipeline *p)
2701 {
2702 	struct thread *t = &p->threads[p->thread_id];
2703 	struct instruction *ip = t->ip;
2704 
2705 	__instr_dma_ht4_exec(p, t, ip);
2706 
2707 	/* Thread. */
2708 	thread_ip_inc(p);
2709 }
2710 
2711 static inline void
2712 instr_dma_ht5_exec(struct rte_swx_pipeline *p)
2713 {
2714 	struct thread *t = &p->threads[p->thread_id];
2715 	struct instruction *ip = t->ip;
2716 
2717 	__instr_dma_ht5_exec(p, t, ip);
2718 
2719 	/* Thread. */
2720 	thread_ip_inc(p);
2721 }
2722 
2723 static inline void
2724 instr_dma_ht6_exec(struct rte_swx_pipeline *p)
2725 {
2726 	struct thread *t = &p->threads[p->thread_id];
2727 	struct instruction *ip = t->ip;
2728 
2729 	__instr_dma_ht6_exec(p, t, ip);
2730 
2731 	/* Thread. */
2732 	thread_ip_inc(p);
2733 }
2734 
2735 static inline void
2736 instr_dma_ht7_exec(struct rte_swx_pipeline *p)
2737 {
2738 	struct thread *t = &p->threads[p->thread_id];
2739 	struct instruction *ip = t->ip;
2740 
2741 	__instr_dma_ht7_exec(p, t, ip);
2742 
2743 	/* Thread. */
2744 	thread_ip_inc(p);
2745 }
2746 
2747 static inline void
2748 instr_dma_ht8_exec(struct rte_swx_pipeline *p)
2749 {
2750 	struct thread *t = &p->threads[p->thread_id];
2751 	struct instruction *ip = t->ip;
2752 
2753 	__instr_dma_ht8_exec(p, t, ip);
2754 
2755 	/* Thread. */
2756 	thread_ip_inc(p);
2757 }
2758 
2759 /*
2760  * alu.
2761  */
2762 static int
2763 instr_alu_add_translate(struct rte_swx_pipeline *p,
2764 			struct action *action,
2765 			char **tokens,
2766 			int n_tokens,
2767 			struct instruction *instr,
2768 			struct instruction_data *data __rte_unused)
2769 {
2770 	char *dst = tokens[1], *src = tokens[2];
2771 	struct field *fdst, *fsrc;
2772 	uint64_t src_val;
2773 	uint32_t dst_struct_id = 0, src_struct_id = 0;
2774 
2775 	CHECK(n_tokens == 3, EINVAL);
2776 
2777 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2778 	CHECK(fdst, EINVAL);
2779 	CHECK(!fdst->var_size, EINVAL);
2780 
2781 	/* ADD, ADD_HM, ADD_MH, ADD_HH. */
2782 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
2783 	if (fsrc) {
2784 		CHECK(!fsrc->var_size, EINVAL);
2785 
2786 		instr->type = INSTR_ALU_ADD;
2787 		if (dst[0] == 'h' && src[0] != 'h')
2788 			instr->type = INSTR_ALU_ADD_HM;
2789 		if (dst[0] != 'h' && src[0] == 'h')
2790 			instr->type = INSTR_ALU_ADD_MH;
2791 		if (dst[0] == 'h' && src[0] == 'h')
2792 			instr->type = INSTR_ALU_ADD_HH;
2793 
2794 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2795 		instr->alu.dst.n_bits = fdst->n_bits;
2796 		instr->alu.dst.offset = fdst->offset / 8;
2797 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
2798 		instr->alu.src.n_bits = fsrc->n_bits;
2799 		instr->alu.src.offset = fsrc->offset / 8;
2800 		return 0;
2801 	}
2802 
2803 	/* ADD_MI, ADD_HI. */
2804 	src_val = strtoull(src, &src, 0);
2805 	CHECK(!src[0], EINVAL);
2806 
2807 	instr->type = INSTR_ALU_ADD_MI;
2808 	if (dst[0] == 'h')
2809 		instr->type = INSTR_ALU_ADD_HI;
2810 
2811 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2812 	instr->alu.dst.n_bits = fdst->n_bits;
2813 	instr->alu.dst.offset = fdst->offset / 8;
2814 	instr->alu.src_val = src_val;
2815 	return 0;
2816 }
2817 
2818 static int
2819 instr_alu_sub_translate(struct rte_swx_pipeline *p,
2820 			struct action *action,
2821 			char **tokens,
2822 			int n_tokens,
2823 			struct instruction *instr,
2824 			struct instruction_data *data __rte_unused)
2825 {
2826 	char *dst = tokens[1], *src = tokens[2];
2827 	struct field *fdst, *fsrc;
2828 	uint64_t src_val;
2829 	uint32_t dst_struct_id = 0, src_struct_id = 0;
2830 
2831 	CHECK(n_tokens == 3, EINVAL);
2832 
2833 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2834 	CHECK(fdst, EINVAL);
2835 	CHECK(!fdst->var_size, EINVAL);
2836 
2837 	/* SUB, SUB_HM, SUB_MH, SUB_HH. */
2838 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
2839 	if (fsrc) {
2840 		CHECK(!fsrc->var_size, EINVAL);
2841 
2842 		instr->type = INSTR_ALU_SUB;
2843 		if (dst[0] == 'h' && src[0] != 'h')
2844 			instr->type = INSTR_ALU_SUB_HM;
2845 		if (dst[0] != 'h' && src[0] == 'h')
2846 			instr->type = INSTR_ALU_SUB_MH;
2847 		if (dst[0] == 'h' && src[0] == 'h')
2848 			instr->type = INSTR_ALU_SUB_HH;
2849 
2850 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2851 		instr->alu.dst.n_bits = fdst->n_bits;
2852 		instr->alu.dst.offset = fdst->offset / 8;
2853 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
2854 		instr->alu.src.n_bits = fsrc->n_bits;
2855 		instr->alu.src.offset = fsrc->offset / 8;
2856 		return 0;
2857 	}
2858 
2859 	/* SUB_MI, SUB_HI. */
2860 	src_val = strtoull(src, &src, 0);
2861 	CHECK(!src[0], EINVAL);
2862 
2863 	instr->type = INSTR_ALU_SUB_MI;
2864 	if (dst[0] == 'h')
2865 		instr->type = INSTR_ALU_SUB_HI;
2866 
2867 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2868 	instr->alu.dst.n_bits = fdst->n_bits;
2869 	instr->alu.dst.offset = fdst->offset / 8;
2870 	instr->alu.src_val = src_val;
2871 	return 0;
2872 }
2873 
2874 static int
2875 instr_alu_ckadd_translate(struct rte_swx_pipeline *p,
2876 			  struct action *action __rte_unused,
2877 			  char **tokens,
2878 			  int n_tokens,
2879 			  struct instruction *instr,
2880 			  struct instruction_data *data __rte_unused)
2881 {
2882 	char *dst = tokens[1], *src = tokens[2];
2883 	struct header *hdst, *hsrc;
2884 	struct field *fdst, *fsrc;
2885 
2886 	CHECK(n_tokens == 3, EINVAL);
2887 
2888 	fdst = header_field_parse(p, dst, &hdst);
2889 	CHECK(fdst, EINVAL);
2890 	CHECK(!fdst->var_size && (fdst->n_bits == 16), EINVAL);
2891 
2892 	/* CKADD_FIELD. */
2893 	fsrc = header_field_parse(p, src, &hsrc);
2894 	if (fsrc) {
2895 		CHECK(!fsrc->var_size, EINVAL);
2896 
2897 		instr->type = INSTR_ALU_CKADD_FIELD;
2898 		instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
2899 		instr->alu.dst.n_bits = fdst->n_bits;
2900 		instr->alu.dst.offset = fdst->offset / 8;
2901 		instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
2902 		instr->alu.src.n_bits = fsrc->n_bits;
2903 		instr->alu.src.offset = fsrc->offset / 8;
2904 		return 0;
2905 	}
2906 
2907 	/* CKADD_STRUCT, CKADD_STRUCT20. */
2908 	hsrc = header_parse(p, src);
2909 	CHECK(hsrc, EINVAL);
2910 
2911 	instr->type = INSTR_ALU_CKADD_STRUCT;
2912 	if (!hsrc->st->var_size && ((hsrc->st->n_bits / 8) == 20))
2913 		instr->type = INSTR_ALU_CKADD_STRUCT20;
2914 
2915 	instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
2916 	instr->alu.dst.n_bits = fdst->n_bits;
2917 	instr->alu.dst.offset = fdst->offset / 8;
2918 	instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
2919 	instr->alu.src.n_bits = (uint8_t)hsrc->id; /* The src header ID is stored here. */
2920 	instr->alu.src.offset = 0; /* Unused. */
2921 	return 0;
2922 }
2923 
2924 static int
2925 instr_alu_cksub_translate(struct rte_swx_pipeline *p,
2926 			  struct action *action __rte_unused,
2927 			  char **tokens,
2928 			  int n_tokens,
2929 			  struct instruction *instr,
2930 			  struct instruction_data *data __rte_unused)
2931 {
2932 	char *dst = tokens[1], *src = tokens[2];
2933 	struct header *hdst, *hsrc;
2934 	struct field *fdst, *fsrc;
2935 
2936 	CHECK(n_tokens == 3, EINVAL);
2937 
2938 	fdst = header_field_parse(p, dst, &hdst);
2939 	CHECK(fdst, EINVAL);
2940 	CHECK(!fdst->var_size && (fdst->n_bits == 16), EINVAL);
2941 
2942 	fsrc = header_field_parse(p, src, &hsrc);
2943 	CHECK(fsrc, EINVAL);
2944 	CHECK(!fsrc->var_size, EINVAL);
2945 
2946 	instr->type = INSTR_ALU_CKSUB_FIELD;
2947 	instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
2948 	instr->alu.dst.n_bits = fdst->n_bits;
2949 	instr->alu.dst.offset = fdst->offset / 8;
2950 	instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
2951 	instr->alu.src.n_bits = fsrc->n_bits;
2952 	instr->alu.src.offset = fsrc->offset / 8;
2953 	return 0;
2954 }
2955 
2956 static int
2957 instr_alu_shl_translate(struct rte_swx_pipeline *p,
2958 			struct action *action,
2959 			char **tokens,
2960 			int n_tokens,
2961 			struct instruction *instr,
2962 			struct instruction_data *data __rte_unused)
2963 {
2964 	char *dst = tokens[1], *src = tokens[2];
2965 	struct field *fdst, *fsrc;
2966 	uint64_t src_val;
2967 	uint32_t dst_struct_id = 0, src_struct_id = 0;
2968 
2969 	CHECK(n_tokens == 3, EINVAL);
2970 
2971 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
2972 	CHECK(fdst, EINVAL);
2973 	CHECK(!fdst->var_size, EINVAL);
2974 
2975 	/* SHL, SHL_HM, SHL_MH, SHL_HH. */
2976 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
2977 	if (fsrc) {
2978 		CHECK(!fsrc->var_size, EINVAL);
2979 
2980 		instr->type = INSTR_ALU_SHL;
2981 		if (dst[0] == 'h' && src[0] != 'h')
2982 			instr->type = INSTR_ALU_SHL_HM;
2983 		if (dst[0] != 'h' && src[0] == 'h')
2984 			instr->type = INSTR_ALU_SHL_MH;
2985 		if (dst[0] == 'h' && src[0] == 'h')
2986 			instr->type = INSTR_ALU_SHL_HH;
2987 
2988 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
2989 		instr->alu.dst.n_bits = fdst->n_bits;
2990 		instr->alu.dst.offset = fdst->offset / 8;
2991 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
2992 		instr->alu.src.n_bits = fsrc->n_bits;
2993 		instr->alu.src.offset = fsrc->offset / 8;
2994 		return 0;
2995 	}
2996 
2997 	/* SHL_MI, SHL_HI. */
2998 	src_val = strtoull(src, &src, 0);
2999 	CHECK(!src[0], EINVAL);
3000 
3001 	instr->type = INSTR_ALU_SHL_MI;
3002 	if (dst[0] == 'h')
3003 		instr->type = INSTR_ALU_SHL_HI;
3004 
3005 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3006 	instr->alu.dst.n_bits = fdst->n_bits;
3007 	instr->alu.dst.offset = fdst->offset / 8;
3008 	instr->alu.src_val = src_val;
3009 	return 0;
3010 }
3011 
3012 static int
3013 instr_alu_shr_translate(struct rte_swx_pipeline *p,
3014 			struct action *action,
3015 			char **tokens,
3016 			int n_tokens,
3017 			struct instruction *instr,
3018 			struct instruction_data *data __rte_unused)
3019 {
3020 	char *dst = tokens[1], *src = tokens[2];
3021 	struct field *fdst, *fsrc;
3022 	uint64_t src_val;
3023 	uint32_t dst_struct_id = 0, src_struct_id = 0;
3024 
3025 	CHECK(n_tokens == 3, EINVAL);
3026 
3027 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3028 	CHECK(fdst, EINVAL);
3029 	CHECK(!fdst->var_size, EINVAL);
3030 
3031 	/* SHR, SHR_HM, SHR_MH, SHR_HH. */
3032 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
3033 	if (fsrc) {
3034 		CHECK(!fsrc->var_size, EINVAL);
3035 
3036 		instr->type = INSTR_ALU_SHR;
3037 		if (dst[0] == 'h' && src[0] != 'h')
3038 			instr->type = INSTR_ALU_SHR_HM;
3039 		if (dst[0] != 'h' && src[0] == 'h')
3040 			instr->type = INSTR_ALU_SHR_MH;
3041 		if (dst[0] == 'h' && src[0] == 'h')
3042 			instr->type = INSTR_ALU_SHR_HH;
3043 
3044 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3045 		instr->alu.dst.n_bits = fdst->n_bits;
3046 		instr->alu.dst.offset = fdst->offset / 8;
3047 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
3048 		instr->alu.src.n_bits = fsrc->n_bits;
3049 		instr->alu.src.offset = fsrc->offset / 8;
3050 		return 0;
3051 	}
3052 
3053 	/* SHR_MI, SHR_HI. */
3054 	src_val = strtoull(src, &src, 0);
3055 	CHECK(!src[0], EINVAL);
3056 
3057 	instr->type = INSTR_ALU_SHR_MI;
3058 	if (dst[0] == 'h')
3059 		instr->type = INSTR_ALU_SHR_HI;
3060 
3061 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3062 	instr->alu.dst.n_bits = fdst->n_bits;
3063 	instr->alu.dst.offset = fdst->offset / 8;
3064 	instr->alu.src_val = src_val;
3065 	return 0;
3066 }
3067 
3068 static int
3069 instr_alu_and_translate(struct rte_swx_pipeline *p,
3070 			struct action *action,
3071 			char **tokens,
3072 			int n_tokens,
3073 			struct instruction *instr,
3074 			struct instruction_data *data __rte_unused)
3075 {
3076 	char *dst = tokens[1], *src = tokens[2];
3077 	struct field *fdst, *fsrc;
3078 	uint64_t src_val;
3079 	uint32_t dst_struct_id = 0, src_struct_id = 0;
3080 
3081 	CHECK(n_tokens == 3, EINVAL);
3082 
3083 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3084 	CHECK(fdst, EINVAL);
3085 	CHECK(!fdst->var_size, EINVAL);
3086 
3087 	/* AND, AND_MH, AND_HM, AND_HH. */
3088 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
3089 	if (fsrc) {
3090 		CHECK(!fsrc->var_size, EINVAL);
3091 
3092 		instr->type = INSTR_ALU_AND;
3093 		if (dst[0] != 'h' && src[0] == 'h')
3094 			instr->type = INSTR_ALU_AND_MH;
3095 		if (dst[0] == 'h' && src[0] != 'h')
3096 			instr->type = INSTR_ALU_AND_HM;
3097 		if (dst[0] == 'h' && src[0] == 'h')
3098 			instr->type = INSTR_ALU_AND_HH;
3099 
3100 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3101 		instr->alu.dst.n_bits = fdst->n_bits;
3102 		instr->alu.dst.offset = fdst->offset / 8;
3103 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
3104 		instr->alu.src.n_bits = fsrc->n_bits;
3105 		instr->alu.src.offset = fsrc->offset / 8;
3106 		return 0;
3107 	}
3108 
3109 	/* AND_I. */
3110 	src_val = strtoull(src, &src, 0);
3111 	CHECK(!src[0], EINVAL);
3112 
3113 	if (dst[0] == 'h')
3114 		src_val = hton64(src_val) >> (64 - fdst->n_bits);
3115 
3116 	instr->type = INSTR_ALU_AND_I;
3117 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3118 	instr->alu.dst.n_bits = fdst->n_bits;
3119 	instr->alu.dst.offset = fdst->offset / 8;
3120 	instr->alu.src_val = src_val;
3121 	return 0;
3122 }
3123 
3124 static int
3125 instr_alu_or_translate(struct rte_swx_pipeline *p,
3126 		       struct action *action,
3127 		       char **tokens,
3128 		       int n_tokens,
3129 		       struct instruction *instr,
3130 		       struct instruction_data *data __rte_unused)
3131 {
3132 	char *dst = tokens[1], *src = tokens[2];
3133 	struct field *fdst, *fsrc;
3134 	uint64_t src_val;
3135 	uint32_t dst_struct_id = 0, src_struct_id = 0;
3136 
3137 	CHECK(n_tokens == 3, EINVAL);
3138 
3139 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3140 	CHECK(fdst, EINVAL);
3141 	CHECK(!fdst->var_size, EINVAL);
3142 
3143 	/* OR, OR_MH, OR_HM, OR_HH. */
3144 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
3145 	if (fsrc) {
3146 		CHECK(!fsrc->var_size, EINVAL);
3147 
3148 		instr->type = INSTR_ALU_OR;
3149 		if (dst[0] != 'h' && src[0] == 'h')
3150 			instr->type = INSTR_ALU_OR_MH;
3151 		if (dst[0] == 'h' && src[0] != 'h')
3152 			instr->type = INSTR_ALU_OR_HM;
3153 		if (dst[0] == 'h' && src[0] == 'h')
3154 			instr->type = INSTR_ALU_OR_HH;
3155 
3156 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3157 		instr->alu.dst.n_bits = fdst->n_bits;
3158 		instr->alu.dst.offset = fdst->offset / 8;
3159 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
3160 		instr->alu.src.n_bits = fsrc->n_bits;
3161 		instr->alu.src.offset = fsrc->offset / 8;
3162 		return 0;
3163 	}
3164 
3165 	/* OR_I. */
3166 	src_val = strtoull(src, &src, 0);
3167 	CHECK(!src[0], EINVAL);
3168 
3169 	if (dst[0] == 'h')
3170 		src_val = hton64(src_val) >> (64 - fdst->n_bits);
3171 
3172 	instr->type = INSTR_ALU_OR_I;
3173 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3174 	instr->alu.dst.n_bits = fdst->n_bits;
3175 	instr->alu.dst.offset = fdst->offset / 8;
3176 	instr->alu.src_val = src_val;
3177 	return 0;
3178 }
3179 
3180 static int
3181 instr_alu_xor_translate(struct rte_swx_pipeline *p,
3182 			struct action *action,
3183 			char **tokens,
3184 			int n_tokens,
3185 			struct instruction *instr,
3186 			struct instruction_data *data __rte_unused)
3187 {
3188 	char *dst = tokens[1], *src = tokens[2];
3189 	struct field *fdst, *fsrc;
3190 	uint64_t src_val;
3191 	uint32_t dst_struct_id = 0, src_struct_id = 0;
3192 
3193 	CHECK(n_tokens == 3, EINVAL);
3194 
3195 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3196 	CHECK(fdst, EINVAL);
3197 	CHECK(!fdst->var_size, EINVAL);
3198 
3199 	/* XOR, XOR_MH, XOR_HM, XOR_HH. */
3200 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
3201 	if (fsrc) {
3202 		CHECK(!fsrc->var_size, EINVAL);
3203 
3204 		instr->type = INSTR_ALU_XOR;
3205 		if (dst[0] != 'h' && src[0] == 'h')
3206 			instr->type = INSTR_ALU_XOR_MH;
3207 		if (dst[0] == 'h' && src[0] != 'h')
3208 			instr->type = INSTR_ALU_XOR_HM;
3209 		if (dst[0] == 'h' && src[0] == 'h')
3210 			instr->type = INSTR_ALU_XOR_HH;
3211 
3212 		instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3213 		instr->alu.dst.n_bits = fdst->n_bits;
3214 		instr->alu.dst.offset = fdst->offset / 8;
3215 		instr->alu.src.struct_id = (uint8_t)src_struct_id;
3216 		instr->alu.src.n_bits = fsrc->n_bits;
3217 		instr->alu.src.offset = fsrc->offset / 8;
3218 		return 0;
3219 	}
3220 
3221 	/* XOR_I. */
3222 	src_val = strtoull(src, &src, 0);
3223 	CHECK(!src[0], EINVAL);
3224 
3225 	if (dst[0] == 'h')
3226 		src_val = hton64(src_val) >> (64 - fdst->n_bits);
3227 
3228 	instr->type = INSTR_ALU_XOR_I;
3229 	instr->alu.dst.struct_id = (uint8_t)dst_struct_id;
3230 	instr->alu.dst.n_bits = fdst->n_bits;
3231 	instr->alu.dst.offset = fdst->offset / 8;
3232 	instr->alu.src_val = src_val;
3233 	return 0;
3234 }
3235 
3236 static inline void
3237 instr_alu_add_exec(struct rte_swx_pipeline *p)
3238 {
3239 	struct thread *t = &p->threads[p->thread_id];
3240 	struct instruction *ip = t->ip;
3241 
3242 	/* Structs */
3243 	__instr_alu_add_exec(p, t, ip);
3244 
3245 	/* Thread. */
3246 	thread_ip_inc(p);
3247 }
3248 
3249 static inline void
3250 instr_alu_add_mh_exec(struct rte_swx_pipeline *p)
3251 {
3252 	struct thread *t = &p->threads[p->thread_id];
3253 	struct instruction *ip = t->ip;
3254 
3255 	/* Structs. */
3256 	__instr_alu_add_mh_exec(p, t, ip);
3257 
3258 	/* Thread. */
3259 	thread_ip_inc(p);
3260 }
3261 
3262 static inline void
3263 instr_alu_add_hm_exec(struct rte_swx_pipeline *p)
3264 {
3265 	struct thread *t = &p->threads[p->thread_id];
3266 	struct instruction *ip = t->ip;
3267 
3268 	/* Structs. */
3269 	__instr_alu_add_hm_exec(p, t, ip);
3270 
3271 	/* Thread. */
3272 	thread_ip_inc(p);
3273 }
3274 
3275 static inline void
3276 instr_alu_add_hh_exec(struct rte_swx_pipeline *p)
3277 {
3278 	struct thread *t = &p->threads[p->thread_id];
3279 	struct instruction *ip = t->ip;
3280 
3281 	/* Structs. */
3282 	__instr_alu_add_hh_exec(p, t, ip);
3283 
3284 	/* Thread. */
3285 	thread_ip_inc(p);
3286 }
3287 
3288 static inline void
3289 instr_alu_add_mi_exec(struct rte_swx_pipeline *p)
3290 {
3291 	struct thread *t = &p->threads[p->thread_id];
3292 	struct instruction *ip = t->ip;
3293 
3294 	/* Structs. */
3295 	__instr_alu_add_mi_exec(p, t, ip);
3296 
3297 	/* Thread. */
3298 	thread_ip_inc(p);
3299 }
3300 
3301 static inline void
3302 instr_alu_add_hi_exec(struct rte_swx_pipeline *p)
3303 {
3304 	struct thread *t = &p->threads[p->thread_id];
3305 	struct instruction *ip = t->ip;
3306 
3307 	/* Structs. */
3308 	__instr_alu_add_hi_exec(p, t, ip);
3309 
3310 	/* Thread. */
3311 	thread_ip_inc(p);
3312 }
3313 
3314 static inline void
3315 instr_alu_sub_exec(struct rte_swx_pipeline *p)
3316 {
3317 	struct thread *t = &p->threads[p->thread_id];
3318 	struct instruction *ip = t->ip;
3319 
3320 	/* Structs. */
3321 	__instr_alu_sub_exec(p, t, ip);
3322 
3323 	/* Thread. */
3324 	thread_ip_inc(p);
3325 }
3326 
3327 static inline void
3328 instr_alu_sub_mh_exec(struct rte_swx_pipeline *p)
3329 {
3330 	struct thread *t = &p->threads[p->thread_id];
3331 	struct instruction *ip = t->ip;
3332 
3333 	/* Structs. */
3334 	__instr_alu_sub_mh_exec(p, t, ip);
3335 
3336 	/* Thread. */
3337 	thread_ip_inc(p);
3338 }
3339 
3340 static inline void
3341 instr_alu_sub_hm_exec(struct rte_swx_pipeline *p)
3342 {
3343 	struct thread *t = &p->threads[p->thread_id];
3344 	struct instruction *ip = t->ip;
3345 
3346 	/* Structs. */
3347 	__instr_alu_sub_hm_exec(p, t, ip);
3348 
3349 	/* Thread. */
3350 	thread_ip_inc(p);
3351 }
3352 
3353 static inline void
3354 instr_alu_sub_hh_exec(struct rte_swx_pipeline *p)
3355 {
3356 	struct thread *t = &p->threads[p->thread_id];
3357 	struct instruction *ip = t->ip;
3358 
3359 	/* Structs. */
3360 	__instr_alu_sub_hh_exec(p, t, ip);
3361 
3362 	/* Thread. */
3363 	thread_ip_inc(p);
3364 }
3365 
3366 static inline void
3367 instr_alu_sub_mi_exec(struct rte_swx_pipeline *p)
3368 {
3369 	struct thread *t = &p->threads[p->thread_id];
3370 	struct instruction *ip = t->ip;
3371 
3372 	/* Structs. */
3373 	__instr_alu_sub_mi_exec(p, t, ip);
3374 
3375 	/* Thread. */
3376 	thread_ip_inc(p);
3377 }
3378 
3379 static inline void
3380 instr_alu_sub_hi_exec(struct rte_swx_pipeline *p)
3381 {
3382 	struct thread *t = &p->threads[p->thread_id];
3383 	struct instruction *ip = t->ip;
3384 
3385 	/* Structs. */
3386 	__instr_alu_sub_hi_exec(p, t, ip);
3387 
3388 	/* Thread. */
3389 	thread_ip_inc(p);
3390 }
3391 
3392 static inline void
3393 instr_alu_shl_exec(struct rte_swx_pipeline *p)
3394 {
3395 	struct thread *t = &p->threads[p->thread_id];
3396 	struct instruction *ip = t->ip;
3397 
3398 	/* Structs. */
3399 	__instr_alu_shl_exec(p, t, ip);
3400 
3401 	/* Thread. */
3402 	thread_ip_inc(p);
3403 }
3404 
3405 static inline void
3406 instr_alu_shl_mh_exec(struct rte_swx_pipeline *p)
3407 {
3408 	struct thread *t = &p->threads[p->thread_id];
3409 	struct instruction *ip = t->ip;
3410 
3411 	/* Structs. */
3412 	__instr_alu_shl_mh_exec(p, t, ip);
3413 
3414 	/* Thread. */
3415 	thread_ip_inc(p);
3416 }
3417 
3418 static inline void
3419 instr_alu_shl_hm_exec(struct rte_swx_pipeline *p)
3420 {
3421 	struct thread *t = &p->threads[p->thread_id];
3422 	struct instruction *ip = t->ip;
3423 
3424 	/* Structs. */
3425 	__instr_alu_shl_hm_exec(p, t, ip);
3426 
3427 	/* Thread. */
3428 	thread_ip_inc(p);
3429 }
3430 
3431 static inline void
3432 instr_alu_shl_hh_exec(struct rte_swx_pipeline *p)
3433 {
3434 	struct thread *t = &p->threads[p->thread_id];
3435 	struct instruction *ip = t->ip;
3436 
3437 	/* Structs. */
3438 	__instr_alu_shl_hh_exec(p, t, ip);
3439 
3440 	/* Thread. */
3441 	thread_ip_inc(p);
3442 }
3443 
3444 static inline void
3445 instr_alu_shl_mi_exec(struct rte_swx_pipeline *p)
3446 {
3447 	struct thread *t = &p->threads[p->thread_id];
3448 	struct instruction *ip = t->ip;
3449 
3450 	/* Structs. */
3451 	__instr_alu_shl_mi_exec(p, t, ip);
3452 
3453 	/* Thread. */
3454 	thread_ip_inc(p);
3455 }
3456 
3457 static inline void
3458 instr_alu_shl_hi_exec(struct rte_swx_pipeline *p)
3459 {
3460 	struct thread *t = &p->threads[p->thread_id];
3461 	struct instruction *ip = t->ip;
3462 
3463 	/* Structs. */
3464 	__instr_alu_shl_hi_exec(p, t, ip);
3465 
3466 	/* Thread. */
3467 	thread_ip_inc(p);
3468 }
3469 
3470 static inline void
3471 instr_alu_shr_exec(struct rte_swx_pipeline *p)
3472 {
3473 	struct thread *t = &p->threads[p->thread_id];
3474 	struct instruction *ip = t->ip;
3475 
3476 	/* Structs. */
3477 	__instr_alu_shr_exec(p, t, ip);
3478 
3479 	/* Thread. */
3480 	thread_ip_inc(p);
3481 }
3482 
3483 static inline void
3484 instr_alu_shr_mh_exec(struct rte_swx_pipeline *p)
3485 {
3486 	struct thread *t = &p->threads[p->thread_id];
3487 	struct instruction *ip = t->ip;
3488 
3489 	/* Structs. */
3490 	__instr_alu_shr_mh_exec(p, t, ip);
3491 
3492 	/* Thread. */
3493 	thread_ip_inc(p);
3494 }
3495 
3496 static inline void
3497 instr_alu_shr_hm_exec(struct rte_swx_pipeline *p)
3498 {
3499 	struct thread *t = &p->threads[p->thread_id];
3500 	struct instruction *ip = t->ip;
3501 
3502 	/* Structs. */
3503 	__instr_alu_shr_hm_exec(p, t, ip);
3504 
3505 	/* Thread. */
3506 	thread_ip_inc(p);
3507 }
3508 
3509 static inline void
3510 instr_alu_shr_hh_exec(struct rte_swx_pipeline *p)
3511 {
3512 	struct thread *t = &p->threads[p->thread_id];
3513 	struct instruction *ip = t->ip;
3514 
3515 	/* Structs. */
3516 	__instr_alu_shr_hh_exec(p, t, ip);
3517 
3518 	/* Thread. */
3519 	thread_ip_inc(p);
3520 }
3521 
3522 static inline void
3523 instr_alu_shr_mi_exec(struct rte_swx_pipeline *p)
3524 {
3525 	struct thread *t = &p->threads[p->thread_id];
3526 	struct instruction *ip = t->ip;
3527 
3528 	/* Structs. */
3529 	__instr_alu_shr_mi_exec(p, t, ip);
3530 
3531 	/* Thread. */
3532 	thread_ip_inc(p);
3533 }
3534 
3535 static inline void
3536 instr_alu_shr_hi_exec(struct rte_swx_pipeline *p)
3537 {
3538 	struct thread *t = &p->threads[p->thread_id];
3539 	struct instruction *ip = t->ip;
3540 
3541 	/* Structs. */
3542 	__instr_alu_shr_hi_exec(p, t, ip);
3543 
3544 	/* Thread. */
3545 	thread_ip_inc(p);
3546 }
3547 
3548 static inline void
3549 instr_alu_and_exec(struct rte_swx_pipeline *p)
3550 {
3551 	struct thread *t = &p->threads[p->thread_id];
3552 	struct instruction *ip = t->ip;
3553 
3554 	/* Structs. */
3555 	__instr_alu_and_exec(p, t, ip);
3556 
3557 	/* Thread. */
3558 	thread_ip_inc(p);
3559 }
3560 
3561 static inline void
3562 instr_alu_and_mh_exec(struct rte_swx_pipeline *p)
3563 {
3564 	struct thread *t = &p->threads[p->thread_id];
3565 	struct instruction *ip = t->ip;
3566 
3567 	/* Structs. */
3568 	__instr_alu_and_mh_exec(p, t, ip);
3569 
3570 	/* Thread. */
3571 	thread_ip_inc(p);
3572 }
3573 
3574 static inline void
3575 instr_alu_and_hm_exec(struct rte_swx_pipeline *p)
3576 {
3577 	struct thread *t = &p->threads[p->thread_id];
3578 	struct instruction *ip = t->ip;
3579 
3580 	/* Structs. */
3581 	__instr_alu_and_hm_exec(p, t, ip);
3582 
3583 	/* Thread. */
3584 	thread_ip_inc(p);
3585 }
3586 
3587 static inline void
3588 instr_alu_and_hh_exec(struct rte_swx_pipeline *p)
3589 {
3590 	struct thread *t = &p->threads[p->thread_id];
3591 	struct instruction *ip = t->ip;
3592 
3593 	/* Structs. */
3594 	__instr_alu_and_hh_exec(p, t, ip);
3595 
3596 	/* Thread. */
3597 	thread_ip_inc(p);
3598 }
3599 
3600 static inline void
3601 instr_alu_and_i_exec(struct rte_swx_pipeline *p)
3602 {
3603 	struct thread *t = &p->threads[p->thread_id];
3604 	struct instruction *ip = t->ip;
3605 
3606 	/* Structs. */
3607 	__instr_alu_and_i_exec(p, t, ip);
3608 
3609 	/* Thread. */
3610 	thread_ip_inc(p);
3611 }
3612 
3613 static inline void
3614 instr_alu_or_exec(struct rte_swx_pipeline *p)
3615 {
3616 	struct thread *t = &p->threads[p->thread_id];
3617 	struct instruction *ip = t->ip;
3618 
3619 	/* Structs. */
3620 	__instr_alu_or_exec(p, t, ip);
3621 
3622 	/* Thread. */
3623 	thread_ip_inc(p);
3624 }
3625 
3626 static inline void
3627 instr_alu_or_mh_exec(struct rte_swx_pipeline *p)
3628 {
3629 	struct thread *t = &p->threads[p->thread_id];
3630 	struct instruction *ip = t->ip;
3631 
3632 	/* Structs. */
3633 	__instr_alu_or_mh_exec(p, t, ip);
3634 
3635 	/* Thread. */
3636 	thread_ip_inc(p);
3637 }
3638 
3639 static inline void
3640 instr_alu_or_hm_exec(struct rte_swx_pipeline *p)
3641 {
3642 	struct thread *t = &p->threads[p->thread_id];
3643 	struct instruction *ip = t->ip;
3644 
3645 	/* Structs. */
3646 	__instr_alu_or_hm_exec(p, t, ip);
3647 
3648 	/* Thread. */
3649 	thread_ip_inc(p);
3650 }
3651 
3652 static inline void
3653 instr_alu_or_hh_exec(struct rte_swx_pipeline *p)
3654 {
3655 	struct thread *t = &p->threads[p->thread_id];
3656 	struct instruction *ip = t->ip;
3657 
3658 	/* Structs. */
3659 	__instr_alu_or_hh_exec(p, t, ip);
3660 
3661 	/* Thread. */
3662 	thread_ip_inc(p);
3663 }
3664 
3665 static inline void
3666 instr_alu_or_i_exec(struct rte_swx_pipeline *p)
3667 {
3668 	struct thread *t = &p->threads[p->thread_id];
3669 	struct instruction *ip = t->ip;
3670 
3671 	/* Structs. */
3672 	__instr_alu_or_i_exec(p, t, ip);
3673 
3674 	/* Thread. */
3675 	thread_ip_inc(p);
3676 }
3677 
3678 static inline void
3679 instr_alu_xor_exec(struct rte_swx_pipeline *p)
3680 {
3681 	struct thread *t = &p->threads[p->thread_id];
3682 	struct instruction *ip = t->ip;
3683 
3684 	/* Structs. */
3685 	__instr_alu_xor_exec(p, t, ip);
3686 
3687 	/* Thread. */
3688 	thread_ip_inc(p);
3689 }
3690 
3691 static inline void
3692 instr_alu_xor_mh_exec(struct rte_swx_pipeline *p)
3693 {
3694 	struct thread *t = &p->threads[p->thread_id];
3695 	struct instruction *ip = t->ip;
3696 
3697 	/* Structs. */
3698 	__instr_alu_xor_mh_exec(p, t, ip);
3699 
3700 	/* Thread. */
3701 	thread_ip_inc(p);
3702 }
3703 
3704 static inline void
3705 instr_alu_xor_hm_exec(struct rte_swx_pipeline *p)
3706 {
3707 	struct thread *t = &p->threads[p->thread_id];
3708 	struct instruction *ip = t->ip;
3709 
3710 	/* Structs. */
3711 	__instr_alu_xor_hm_exec(p, t, ip);
3712 
3713 	/* Thread. */
3714 	thread_ip_inc(p);
3715 }
3716 
3717 static inline void
3718 instr_alu_xor_hh_exec(struct rte_swx_pipeline *p)
3719 {
3720 	struct thread *t = &p->threads[p->thread_id];
3721 	struct instruction *ip = t->ip;
3722 
3723 	/* Structs. */
3724 	__instr_alu_xor_hh_exec(p, t, ip);
3725 
3726 	/* Thread. */
3727 	thread_ip_inc(p);
3728 }
3729 
3730 static inline void
3731 instr_alu_xor_i_exec(struct rte_swx_pipeline *p)
3732 {
3733 	struct thread *t = &p->threads[p->thread_id];
3734 	struct instruction *ip = t->ip;
3735 
3736 	/* Structs. */
3737 	__instr_alu_xor_i_exec(p, t, ip);
3738 
3739 	/* Thread. */
3740 	thread_ip_inc(p);
3741 }
3742 
3743 static inline void
3744 instr_alu_ckadd_field_exec(struct rte_swx_pipeline *p)
3745 {
3746 	struct thread *t = &p->threads[p->thread_id];
3747 	struct instruction *ip = t->ip;
3748 
3749 	/* Structs. */
3750 	__instr_alu_ckadd_field_exec(p, t, ip);
3751 
3752 	/* Thread. */
3753 	thread_ip_inc(p);
3754 }
3755 
3756 static inline void
3757 instr_alu_cksub_field_exec(struct rte_swx_pipeline *p)
3758 {
3759 	struct thread *t = &p->threads[p->thread_id];
3760 	struct instruction *ip = t->ip;
3761 
3762 	/* Structs. */
3763 	__instr_alu_cksub_field_exec(p, t, ip);
3764 
3765 	/* Thread. */
3766 	thread_ip_inc(p);
3767 }
3768 
3769 static inline void
3770 instr_alu_ckadd_struct20_exec(struct rte_swx_pipeline *p)
3771 {
3772 	struct thread *t = &p->threads[p->thread_id];
3773 	struct instruction *ip = t->ip;
3774 
3775 	/* Structs. */
3776 	__instr_alu_ckadd_struct20_exec(p, t, ip);
3777 
3778 	/* Thread. */
3779 	thread_ip_inc(p);
3780 }
3781 
3782 static inline void
3783 instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p)
3784 {
3785 	struct thread *t = &p->threads[p->thread_id];
3786 	struct instruction *ip = t->ip;
3787 
3788 	/* Structs. */
3789 	__instr_alu_ckadd_struct_exec(p, t, ip);
3790 
3791 	/* Thread. */
3792 	thread_ip_inc(p);
3793 }
3794 
3795 /*
3796  * Register array.
3797  */
3798 static struct regarray *
3799 regarray_find(struct rte_swx_pipeline *p, const char *name);
3800 
3801 static int
3802 instr_regprefetch_translate(struct rte_swx_pipeline *p,
3803 		      struct action *action,
3804 		      char **tokens,
3805 		      int n_tokens,
3806 		      struct instruction *instr,
3807 		      struct instruction_data *data __rte_unused)
3808 {
3809 	char *regarray = tokens[1], *idx = tokens[2];
3810 	struct regarray *r;
3811 	struct field *fidx;
3812 	uint32_t idx_struct_id, idx_val;
3813 
3814 	CHECK(n_tokens == 3, EINVAL);
3815 
3816 	r = regarray_find(p, regarray);
3817 	CHECK(r, EINVAL);
3818 
3819 	/* REGPREFETCH_RH, REGPREFETCH_RM. */
3820 	fidx = struct_field_parse(p, action, idx, &idx_struct_id);
3821 	if (fidx) {
3822 		CHECK(!fidx->var_size, EINVAL);
3823 
3824 		instr->type = INSTR_REGPREFETCH_RM;
3825 		if (idx[0] == 'h')
3826 			instr->type = INSTR_REGPREFETCH_RH;
3827 
3828 		instr->regarray.regarray_id = r->id;
3829 		instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3830 		instr->regarray.idx.n_bits = fidx->n_bits;
3831 		instr->regarray.idx.offset = fidx->offset / 8;
3832 		instr->regarray.dstsrc_val = 0; /* Unused. */
3833 		return 0;
3834 	}
3835 
3836 	/* REGPREFETCH_RI. */
3837 	idx_val = strtoul(idx, &idx, 0);
3838 	CHECK(!idx[0], EINVAL);
3839 
3840 	instr->type = INSTR_REGPREFETCH_RI;
3841 	instr->regarray.regarray_id = r->id;
3842 	instr->regarray.idx_val = idx_val;
3843 	instr->regarray.dstsrc_val = 0; /* Unused. */
3844 	return 0;
3845 }
3846 
3847 static int
3848 instr_regrd_translate(struct rte_swx_pipeline *p,
3849 		      struct action *action,
3850 		      char **tokens,
3851 		      int n_tokens,
3852 		      struct instruction *instr,
3853 		      struct instruction_data *data __rte_unused)
3854 {
3855 	char *dst = tokens[1], *regarray = tokens[2], *idx = tokens[3];
3856 	struct regarray *r;
3857 	struct field *fdst, *fidx;
3858 	uint32_t dst_struct_id, idx_struct_id, idx_val;
3859 
3860 	CHECK(n_tokens == 4, EINVAL);
3861 
3862 	r = regarray_find(p, regarray);
3863 	CHECK(r, EINVAL);
3864 
3865 	fdst = struct_field_parse(p, NULL, dst, &dst_struct_id);
3866 	CHECK(fdst, EINVAL);
3867 	CHECK(!fdst->var_size, EINVAL);
3868 
3869 	/* REGRD_HRH, REGRD_HRM, REGRD_MRH, REGRD_MRM. */
3870 	fidx = struct_field_parse(p, action, idx, &idx_struct_id);
3871 	if (fidx) {
3872 		CHECK(!fidx->var_size, EINVAL);
3873 
3874 		instr->type = INSTR_REGRD_MRM;
3875 		if (dst[0] == 'h' && idx[0] != 'h')
3876 			instr->type = INSTR_REGRD_HRM;
3877 		if (dst[0] != 'h' && idx[0] == 'h')
3878 			instr->type = INSTR_REGRD_MRH;
3879 		if (dst[0] == 'h' && idx[0] == 'h')
3880 			instr->type = INSTR_REGRD_HRH;
3881 
3882 		instr->regarray.regarray_id = r->id;
3883 		instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3884 		instr->regarray.idx.n_bits = fidx->n_bits;
3885 		instr->regarray.idx.offset = fidx->offset / 8;
3886 		instr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;
3887 		instr->regarray.dstsrc.n_bits = fdst->n_bits;
3888 		instr->regarray.dstsrc.offset = fdst->offset / 8;
3889 		return 0;
3890 	}
3891 
3892 	/* REGRD_MRI, REGRD_HRI. */
3893 	idx_val = strtoul(idx, &idx, 0);
3894 	CHECK(!idx[0], EINVAL);
3895 
3896 	instr->type = INSTR_REGRD_MRI;
3897 	if (dst[0] == 'h')
3898 		instr->type = INSTR_REGRD_HRI;
3899 
3900 	instr->regarray.regarray_id = r->id;
3901 	instr->regarray.idx_val = idx_val;
3902 	instr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;
3903 	instr->regarray.dstsrc.n_bits = fdst->n_bits;
3904 	instr->regarray.dstsrc.offset = fdst->offset / 8;
3905 	return 0;
3906 }
3907 
3908 static int
3909 instr_regwr_translate(struct rte_swx_pipeline *p,
3910 		      struct action *action,
3911 		      char **tokens,
3912 		      int n_tokens,
3913 		      struct instruction *instr,
3914 		      struct instruction_data *data __rte_unused)
3915 {
3916 	char *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];
3917 	struct regarray *r;
3918 	struct field *fidx, *fsrc;
3919 	uint64_t src_val;
3920 	uint32_t idx_struct_id, idx_val, src_struct_id;
3921 
3922 	CHECK(n_tokens == 4, EINVAL);
3923 
3924 	r = regarray_find(p, regarray);
3925 	CHECK(r, EINVAL);
3926 
3927 	/* REGWR_RHH, REGWR_RHM, REGWR_RMH, REGWR_RMM. */
3928 	fidx = struct_field_parse(p, action, idx, &idx_struct_id);
3929 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
3930 	if (fidx && fsrc) {
3931 		CHECK(!fidx->var_size, EINVAL);
3932 		CHECK(!fsrc->var_size, EINVAL);
3933 
3934 		instr->type = INSTR_REGWR_RMM;
3935 		if (idx[0] == 'h' && src[0] != 'h')
3936 			instr->type = INSTR_REGWR_RHM;
3937 		if (idx[0] != 'h' && src[0] == 'h')
3938 			instr->type = INSTR_REGWR_RMH;
3939 		if (idx[0] == 'h' && src[0] == 'h')
3940 			instr->type = INSTR_REGWR_RHH;
3941 
3942 		instr->regarray.regarray_id = r->id;
3943 		instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3944 		instr->regarray.idx.n_bits = fidx->n_bits;
3945 		instr->regarray.idx.offset = fidx->offset / 8;
3946 		instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
3947 		instr->regarray.dstsrc.n_bits = fsrc->n_bits;
3948 		instr->regarray.dstsrc.offset = fsrc->offset / 8;
3949 		return 0;
3950 	}
3951 
3952 	/* REGWR_RHI, REGWR_RMI. */
3953 	if (fidx && !fsrc) {
3954 		CHECK(!fidx->var_size, EINVAL);
3955 
3956 		src_val = strtoull(src, &src, 0);
3957 		CHECK(!src[0], EINVAL);
3958 
3959 		instr->type = INSTR_REGWR_RMI;
3960 		if (idx[0] == 'h')
3961 			instr->type = INSTR_REGWR_RHI;
3962 
3963 		instr->regarray.regarray_id = r->id;
3964 		instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
3965 		instr->regarray.idx.n_bits = fidx->n_bits;
3966 		instr->regarray.idx.offset = fidx->offset / 8;
3967 		instr->regarray.dstsrc_val = src_val;
3968 		return 0;
3969 	}
3970 
3971 	/* REGWR_RIH, REGWR_RIM. */
3972 	if (!fidx && fsrc) {
3973 		idx_val = strtoul(idx, &idx, 0);
3974 		CHECK(!idx[0], EINVAL);
3975 
3976 		CHECK(!fsrc->var_size, EINVAL);
3977 
3978 		instr->type = INSTR_REGWR_RIM;
3979 		if (src[0] == 'h')
3980 			instr->type = INSTR_REGWR_RIH;
3981 
3982 		instr->regarray.regarray_id = r->id;
3983 		instr->regarray.idx_val = idx_val;
3984 		instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
3985 		instr->regarray.dstsrc.n_bits = fsrc->n_bits;
3986 		instr->regarray.dstsrc.offset = fsrc->offset / 8;
3987 		return 0;
3988 	}
3989 
3990 	/* REGWR_RII. */
3991 	src_val = strtoull(src, &src, 0);
3992 	CHECK(!src[0], EINVAL);
3993 
3994 	idx_val = strtoul(idx, &idx, 0);
3995 	CHECK(!idx[0], EINVAL);
3996 
3997 	instr->type = INSTR_REGWR_RII;
3998 	instr->regarray.idx_val = idx_val;
3999 	instr->regarray.dstsrc_val = src_val;
4000 
4001 	return 0;
4002 }
4003 
4004 static int
4005 instr_regadd_translate(struct rte_swx_pipeline *p,
4006 		       struct action *action,
4007 		       char **tokens,
4008 		       int n_tokens,
4009 		       struct instruction *instr,
4010 		       struct instruction_data *data __rte_unused)
4011 {
4012 	char *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];
4013 	struct regarray *r;
4014 	struct field *fidx, *fsrc;
4015 	uint64_t src_val;
4016 	uint32_t idx_struct_id, idx_val, src_struct_id;
4017 
4018 	CHECK(n_tokens == 4, EINVAL);
4019 
4020 	r = regarray_find(p, regarray);
4021 	CHECK(r, EINVAL);
4022 
4023 	/* REGADD_RHH, REGADD_RHM, REGADD_RMH, REGADD_RMM. */
4024 	fidx = struct_field_parse(p, action, idx, &idx_struct_id);
4025 	fsrc = struct_field_parse(p, action, src, &src_struct_id);
4026 	if (fidx && fsrc) {
4027 		CHECK(!fidx->var_size, EINVAL);
4028 		CHECK(!fsrc->var_size, EINVAL);
4029 
4030 		instr->type = INSTR_REGADD_RMM;
4031 		if (idx[0] == 'h' && src[0] != 'h')
4032 			instr->type = INSTR_REGADD_RHM;
4033 		if (idx[0] != 'h' && src[0] == 'h')
4034 			instr->type = INSTR_REGADD_RMH;
4035 		if (idx[0] == 'h' && src[0] == 'h')
4036 			instr->type = INSTR_REGADD_RHH;
4037 
4038 		instr->regarray.regarray_id = r->id;
4039 		instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
4040 		instr->regarray.idx.n_bits = fidx->n_bits;
4041 		instr->regarray.idx.offset = fidx->offset / 8;
4042 		instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
4043 		instr->regarray.dstsrc.n_bits = fsrc->n_bits;
4044 		instr->regarray.dstsrc.offset = fsrc->offset / 8;
4045 		return 0;
4046 	}
4047 
4048 	/* REGADD_RHI, REGADD_RMI. */
4049 	if (fidx && !fsrc) {
4050 		CHECK(!fidx->var_size, EINVAL);
4051 
4052 		src_val = strtoull(src, &src, 0);
4053 		CHECK(!src[0], EINVAL);
4054 
4055 		instr->type = INSTR_REGADD_RMI;
4056 		if (idx[0] == 'h')
4057 			instr->type = INSTR_REGADD_RHI;
4058 
4059 		instr->regarray.regarray_id = r->id;
4060 		instr->regarray.idx.struct_id = (uint8_t)idx_struct_id;
4061 		instr->regarray.idx.n_bits = fidx->n_bits;
4062 		instr->regarray.idx.offset = fidx->offset / 8;
4063 		instr->regarray.dstsrc_val = src_val;
4064 		return 0;
4065 	}
4066 
4067 	/* REGADD_RIH, REGADD_RIM. */
4068 	if (!fidx && fsrc) {
4069 		idx_val = strtoul(idx, &idx, 0);
4070 		CHECK(!idx[0], EINVAL);
4071 
4072 		CHECK(!fsrc->var_size, EINVAL);
4073 
4074 		instr->type = INSTR_REGADD_RIM;
4075 		if (src[0] == 'h')
4076 			instr->type = INSTR_REGADD_RIH;
4077 
4078 		instr->regarray.regarray_id = r->id;
4079 		instr->regarray.idx_val = idx_val;
4080 		instr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;
4081 		instr->regarray.dstsrc.n_bits = fsrc->n_bits;
4082 		instr->regarray.dstsrc.offset = fsrc->offset / 8;
4083 		return 0;
4084 	}
4085 
4086 	/* REGADD_RII. */
4087 	src_val = strtoull(src, &src, 0);
4088 	CHECK(!src[0], EINVAL);
4089 
4090 	idx_val = strtoul(idx, &idx, 0);
4091 	CHECK(!idx[0], EINVAL);
4092 
4093 	instr->type = INSTR_REGADD_RII;
4094 	instr->regarray.idx_val = idx_val;
4095 	instr->regarray.dstsrc_val = src_val;
4096 	return 0;
4097 }
4098 
4099 static inline void
4100 instr_regprefetch_rh_exec(struct rte_swx_pipeline *p)
4101 {
4102 	struct thread *t = &p->threads[p->thread_id];
4103 	struct instruction *ip = t->ip;
4104 
4105 	/* Structs. */
4106 	__instr_regprefetch_rh_exec(p, t, ip);
4107 
4108 	/* Thread. */
4109 	thread_ip_inc(p);
4110 }
4111 
4112 static inline void
4113 instr_regprefetch_rm_exec(struct rte_swx_pipeline *p)
4114 {
4115 	struct thread *t = &p->threads[p->thread_id];
4116 	struct instruction *ip = t->ip;
4117 
4118 	/* Structs. */
4119 	__instr_regprefetch_rm_exec(p, t, ip);
4120 
4121 	/* Thread. */
4122 	thread_ip_inc(p);
4123 }
4124 
4125 static inline void
4126 instr_regprefetch_ri_exec(struct rte_swx_pipeline *p)
4127 {
4128 	struct thread *t = &p->threads[p->thread_id];
4129 	struct instruction *ip = t->ip;
4130 
4131 	/* Structs. */
4132 	__instr_regprefetch_ri_exec(p, t, ip);
4133 
4134 	/* Thread. */
4135 	thread_ip_inc(p);
4136 }
4137 
4138 static inline void
4139 instr_regrd_hrh_exec(struct rte_swx_pipeline *p)
4140 {
4141 	struct thread *t = &p->threads[p->thread_id];
4142 	struct instruction *ip = t->ip;
4143 
4144 	/* Structs. */
4145 	__instr_regrd_hrh_exec(p, t, ip);
4146 
4147 	/* Thread. */
4148 	thread_ip_inc(p);
4149 }
4150 
4151 static inline void
4152 instr_regrd_hrm_exec(struct rte_swx_pipeline *p)
4153 {
4154 	struct thread *t = &p->threads[p->thread_id];
4155 	struct instruction *ip = t->ip;
4156 
4157 	/* Structs. */
4158 	__instr_regrd_hrm_exec(p, t, ip);
4159 
4160 	/* Thread. */
4161 	thread_ip_inc(p);
4162 }
4163 
4164 static inline void
4165 instr_regrd_mrh_exec(struct rte_swx_pipeline *p)
4166 {
4167 	struct thread *t = &p->threads[p->thread_id];
4168 	struct instruction *ip = t->ip;
4169 
4170 	/* Structs. */
4171 	__instr_regrd_mrh_exec(p, t, ip);
4172 
4173 	/* Thread. */
4174 	thread_ip_inc(p);
4175 }
4176 
4177 static inline void
4178 instr_regrd_mrm_exec(struct rte_swx_pipeline *p)
4179 {
4180 	struct thread *t = &p->threads[p->thread_id];
4181 	struct instruction *ip = t->ip;
4182 
4183 	/* Structs. */
4184 	__instr_regrd_mrm_exec(p, t, ip);
4185 
4186 	/* Thread. */
4187 	thread_ip_inc(p);
4188 }
4189 
4190 static inline void
4191 instr_regrd_hri_exec(struct rte_swx_pipeline *p)
4192 {
4193 	struct thread *t = &p->threads[p->thread_id];
4194 	struct instruction *ip = t->ip;
4195 
4196 	/* Structs. */
4197 	__instr_regrd_hri_exec(p, t, ip);
4198 
4199 	/* Thread. */
4200 	thread_ip_inc(p);
4201 }
4202 
4203 static inline void
4204 instr_regrd_mri_exec(struct rte_swx_pipeline *p)
4205 {
4206 	struct thread *t = &p->threads[p->thread_id];
4207 	struct instruction *ip = t->ip;
4208 
4209 	/* Structs. */
4210 	__instr_regrd_mri_exec(p, t, ip);
4211 
4212 	/* Thread. */
4213 	thread_ip_inc(p);
4214 }
4215 
4216 static inline void
4217 instr_regwr_rhh_exec(struct rte_swx_pipeline *p)
4218 {
4219 	struct thread *t = &p->threads[p->thread_id];
4220 	struct instruction *ip = t->ip;
4221 
4222 	/* Structs. */
4223 	__instr_regwr_rhh_exec(p, t, ip);
4224 
4225 	/* Thread. */
4226 	thread_ip_inc(p);
4227 }
4228 
4229 static inline void
4230 instr_regwr_rhm_exec(struct rte_swx_pipeline *p)
4231 {
4232 	struct thread *t = &p->threads[p->thread_id];
4233 	struct instruction *ip = t->ip;
4234 
4235 	/* Structs. */
4236 	__instr_regwr_rhm_exec(p, t, ip);
4237 
4238 	/* Thread. */
4239 	thread_ip_inc(p);
4240 }
4241 
4242 static inline void
4243 instr_regwr_rmh_exec(struct rte_swx_pipeline *p)
4244 {
4245 	struct thread *t = &p->threads[p->thread_id];
4246 	struct instruction *ip = t->ip;
4247 
4248 	/* Structs. */
4249 	__instr_regwr_rmh_exec(p, t, ip);
4250 
4251 	/* Thread. */
4252 	thread_ip_inc(p);
4253 }
4254 
4255 static inline void
4256 instr_regwr_rmm_exec(struct rte_swx_pipeline *p)
4257 {
4258 	struct thread *t = &p->threads[p->thread_id];
4259 	struct instruction *ip = t->ip;
4260 
4261 	/* Structs. */
4262 	__instr_regwr_rmm_exec(p, t, ip);
4263 
4264 	/* Thread. */
4265 	thread_ip_inc(p);
4266 }
4267 
4268 static inline void
4269 instr_regwr_rhi_exec(struct rte_swx_pipeline *p)
4270 {
4271 	struct thread *t = &p->threads[p->thread_id];
4272 	struct instruction *ip = t->ip;
4273 
4274 	/* Structs. */
4275 	__instr_regwr_rhi_exec(p, t, ip);
4276 
4277 	/* Thread. */
4278 	thread_ip_inc(p);
4279 }
4280 
4281 static inline void
4282 instr_regwr_rmi_exec(struct rte_swx_pipeline *p)
4283 {
4284 	struct thread *t = &p->threads[p->thread_id];
4285 	struct instruction *ip = t->ip;
4286 
4287 	/* Structs. */
4288 	__instr_regwr_rmi_exec(p, t, ip);
4289 
4290 	/* Thread. */
4291 	thread_ip_inc(p);
4292 }
4293 
4294 static inline void
4295 instr_regwr_rih_exec(struct rte_swx_pipeline *p)
4296 {
4297 	struct thread *t = &p->threads[p->thread_id];
4298 	struct instruction *ip = t->ip;
4299 
4300 	/* Structs. */
4301 	__instr_regwr_rih_exec(p, t, ip);
4302 
4303 	/* Thread. */
4304 	thread_ip_inc(p);
4305 }
4306 
4307 static inline void
4308 instr_regwr_rim_exec(struct rte_swx_pipeline *p)
4309 {
4310 	struct thread *t = &p->threads[p->thread_id];
4311 	struct instruction *ip = t->ip;
4312 
4313 	/* Structs. */
4314 	__instr_regwr_rim_exec(p, t, ip);
4315 
4316 	/* Thread. */
4317 	thread_ip_inc(p);
4318 }
4319 
4320 static inline void
4321 instr_regwr_rii_exec(struct rte_swx_pipeline *p)
4322 {
4323 	struct thread *t = &p->threads[p->thread_id];
4324 	struct instruction *ip = t->ip;
4325 
4326 	/* Structs. */
4327 	__instr_regwr_rii_exec(p, t, ip);
4328 
4329 	/* Thread. */
4330 	thread_ip_inc(p);
4331 }
4332 
4333 static inline void
4334 instr_regadd_rhh_exec(struct rte_swx_pipeline *p)
4335 {
4336 	struct thread *t = &p->threads[p->thread_id];
4337 	struct instruction *ip = t->ip;
4338 
4339 	/* Structs. */
4340 	__instr_regadd_rhh_exec(p, t, ip);
4341 
4342 	/* Thread. */
4343 	thread_ip_inc(p);
4344 }
4345 
4346 static inline void
4347 instr_regadd_rhm_exec(struct rte_swx_pipeline *p)
4348 {
4349 	struct thread *t = &p->threads[p->thread_id];
4350 	struct instruction *ip = t->ip;
4351 
4352 	/* Structs. */
4353 	__instr_regadd_rhm_exec(p, t, ip);
4354 
4355 	/* Thread. */
4356 	thread_ip_inc(p);
4357 }
4358 
4359 static inline void
4360 instr_regadd_rmh_exec(struct rte_swx_pipeline *p)
4361 {
4362 	struct thread *t = &p->threads[p->thread_id];
4363 	struct instruction *ip = t->ip;
4364 
4365 	/* Structs. */
4366 	__instr_regadd_rmh_exec(p, t, ip);
4367 
4368 	/* Thread. */
4369 	thread_ip_inc(p);
4370 }
4371 
4372 static inline void
4373 instr_regadd_rmm_exec(struct rte_swx_pipeline *p)
4374 {
4375 	struct thread *t = &p->threads[p->thread_id];
4376 	struct instruction *ip = t->ip;
4377 
4378 	/* Structs. */
4379 	__instr_regadd_rmm_exec(p, t, ip);
4380 
4381 	/* Thread. */
4382 	thread_ip_inc(p);
4383 }
4384 
4385 static inline void
4386 instr_regadd_rhi_exec(struct rte_swx_pipeline *p)
4387 {
4388 	struct thread *t = &p->threads[p->thread_id];
4389 	struct instruction *ip = t->ip;
4390 
4391 	/* Structs. */
4392 	__instr_regadd_rhi_exec(p, t, ip);
4393 
4394 	/* Thread. */
4395 	thread_ip_inc(p);
4396 }
4397 
4398 static inline void
4399 instr_regadd_rmi_exec(struct rte_swx_pipeline *p)
4400 {
4401 	struct thread *t = &p->threads[p->thread_id];
4402 	struct instruction *ip = t->ip;
4403 
4404 	/* Structs. */
4405 	__instr_regadd_rmi_exec(p, t, ip);
4406 
4407 	/* Thread. */
4408 	thread_ip_inc(p);
4409 }
4410 
4411 static inline void
4412 instr_regadd_rih_exec(struct rte_swx_pipeline *p)
4413 {
4414 	struct thread *t = &p->threads[p->thread_id];
4415 	struct instruction *ip = t->ip;
4416 
4417 	/* Structs. */
4418 	__instr_regadd_rih_exec(p, t, ip);
4419 
4420 	/* Thread. */
4421 	thread_ip_inc(p);
4422 }
4423 
4424 static inline void
4425 instr_regadd_rim_exec(struct rte_swx_pipeline *p)
4426 {
4427 	struct thread *t = &p->threads[p->thread_id];
4428 	struct instruction *ip = t->ip;
4429 
4430 	/* Structs. */
4431 	__instr_regadd_rim_exec(p, t, ip);
4432 
4433 	/* Thread. */
4434 	thread_ip_inc(p);
4435 }
4436 
4437 static inline void
4438 instr_regadd_rii_exec(struct rte_swx_pipeline *p)
4439 {
4440 	struct thread *t = &p->threads[p->thread_id];
4441 	struct instruction *ip = t->ip;
4442 
4443 	/* Structs. */
4444 	__instr_regadd_rii_exec(p, t, ip);
4445 
4446 	/* Thread. */
4447 	thread_ip_inc(p);
4448 }
4449 
4450 /*
4451  * metarray.
4452  */
4453 static struct metarray *
4454 metarray_find(struct rte_swx_pipeline *p, const char *name);
4455 
4456 static int
4457 instr_metprefetch_translate(struct rte_swx_pipeline *p,
4458 			    struct action *action,
4459 			    char **tokens,
4460 			    int n_tokens,
4461 			    struct instruction *instr,
4462 			    struct instruction_data *data __rte_unused)
4463 {
4464 	char *metarray = tokens[1], *idx = tokens[2];
4465 	struct metarray *m;
4466 	struct field *fidx;
4467 	uint32_t idx_struct_id, idx_val;
4468 
4469 	CHECK(n_tokens == 3, EINVAL);
4470 
4471 	m = metarray_find(p, metarray);
4472 	CHECK(m, EINVAL);
4473 
4474 	/* METPREFETCH_H, METPREFETCH_M. */
4475 	fidx = struct_field_parse(p, action, idx, &idx_struct_id);
4476 	if (fidx) {
4477 		CHECK(!fidx->var_size, EINVAL);
4478 
4479 		instr->type = INSTR_METPREFETCH_M;
4480 		if (idx[0] == 'h')
4481 			instr->type = INSTR_METPREFETCH_H;
4482 
4483 		instr->meter.metarray_id = m->id;
4484 		instr->meter.idx.struct_id = (uint8_t)idx_struct_id;
4485 		instr->meter.idx.n_bits = fidx->n_bits;
4486 		instr->meter.idx.offset = fidx->offset / 8;
4487 		return 0;
4488 	}
4489 
4490 	/* METPREFETCH_I. */
4491 	idx_val = strtoul(idx, &idx, 0);
4492 	CHECK(!idx[0], EINVAL);
4493 
4494 	instr->type = INSTR_METPREFETCH_I;
4495 	instr->meter.metarray_id = m->id;
4496 	instr->meter.idx_val = idx_val;
4497 	return 0;
4498 }
4499 
4500 static int
4501 instr_meter_translate(struct rte_swx_pipeline *p,
4502 		      struct action *action,
4503 		      char **tokens,
4504 		      int n_tokens,
4505 		      struct instruction *instr,
4506 		      struct instruction_data *data __rte_unused)
4507 {
4508 	char *metarray = tokens[1], *idx = tokens[2], *length = tokens[3];
4509 	char *color_in = tokens[4], *color_out = tokens[5];
4510 	struct metarray *m;
4511 	struct field *fidx, *flength, *fcin, *fcout;
4512 	uint32_t idx_struct_id, length_struct_id;
4513 	uint32_t color_in_struct_id, color_out_struct_id;
4514 
4515 	CHECK(n_tokens == 6, EINVAL);
4516 
4517 	m = metarray_find(p, metarray);
4518 	CHECK(m, EINVAL);
4519 
4520 	fidx = struct_field_parse(p, action, idx, &idx_struct_id);
4521 
4522 	flength = struct_field_parse(p, action, length, &length_struct_id);
4523 	CHECK(flength, EINVAL);
4524 	CHECK(!flength->var_size, EINVAL);
4525 
4526 	fcin = struct_field_parse(p, action, color_in, &color_in_struct_id);
4527 
4528 	fcout = struct_field_parse(p, NULL, color_out, &color_out_struct_id);
4529 	CHECK(fcout, EINVAL);
4530 	CHECK(!fcout->var_size, EINVAL);
4531 
4532 	/* index = HMEFT, length = HMEFT, color_in = MEFT, color_out = MEF. */
4533 	if (fidx && fcin) {
4534 		CHECK(!fidx->var_size, EINVAL);
4535 		CHECK(!fcin->var_size, EINVAL);
4536 
4537 		instr->type = INSTR_METER_MMM;
4538 		if (idx[0] == 'h' && length[0] == 'h')
4539 			instr->type = INSTR_METER_HHM;
4540 		if (idx[0] == 'h' && length[0] != 'h')
4541 			instr->type = INSTR_METER_HMM;
4542 		if (idx[0] != 'h' && length[0] == 'h')
4543 			instr->type = INSTR_METER_MHM;
4544 
4545 		instr->meter.metarray_id = m->id;
4546 
4547 		instr->meter.idx.struct_id = (uint8_t)idx_struct_id;
4548 		instr->meter.idx.n_bits = fidx->n_bits;
4549 		instr->meter.idx.offset = fidx->offset / 8;
4550 
4551 		instr->meter.length.struct_id = (uint8_t)length_struct_id;
4552 		instr->meter.length.n_bits = flength->n_bits;
4553 		instr->meter.length.offset = flength->offset / 8;
4554 
4555 		instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id;
4556 		instr->meter.color_in.n_bits = fcin->n_bits;
4557 		instr->meter.color_in.offset = fcin->offset / 8;
4558 
4559 		instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4560 		instr->meter.color_out.n_bits = fcout->n_bits;
4561 		instr->meter.color_out.offset = fcout->offset / 8;
4562 	}
4563 
4564 	/* index = HMEFT, length = HMEFT, color_in = I, color_out = MEF. */
4565 	if (fidx && !fcin) {
4566 		uint32_t color_in_val;
4567 
4568 		CHECK(!fidx->var_size, EINVAL);
4569 
4570 		color_in_val = strtoul(color_in, &color_in, 0);
4571 		CHECK(!color_in[0], EINVAL);
4572 
4573 		instr->type = INSTR_METER_MMI;
4574 		if (idx[0] == 'h' && length[0] == 'h')
4575 			instr->type = INSTR_METER_HHI;
4576 		if (idx[0] == 'h' && length[0] != 'h')
4577 			instr->type = INSTR_METER_HMI;
4578 		if (idx[0] != 'h' && length[0] == 'h')
4579 			instr->type = INSTR_METER_MHI;
4580 
4581 		instr->meter.metarray_id = m->id;
4582 
4583 		instr->meter.idx.struct_id = (uint8_t)idx_struct_id;
4584 		instr->meter.idx.n_bits = fidx->n_bits;
4585 		instr->meter.idx.offset = fidx->offset / 8;
4586 
4587 		instr->meter.length.struct_id = (uint8_t)length_struct_id;
4588 		instr->meter.length.n_bits = flength->n_bits;
4589 		instr->meter.length.offset = flength->offset / 8;
4590 
4591 		instr->meter.color_in_val = color_in_val;
4592 
4593 		instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4594 		instr->meter.color_out.n_bits = fcout->n_bits;
4595 		instr->meter.color_out.offset = fcout->offset / 8;
4596 	}
4597 
4598 	/* index = I, length = HMEFT, color_in = MEFT, color_out = MEF. */
4599 	if (!fidx && fcin) {
4600 		uint32_t idx_val;
4601 
4602 		idx_val = strtoul(idx, &idx, 0);
4603 		CHECK(!idx[0], EINVAL);
4604 
4605 		CHECK(!fcin->var_size, EINVAL);
4606 
4607 		instr->type = INSTR_METER_IMM;
4608 		if (length[0] == 'h')
4609 			instr->type = INSTR_METER_IHM;
4610 
4611 		instr->meter.metarray_id = m->id;
4612 
4613 		instr->meter.idx_val = idx_val;
4614 
4615 		instr->meter.length.struct_id = (uint8_t)length_struct_id;
4616 		instr->meter.length.n_bits = flength->n_bits;
4617 		instr->meter.length.offset = flength->offset / 8;
4618 
4619 		instr->meter.color_in.struct_id = (uint8_t)color_in_struct_id;
4620 		instr->meter.color_in.n_bits = fcin->n_bits;
4621 		instr->meter.color_in.offset = fcin->offset / 8;
4622 
4623 		instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4624 		instr->meter.color_out.n_bits = fcout->n_bits;
4625 		instr->meter.color_out.offset = fcout->offset / 8;
4626 	}
4627 
4628 	/* index = I, length = HMEFT, color_in = I, color_out = MEF. */
4629 	if (!fidx && !fcin) {
4630 		uint32_t idx_val, color_in_val;
4631 
4632 		idx_val = strtoul(idx, &idx, 0);
4633 		CHECK(!idx[0], EINVAL);
4634 
4635 		color_in_val = strtoul(color_in, &color_in, 0);
4636 		CHECK(!color_in[0], EINVAL);
4637 
4638 		instr->type = INSTR_METER_IMI;
4639 		if (length[0] == 'h')
4640 			instr->type = INSTR_METER_IHI;
4641 
4642 		instr->meter.metarray_id = m->id;
4643 
4644 		instr->meter.idx_val = idx_val;
4645 
4646 		instr->meter.length.struct_id = (uint8_t)length_struct_id;
4647 		instr->meter.length.n_bits = flength->n_bits;
4648 		instr->meter.length.offset = flength->offset / 8;
4649 
4650 		instr->meter.color_in_val = color_in_val;
4651 
4652 		instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
4653 		instr->meter.color_out.n_bits = fcout->n_bits;
4654 		instr->meter.color_out.offset = fcout->offset / 8;
4655 	}
4656 
4657 	return 0;
4658 }
4659 
4660 static inline void
4661 instr_metprefetch_h_exec(struct rte_swx_pipeline *p)
4662 {
4663 	struct thread *t = &p->threads[p->thread_id];
4664 	struct instruction *ip = t->ip;
4665 
4666 	/* Structs. */
4667 	__instr_metprefetch_h_exec(p, t, ip);
4668 
4669 	/* Thread. */
4670 	thread_ip_inc(p);
4671 }
4672 
4673 static inline void
4674 instr_metprefetch_m_exec(struct rte_swx_pipeline *p)
4675 {
4676 	struct thread *t = &p->threads[p->thread_id];
4677 	struct instruction *ip = t->ip;
4678 
4679 	/* Structs. */
4680 	__instr_metprefetch_m_exec(p, t, ip);
4681 
4682 	/* Thread. */
4683 	thread_ip_inc(p);
4684 }
4685 
4686 static inline void
4687 instr_metprefetch_i_exec(struct rte_swx_pipeline *p)
4688 {
4689 	struct thread *t = &p->threads[p->thread_id];
4690 	struct instruction *ip = t->ip;
4691 
4692 	/* Structs. */
4693 	__instr_metprefetch_i_exec(p, t, ip);
4694 
4695 	/* Thread. */
4696 	thread_ip_inc(p);
4697 }
4698 
4699 static inline void
4700 instr_meter_hhm_exec(struct rte_swx_pipeline *p)
4701 {
4702 	struct thread *t = &p->threads[p->thread_id];
4703 	struct instruction *ip = t->ip;
4704 
4705 	/* Structs. */
4706 	__instr_meter_hhm_exec(p, t, ip);
4707 
4708 	/* Thread. */
4709 	thread_ip_inc(p);
4710 }
4711 
4712 static inline void
4713 instr_meter_hhi_exec(struct rte_swx_pipeline *p)
4714 {
4715 	struct thread *t = &p->threads[p->thread_id];
4716 	struct instruction *ip = t->ip;
4717 
4718 	/* Structs. */
4719 	__instr_meter_hhi_exec(p, t, ip);
4720 
4721 	/* Thread. */
4722 	thread_ip_inc(p);
4723 }
4724 
4725 static inline void
4726 instr_meter_hmm_exec(struct rte_swx_pipeline *p)
4727 {
4728 	struct thread *t = &p->threads[p->thread_id];
4729 	struct instruction *ip = t->ip;
4730 
4731 	/* Structs. */
4732 	__instr_meter_hmm_exec(p, t, ip);
4733 
4734 	/* Thread. */
4735 	thread_ip_inc(p);
4736 }
4737 
4738 static inline void
4739 instr_meter_hmi_exec(struct rte_swx_pipeline *p)
4740 {
4741 	struct thread *t = &p->threads[p->thread_id];
4742 	struct instruction *ip = t->ip;
4743 
4744 	/* Structs. */
4745 	__instr_meter_hmi_exec(p, t, ip);
4746 
4747 	/* Thread. */
4748 	thread_ip_inc(p);
4749 }
4750 
4751 static inline void
4752 instr_meter_mhm_exec(struct rte_swx_pipeline *p)
4753 {
4754 	struct thread *t = &p->threads[p->thread_id];
4755 	struct instruction *ip = t->ip;
4756 
4757 	/* Structs. */
4758 	__instr_meter_mhm_exec(p, t, ip);
4759 
4760 	/* Thread. */
4761 	thread_ip_inc(p);
4762 }
4763 
4764 static inline void
4765 instr_meter_mhi_exec(struct rte_swx_pipeline *p)
4766 {
4767 	struct thread *t = &p->threads[p->thread_id];
4768 	struct instruction *ip = t->ip;
4769 
4770 	/* Structs. */
4771 	__instr_meter_mhi_exec(p, t, ip);
4772 
4773 	/* Thread. */
4774 	thread_ip_inc(p);
4775 }
4776 
4777 static inline void
4778 instr_meter_mmm_exec(struct rte_swx_pipeline *p)
4779 {
4780 	struct thread *t = &p->threads[p->thread_id];
4781 	struct instruction *ip = t->ip;
4782 
4783 	/* Structs. */
4784 	__instr_meter_mmm_exec(p, t, ip);
4785 
4786 	/* Thread. */
4787 	thread_ip_inc(p);
4788 }
4789 
4790 static inline void
4791 instr_meter_mmi_exec(struct rte_swx_pipeline *p)
4792 {
4793 	struct thread *t = &p->threads[p->thread_id];
4794 	struct instruction *ip = t->ip;
4795 
4796 	/* Structs. */
4797 	__instr_meter_mmi_exec(p, t, ip);
4798 
4799 	/* Thread. */
4800 	thread_ip_inc(p);
4801 }
4802 
4803 static inline void
4804 instr_meter_ihm_exec(struct rte_swx_pipeline *p)
4805 {
4806 	struct thread *t = &p->threads[p->thread_id];
4807 	struct instruction *ip = t->ip;
4808 
4809 	/* Structs. */
4810 	__instr_meter_ihm_exec(p, t, ip);
4811 
4812 	/* Thread. */
4813 	thread_ip_inc(p);
4814 }
4815 
4816 static inline void
4817 instr_meter_ihi_exec(struct rte_swx_pipeline *p)
4818 {
4819 	struct thread *t = &p->threads[p->thread_id];
4820 	struct instruction *ip = t->ip;
4821 
4822 	/* Structs. */
4823 	__instr_meter_ihi_exec(p, t, ip);
4824 
4825 	/* Thread. */
4826 	thread_ip_inc(p);
4827 }
4828 
4829 static inline void
4830 instr_meter_imm_exec(struct rte_swx_pipeline *p)
4831 {
4832 	struct thread *t = &p->threads[p->thread_id];
4833 	struct instruction *ip = t->ip;
4834 
4835 	/* Structs. */
4836 	__instr_meter_imm_exec(p, t, ip);
4837 
4838 	/* Thread. */
4839 	thread_ip_inc(p);
4840 }
4841 
4842 static inline void
4843 instr_meter_imi_exec(struct rte_swx_pipeline *p)
4844 {
4845 	struct thread *t = &p->threads[p->thread_id];
4846 	struct instruction *ip = t->ip;
4847 
4848 	/* Structs. */
4849 	__instr_meter_imi_exec(p, t, ip);
4850 
4851 	/* Thread. */
4852 	thread_ip_inc(p);
4853 }
4854 
4855 /*
4856  * jmp.
4857  */
4858 static int
4859 instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,
4860 		    struct action *action __rte_unused,
4861 		    char **tokens,
4862 		    int n_tokens,
4863 		    struct instruction *instr,
4864 		    struct instruction_data *data)
4865 {
4866 	CHECK(n_tokens == 2, EINVAL);
4867 
4868 	strcpy(data->jmp_label, tokens[1]);
4869 
4870 	instr->type = INSTR_JMP;
4871 	instr->jmp.ip = NULL; /* Resolved later. */
4872 	return 0;
4873 }
4874 
4875 static int
4876 instr_jmp_valid_translate(struct rte_swx_pipeline *p,
4877 			  struct action *action __rte_unused,
4878 			  char **tokens,
4879 			  int n_tokens,
4880 			  struct instruction *instr,
4881 			  struct instruction_data *data)
4882 {
4883 	struct header *h;
4884 
4885 	CHECK(n_tokens == 3, EINVAL);
4886 
4887 	strcpy(data->jmp_label, tokens[1]);
4888 
4889 	h = header_parse(p, tokens[2]);
4890 	CHECK(h, EINVAL);
4891 
4892 	instr->type = INSTR_JMP_VALID;
4893 	instr->jmp.ip = NULL; /* Resolved later. */
4894 	instr->jmp.header_id = h->id;
4895 	return 0;
4896 }
4897 
4898 static int
4899 instr_jmp_invalid_translate(struct rte_swx_pipeline *p,
4900 			    struct action *action __rte_unused,
4901 			    char **tokens,
4902 			    int n_tokens,
4903 			    struct instruction *instr,
4904 			    struct instruction_data *data)
4905 {
4906 	struct header *h;
4907 
4908 	CHECK(n_tokens == 3, EINVAL);
4909 
4910 	strcpy(data->jmp_label, tokens[1]);
4911 
4912 	h = header_parse(p, tokens[2]);
4913 	CHECK(h, EINVAL);
4914 
4915 	instr->type = INSTR_JMP_INVALID;
4916 	instr->jmp.ip = NULL; /* Resolved later. */
4917 	instr->jmp.header_id = h->id;
4918 	return 0;
4919 }
4920 
4921 static int
4922 instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,
4923 			struct action *action,
4924 			char **tokens,
4925 			int n_tokens,
4926 			struct instruction *instr,
4927 			struct instruction_data *data)
4928 {
4929 	CHECK(!action, EINVAL);
4930 	CHECK(n_tokens == 2, EINVAL);
4931 
4932 	strcpy(data->jmp_label, tokens[1]);
4933 
4934 	instr->type = INSTR_JMP_HIT;
4935 	instr->jmp.ip = NULL; /* Resolved later. */
4936 	return 0;
4937 }
4938 
4939 static int
4940 instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,
4941 			 struct action *action,
4942 			 char **tokens,
4943 			 int n_tokens,
4944 			 struct instruction *instr,
4945 			 struct instruction_data *data)
4946 {
4947 	CHECK(!action, EINVAL);
4948 	CHECK(n_tokens == 2, EINVAL);
4949 
4950 	strcpy(data->jmp_label, tokens[1]);
4951 
4952 	instr->type = INSTR_JMP_MISS;
4953 	instr->jmp.ip = NULL; /* Resolved later. */
4954 	return 0;
4955 }
4956 
4957 static int
4958 instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,
4959 			       struct action *action,
4960 			       char **tokens,
4961 			       int n_tokens,
4962 			       struct instruction *instr,
4963 			       struct instruction_data *data)
4964 {
4965 	struct action *a;
4966 
4967 	CHECK(!action, EINVAL);
4968 	CHECK(n_tokens == 3, EINVAL);
4969 
4970 	strcpy(data->jmp_label, tokens[1]);
4971 
4972 	a = action_find(p, tokens[2]);
4973 	CHECK(a, EINVAL);
4974 
4975 	instr->type = INSTR_JMP_ACTION_HIT;
4976 	instr->jmp.ip = NULL; /* Resolved later. */
4977 	instr->jmp.action_id = a->id;
4978 	return 0;
4979 }
4980 
4981 static int
4982 instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,
4983 				struct action *action,
4984 				char **tokens,
4985 				int n_tokens,
4986 				struct instruction *instr,
4987 				struct instruction_data *data)
4988 {
4989 	struct action *a;
4990 
4991 	CHECK(!action, EINVAL);
4992 	CHECK(n_tokens == 3, EINVAL);
4993 
4994 	strcpy(data->jmp_label, tokens[1]);
4995 
4996 	a = action_find(p, tokens[2]);
4997 	CHECK(a, EINVAL);
4998 
4999 	instr->type = INSTR_JMP_ACTION_MISS;
5000 	instr->jmp.ip = NULL; /* Resolved later. */
5001 	instr->jmp.action_id = a->id;
5002 	return 0;
5003 }
5004 
5005 static int
5006 instr_jmp_eq_translate(struct rte_swx_pipeline *p,
5007 		       struct action *action,
5008 		       char **tokens,
5009 		       int n_tokens,
5010 		       struct instruction *instr,
5011 		       struct instruction_data *data)
5012 {
5013 	char *a = tokens[2], *b = tokens[3];
5014 	struct field *fa, *fb;
5015 	uint64_t b_val;
5016 	uint32_t a_struct_id, b_struct_id;
5017 
5018 	CHECK(n_tokens == 4, EINVAL);
5019 
5020 	strcpy(data->jmp_label, tokens[1]);
5021 
5022 	fa = struct_field_parse(p, action, a, &a_struct_id);
5023 	CHECK(fa, EINVAL);
5024 	CHECK(!fa->var_size, EINVAL);
5025 
5026 	/* JMP_EQ, JMP_EQ_MH, JMP_EQ_HM, JMP_EQ_HH. */
5027 	fb = struct_field_parse(p, action, b, &b_struct_id);
5028 	if (fb) {
5029 		CHECK(!fb->var_size, EINVAL);
5030 
5031 		instr->type = INSTR_JMP_EQ;
5032 		if (a[0] != 'h' && b[0] == 'h')
5033 			instr->type = INSTR_JMP_EQ_MH;
5034 		if (a[0] == 'h' && b[0] != 'h')
5035 			instr->type = INSTR_JMP_EQ_HM;
5036 		if (a[0] == 'h' && b[0] == 'h')
5037 			instr->type = INSTR_JMP_EQ_HH;
5038 		instr->jmp.ip = NULL; /* Resolved later. */
5039 
5040 		instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5041 		instr->jmp.a.n_bits = fa->n_bits;
5042 		instr->jmp.a.offset = fa->offset / 8;
5043 		instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5044 		instr->jmp.b.n_bits = fb->n_bits;
5045 		instr->jmp.b.offset = fb->offset / 8;
5046 		return 0;
5047 	}
5048 
5049 	/* JMP_EQ_I. */
5050 	b_val = strtoull(b, &b, 0);
5051 	CHECK(!b[0], EINVAL);
5052 
5053 	if (a[0] == 'h')
5054 		b_val = hton64(b_val) >> (64 - fa->n_bits);
5055 
5056 	instr->type = INSTR_JMP_EQ_I;
5057 	instr->jmp.ip = NULL; /* Resolved later. */
5058 	instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5059 	instr->jmp.a.n_bits = fa->n_bits;
5060 	instr->jmp.a.offset = fa->offset / 8;
5061 	instr->jmp.b_val = b_val;
5062 	return 0;
5063 }
5064 
5065 static int
5066 instr_jmp_neq_translate(struct rte_swx_pipeline *p,
5067 			struct action *action,
5068 			char **tokens,
5069 			int n_tokens,
5070 			struct instruction *instr,
5071 			struct instruction_data *data)
5072 {
5073 	char *a = tokens[2], *b = tokens[3];
5074 	struct field *fa, *fb;
5075 	uint64_t b_val;
5076 	uint32_t a_struct_id, b_struct_id;
5077 
5078 	CHECK(n_tokens == 4, EINVAL);
5079 
5080 	strcpy(data->jmp_label, tokens[1]);
5081 
5082 	fa = struct_field_parse(p, action, a, &a_struct_id);
5083 	CHECK(fa, EINVAL);
5084 	CHECK(!fa->var_size, EINVAL);
5085 
5086 	/* JMP_NEQ, JMP_NEQ_MH, JMP_NEQ_HM, JMP_NEQ_HH. */
5087 	fb = struct_field_parse(p, action, b, &b_struct_id);
5088 	if (fb) {
5089 		CHECK(!fb->var_size, EINVAL);
5090 
5091 		instr->type = INSTR_JMP_NEQ;
5092 		if (a[0] != 'h' && b[0] == 'h')
5093 			instr->type = INSTR_JMP_NEQ_MH;
5094 		if (a[0] == 'h' && b[0] != 'h')
5095 			instr->type = INSTR_JMP_NEQ_HM;
5096 		if (a[0] == 'h' && b[0] == 'h')
5097 			instr->type = INSTR_JMP_NEQ_HH;
5098 		instr->jmp.ip = NULL; /* Resolved later. */
5099 
5100 		instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5101 		instr->jmp.a.n_bits = fa->n_bits;
5102 		instr->jmp.a.offset = fa->offset / 8;
5103 		instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5104 		instr->jmp.b.n_bits = fb->n_bits;
5105 		instr->jmp.b.offset = fb->offset / 8;
5106 		return 0;
5107 	}
5108 
5109 	/* JMP_NEQ_I. */
5110 	b_val = strtoull(b, &b, 0);
5111 	CHECK(!b[0], EINVAL);
5112 
5113 	if (a[0] == 'h')
5114 		b_val = hton64(b_val) >> (64 - fa->n_bits);
5115 
5116 	instr->type = INSTR_JMP_NEQ_I;
5117 	instr->jmp.ip = NULL; /* Resolved later. */
5118 	instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5119 	instr->jmp.a.n_bits = fa->n_bits;
5120 	instr->jmp.a.offset = fa->offset / 8;
5121 	instr->jmp.b_val = b_val;
5122 	return 0;
5123 }
5124 
5125 static int
5126 instr_jmp_lt_translate(struct rte_swx_pipeline *p,
5127 		       struct action *action,
5128 		       char **tokens,
5129 		       int n_tokens,
5130 		       struct instruction *instr,
5131 		       struct instruction_data *data)
5132 {
5133 	char *a = tokens[2], *b = tokens[3];
5134 	struct field *fa, *fb;
5135 	uint64_t b_val;
5136 	uint32_t a_struct_id, b_struct_id;
5137 
5138 	CHECK(n_tokens == 4, EINVAL);
5139 
5140 	strcpy(data->jmp_label, tokens[1]);
5141 
5142 	fa = struct_field_parse(p, action, a, &a_struct_id);
5143 	CHECK(fa, EINVAL);
5144 	CHECK(!fa->var_size, EINVAL);
5145 
5146 	/* JMP_LT, JMP_LT_MH, JMP_LT_HM, JMP_LT_HH. */
5147 	fb = struct_field_parse(p, action, b, &b_struct_id);
5148 	if (fb) {
5149 		CHECK(!fb->var_size, EINVAL);
5150 
5151 		instr->type = INSTR_JMP_LT;
5152 		if (a[0] == 'h' && b[0] != 'h')
5153 			instr->type = INSTR_JMP_LT_HM;
5154 		if (a[0] != 'h' && b[0] == 'h')
5155 			instr->type = INSTR_JMP_LT_MH;
5156 		if (a[0] == 'h' && b[0] == 'h')
5157 			instr->type = INSTR_JMP_LT_HH;
5158 		instr->jmp.ip = NULL; /* Resolved later. */
5159 
5160 		instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5161 		instr->jmp.a.n_bits = fa->n_bits;
5162 		instr->jmp.a.offset = fa->offset / 8;
5163 		instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5164 		instr->jmp.b.n_bits = fb->n_bits;
5165 		instr->jmp.b.offset = fb->offset / 8;
5166 		return 0;
5167 	}
5168 
5169 	/* JMP_LT_MI, JMP_LT_HI. */
5170 	b_val = strtoull(b, &b, 0);
5171 	CHECK(!b[0], EINVAL);
5172 
5173 	instr->type = INSTR_JMP_LT_MI;
5174 	if (a[0] == 'h')
5175 		instr->type = INSTR_JMP_LT_HI;
5176 	instr->jmp.ip = NULL; /* Resolved later. */
5177 
5178 	instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5179 	instr->jmp.a.n_bits = fa->n_bits;
5180 	instr->jmp.a.offset = fa->offset / 8;
5181 	instr->jmp.b_val = b_val;
5182 	return 0;
5183 }
5184 
5185 static int
5186 instr_jmp_gt_translate(struct rte_swx_pipeline *p,
5187 		       struct action *action,
5188 		       char **tokens,
5189 		       int n_tokens,
5190 		       struct instruction *instr,
5191 		       struct instruction_data *data)
5192 {
5193 	char *a = tokens[2], *b = tokens[3];
5194 	struct field *fa, *fb;
5195 	uint64_t b_val;
5196 	uint32_t a_struct_id, b_struct_id;
5197 
5198 	CHECK(n_tokens == 4, EINVAL);
5199 
5200 	strcpy(data->jmp_label, tokens[1]);
5201 
5202 	fa = struct_field_parse(p, action, a, &a_struct_id);
5203 	CHECK(fa, EINVAL);
5204 	CHECK(!fa->var_size, EINVAL);
5205 
5206 	/* JMP_GT, JMP_GT_MH, JMP_GT_HM, JMP_GT_HH. */
5207 	fb = struct_field_parse(p, action, b, &b_struct_id);
5208 	if (fb) {
5209 		CHECK(!fb->var_size, EINVAL);
5210 
5211 		instr->type = INSTR_JMP_GT;
5212 		if (a[0] == 'h' && b[0] != 'h')
5213 			instr->type = INSTR_JMP_GT_HM;
5214 		if (a[0] != 'h' && b[0] == 'h')
5215 			instr->type = INSTR_JMP_GT_MH;
5216 		if (a[0] == 'h' && b[0] == 'h')
5217 			instr->type = INSTR_JMP_GT_HH;
5218 		instr->jmp.ip = NULL; /* Resolved later. */
5219 
5220 		instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5221 		instr->jmp.a.n_bits = fa->n_bits;
5222 		instr->jmp.a.offset = fa->offset / 8;
5223 		instr->jmp.b.struct_id = (uint8_t)b_struct_id;
5224 		instr->jmp.b.n_bits = fb->n_bits;
5225 		instr->jmp.b.offset = fb->offset / 8;
5226 		return 0;
5227 	}
5228 
5229 	/* JMP_GT_MI, JMP_GT_HI. */
5230 	b_val = strtoull(b, &b, 0);
5231 	CHECK(!b[0], EINVAL);
5232 
5233 	instr->type = INSTR_JMP_GT_MI;
5234 	if (a[0] == 'h')
5235 		instr->type = INSTR_JMP_GT_HI;
5236 	instr->jmp.ip = NULL; /* Resolved later. */
5237 
5238 	instr->jmp.a.struct_id = (uint8_t)a_struct_id;
5239 	instr->jmp.a.n_bits = fa->n_bits;
5240 	instr->jmp.a.offset = fa->offset / 8;
5241 	instr->jmp.b_val = b_val;
5242 	return 0;
5243 }
5244 
5245 static inline void
5246 instr_jmp_exec(struct rte_swx_pipeline *p)
5247 {
5248 	struct thread *t = &p->threads[p->thread_id];
5249 	struct instruction *ip = t->ip;
5250 
5251 	TRACE("[Thread %2u] jmp\n", p->thread_id);
5252 
5253 	thread_ip_set(t, ip->jmp.ip);
5254 }
5255 
5256 static inline void
5257 instr_jmp_valid_exec(struct rte_swx_pipeline *p)
5258 {
5259 	struct thread *t = &p->threads[p->thread_id];
5260 	struct instruction *ip = t->ip;
5261 	uint32_t header_id = ip->jmp.header_id;
5262 
5263 	TRACE("[Thread %2u] jmpv\n", p->thread_id);
5264 
5265 	t->ip = HEADER_VALID(t, header_id) ? ip->jmp.ip : (t->ip + 1);
5266 }
5267 
5268 static inline void
5269 instr_jmp_invalid_exec(struct rte_swx_pipeline *p)
5270 {
5271 	struct thread *t = &p->threads[p->thread_id];
5272 	struct instruction *ip = t->ip;
5273 	uint32_t header_id = ip->jmp.header_id;
5274 
5275 	TRACE("[Thread %2u] jmpnv\n", p->thread_id);
5276 
5277 	t->ip = HEADER_VALID(t, header_id) ? (t->ip + 1) : ip->jmp.ip;
5278 }
5279 
5280 static inline void
5281 instr_jmp_hit_exec(struct rte_swx_pipeline *p)
5282 {
5283 	struct thread *t = &p->threads[p->thread_id];
5284 	struct instruction *ip = t->ip;
5285 	struct instruction *ip_next[] = {t->ip + 1, ip->jmp.ip};
5286 
5287 	TRACE("[Thread %2u] jmph\n", p->thread_id);
5288 
5289 	t->ip = ip_next[t->hit];
5290 }
5291 
5292 static inline void
5293 instr_jmp_miss_exec(struct rte_swx_pipeline *p)
5294 {
5295 	struct thread *t = &p->threads[p->thread_id];
5296 	struct instruction *ip = t->ip;
5297 	struct instruction *ip_next[] = {ip->jmp.ip, t->ip + 1};
5298 
5299 	TRACE("[Thread %2u] jmpnh\n", p->thread_id);
5300 
5301 	t->ip = ip_next[t->hit];
5302 }
5303 
5304 static inline void
5305 instr_jmp_action_hit_exec(struct rte_swx_pipeline *p)
5306 {
5307 	struct thread *t = &p->threads[p->thread_id];
5308 	struct instruction *ip = t->ip;
5309 
5310 	TRACE("[Thread %2u] jmpa\n", p->thread_id);
5311 
5312 	t->ip = (ip->jmp.action_id == t->action_id) ? ip->jmp.ip : (t->ip + 1);
5313 }
5314 
5315 static inline void
5316 instr_jmp_action_miss_exec(struct rte_swx_pipeline *p)
5317 {
5318 	struct thread *t = &p->threads[p->thread_id];
5319 	struct instruction *ip = t->ip;
5320 
5321 	TRACE("[Thread %2u] jmpna\n", p->thread_id);
5322 
5323 	t->ip = (ip->jmp.action_id == t->action_id) ? (t->ip + 1) : ip->jmp.ip;
5324 }
5325 
5326 static inline void
5327 instr_jmp_eq_exec(struct rte_swx_pipeline *p)
5328 {
5329 	struct thread *t = &p->threads[p->thread_id];
5330 	struct instruction *ip = t->ip;
5331 
5332 	TRACE("[Thread %2u] jmpeq\n", p->thread_id);
5333 
5334 	JMP_CMP(t, ip, ==);
5335 }
5336 
5337 static inline void
5338 instr_jmp_eq_mh_exec(struct rte_swx_pipeline *p)
5339 {
5340 	struct thread *t = &p->threads[p->thread_id];
5341 	struct instruction *ip = t->ip;
5342 
5343 	TRACE("[Thread %2u] jmpeq (mh)\n", p->thread_id);
5344 
5345 	JMP_CMP_MH(t, ip, ==);
5346 }
5347 
5348 static inline void
5349 instr_jmp_eq_hm_exec(struct rte_swx_pipeline *p)
5350 {
5351 	struct thread *t = &p->threads[p->thread_id];
5352 	struct instruction *ip = t->ip;
5353 
5354 	TRACE("[Thread %2u] jmpeq (hm)\n", p->thread_id);
5355 
5356 	JMP_CMP_HM(t, ip, ==);
5357 }
5358 
5359 static inline void
5360 instr_jmp_eq_hh_exec(struct rte_swx_pipeline *p)
5361 {
5362 	struct thread *t = &p->threads[p->thread_id];
5363 	struct instruction *ip = t->ip;
5364 
5365 	TRACE("[Thread %2u] jmpeq (hh)\n", p->thread_id);
5366 
5367 	JMP_CMP_HH_FAST(t, ip, ==);
5368 }
5369 
5370 static inline void
5371 instr_jmp_eq_i_exec(struct rte_swx_pipeline *p)
5372 {
5373 	struct thread *t = &p->threads[p->thread_id];
5374 	struct instruction *ip = t->ip;
5375 
5376 	TRACE("[Thread %2u] jmpeq (i)\n", p->thread_id);
5377 
5378 	JMP_CMP_I(t, ip, ==);
5379 }
5380 
5381 static inline void
5382 instr_jmp_neq_exec(struct rte_swx_pipeline *p)
5383 {
5384 	struct thread *t = &p->threads[p->thread_id];
5385 	struct instruction *ip = t->ip;
5386 
5387 	TRACE("[Thread %2u] jmpneq\n", p->thread_id);
5388 
5389 	JMP_CMP(t, ip, !=);
5390 }
5391 
5392 static inline void
5393 instr_jmp_neq_mh_exec(struct rte_swx_pipeline *p)
5394 {
5395 	struct thread *t = &p->threads[p->thread_id];
5396 	struct instruction *ip = t->ip;
5397 
5398 	TRACE("[Thread %2u] jmpneq (mh)\n", p->thread_id);
5399 
5400 	JMP_CMP_MH(t, ip, !=);
5401 }
5402 
5403 static inline void
5404 instr_jmp_neq_hm_exec(struct rte_swx_pipeline *p)
5405 {
5406 	struct thread *t = &p->threads[p->thread_id];
5407 	struct instruction *ip = t->ip;
5408 
5409 	TRACE("[Thread %2u] jmpneq (hm)\n", p->thread_id);
5410 
5411 	JMP_CMP_HM(t, ip, !=);
5412 }
5413 
5414 static inline void
5415 instr_jmp_neq_hh_exec(struct rte_swx_pipeline *p)
5416 {
5417 	struct thread *t = &p->threads[p->thread_id];
5418 	struct instruction *ip = t->ip;
5419 
5420 	TRACE("[Thread %2u] jmpneq (hh)\n", p->thread_id);
5421 
5422 	JMP_CMP_HH_FAST(t, ip, !=);
5423 }
5424 
5425 static inline void
5426 instr_jmp_neq_i_exec(struct rte_swx_pipeline *p)
5427 {
5428 	struct thread *t = &p->threads[p->thread_id];
5429 	struct instruction *ip = t->ip;
5430 
5431 	TRACE("[Thread %2u] jmpneq (i)\n", p->thread_id);
5432 
5433 	JMP_CMP_I(t, ip, !=);
5434 }
5435 
5436 static inline void
5437 instr_jmp_lt_exec(struct rte_swx_pipeline *p)
5438 {
5439 	struct thread *t = &p->threads[p->thread_id];
5440 	struct instruction *ip = t->ip;
5441 
5442 	TRACE("[Thread %2u] jmplt\n", p->thread_id);
5443 
5444 	JMP_CMP(t, ip, <);
5445 }
5446 
5447 static inline void
5448 instr_jmp_lt_mh_exec(struct rte_swx_pipeline *p)
5449 {
5450 	struct thread *t = &p->threads[p->thread_id];
5451 	struct instruction *ip = t->ip;
5452 
5453 	TRACE("[Thread %2u] jmplt (mh)\n", p->thread_id);
5454 
5455 	JMP_CMP_MH(t, ip, <);
5456 }
5457 
5458 static inline void
5459 instr_jmp_lt_hm_exec(struct rte_swx_pipeline *p)
5460 {
5461 	struct thread *t = &p->threads[p->thread_id];
5462 	struct instruction *ip = t->ip;
5463 
5464 	TRACE("[Thread %2u] jmplt (hm)\n", p->thread_id);
5465 
5466 	JMP_CMP_HM(t, ip, <);
5467 }
5468 
5469 static inline void
5470 instr_jmp_lt_hh_exec(struct rte_swx_pipeline *p)
5471 {
5472 	struct thread *t = &p->threads[p->thread_id];
5473 	struct instruction *ip = t->ip;
5474 
5475 	TRACE("[Thread %2u] jmplt (hh)\n", p->thread_id);
5476 
5477 	JMP_CMP_HH(t, ip, <);
5478 }
5479 
5480 static inline void
5481 instr_jmp_lt_mi_exec(struct rte_swx_pipeline *p)
5482 {
5483 	struct thread *t = &p->threads[p->thread_id];
5484 	struct instruction *ip = t->ip;
5485 
5486 	TRACE("[Thread %2u] jmplt (mi)\n", p->thread_id);
5487 
5488 	JMP_CMP_MI(t, ip, <);
5489 }
5490 
5491 static inline void
5492 instr_jmp_lt_hi_exec(struct rte_swx_pipeline *p)
5493 {
5494 	struct thread *t = &p->threads[p->thread_id];
5495 	struct instruction *ip = t->ip;
5496 
5497 	TRACE("[Thread %2u] jmplt (hi)\n", p->thread_id);
5498 
5499 	JMP_CMP_HI(t, ip, <);
5500 }
5501 
5502 static inline void
5503 instr_jmp_gt_exec(struct rte_swx_pipeline *p)
5504 {
5505 	struct thread *t = &p->threads[p->thread_id];
5506 	struct instruction *ip = t->ip;
5507 
5508 	TRACE("[Thread %2u] jmpgt\n", p->thread_id);
5509 
5510 	JMP_CMP(t, ip, >);
5511 }
5512 
5513 static inline void
5514 instr_jmp_gt_mh_exec(struct rte_swx_pipeline *p)
5515 {
5516 	struct thread *t = &p->threads[p->thread_id];
5517 	struct instruction *ip = t->ip;
5518 
5519 	TRACE("[Thread %2u] jmpgt (mh)\n", p->thread_id);
5520 
5521 	JMP_CMP_MH(t, ip, >);
5522 }
5523 
5524 static inline void
5525 instr_jmp_gt_hm_exec(struct rte_swx_pipeline *p)
5526 {
5527 	struct thread *t = &p->threads[p->thread_id];
5528 	struct instruction *ip = t->ip;
5529 
5530 	TRACE("[Thread %2u] jmpgt (hm)\n", p->thread_id);
5531 
5532 	JMP_CMP_HM(t, ip, >);
5533 }
5534 
5535 static inline void
5536 instr_jmp_gt_hh_exec(struct rte_swx_pipeline *p)
5537 {
5538 	struct thread *t = &p->threads[p->thread_id];
5539 	struct instruction *ip = t->ip;
5540 
5541 	TRACE("[Thread %2u] jmpgt (hh)\n", p->thread_id);
5542 
5543 	JMP_CMP_HH(t, ip, >);
5544 }
5545 
5546 static inline void
5547 instr_jmp_gt_mi_exec(struct rte_swx_pipeline *p)
5548 {
5549 	struct thread *t = &p->threads[p->thread_id];
5550 	struct instruction *ip = t->ip;
5551 
5552 	TRACE("[Thread %2u] jmpgt (mi)\n", p->thread_id);
5553 
5554 	JMP_CMP_MI(t, ip, >);
5555 }
5556 
5557 static inline void
5558 instr_jmp_gt_hi_exec(struct rte_swx_pipeline *p)
5559 {
5560 	struct thread *t = &p->threads[p->thread_id];
5561 	struct instruction *ip = t->ip;
5562 
5563 	TRACE("[Thread %2u] jmpgt (hi)\n", p->thread_id);
5564 
5565 	JMP_CMP_HI(t, ip, >);
5566 }
5567 
5568 /*
5569  * return.
5570  */
5571 static int
5572 instr_return_translate(struct rte_swx_pipeline *p __rte_unused,
5573 		       struct action *action,
5574 		       char **tokens __rte_unused,
5575 		       int n_tokens,
5576 		       struct instruction *instr,
5577 		       struct instruction_data *data __rte_unused)
5578 {
5579 	CHECK(action, EINVAL);
5580 	CHECK(n_tokens == 1, EINVAL);
5581 
5582 	instr->type = INSTR_RETURN;
5583 	return 0;
5584 }
5585 
5586 static inline void
5587 instr_return_exec(struct rte_swx_pipeline *p)
5588 {
5589 	struct thread *t = &p->threads[p->thread_id];
5590 
5591 	TRACE("[Thread %2u] return\n", p->thread_id);
5592 
5593 	t->ip = t->ret;
5594 }
5595 
5596 static int
5597 instr_translate(struct rte_swx_pipeline *p,
5598 		struct action *action,
5599 		char *string,
5600 		struct instruction *instr,
5601 		struct instruction_data *data)
5602 {
5603 	char *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX];
5604 	int n_tokens = 0, tpos = 0;
5605 
5606 	/* Parse the instruction string into tokens. */
5607 	for ( ; ; ) {
5608 		char *token;
5609 
5610 		token = strtok_r(string, " \t\v", &string);
5611 		if (!token)
5612 			break;
5613 
5614 		CHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL);
5615 		CHECK_NAME(token, EINVAL);
5616 
5617 		tokens[n_tokens] = token;
5618 		n_tokens++;
5619 	}
5620 
5621 	CHECK(n_tokens, EINVAL);
5622 
5623 	/* Handle the optional instruction label. */
5624 	if ((n_tokens >= 2) && !strcmp(tokens[1], ":")) {
5625 		strcpy(data->label, tokens[0]);
5626 
5627 		tpos += 2;
5628 		CHECK(n_tokens - tpos, EINVAL);
5629 	}
5630 
5631 	/* Identify the instruction type. */
5632 	if (!strcmp(tokens[tpos], "rx"))
5633 		return instr_rx_translate(p,
5634 					  action,
5635 					  &tokens[tpos],
5636 					  n_tokens - tpos,
5637 					  instr,
5638 					  data);
5639 
5640 	if (!strcmp(tokens[tpos], "tx"))
5641 		return instr_tx_translate(p,
5642 					  action,
5643 					  &tokens[tpos],
5644 					  n_tokens - tpos,
5645 					  instr,
5646 					  data);
5647 
5648 	if (!strcmp(tokens[tpos], "drop"))
5649 		return instr_drop_translate(p,
5650 					    action,
5651 					    &tokens[tpos],
5652 					    n_tokens - tpos,
5653 					    instr,
5654 					    data);
5655 
5656 	if (!strcmp(tokens[tpos], "extract"))
5657 		return instr_hdr_extract_translate(p,
5658 						   action,
5659 						   &tokens[tpos],
5660 						   n_tokens - tpos,
5661 						   instr,
5662 						   data);
5663 
5664 	if (!strcmp(tokens[tpos], "lookahead"))
5665 		return instr_hdr_lookahead_translate(p,
5666 						     action,
5667 						     &tokens[tpos],
5668 						     n_tokens - tpos,
5669 						     instr,
5670 						     data);
5671 
5672 	if (!strcmp(tokens[tpos], "emit"))
5673 		return instr_hdr_emit_translate(p,
5674 						action,
5675 						&tokens[tpos],
5676 						n_tokens - tpos,
5677 						instr,
5678 						data);
5679 
5680 	if (!strcmp(tokens[tpos], "validate"))
5681 		return instr_hdr_validate_translate(p,
5682 						    action,
5683 						    &tokens[tpos],
5684 						    n_tokens - tpos,
5685 						    instr,
5686 						    data);
5687 
5688 	if (!strcmp(tokens[tpos], "invalidate"))
5689 		return instr_hdr_invalidate_translate(p,
5690 						      action,
5691 						      &tokens[tpos],
5692 						      n_tokens - tpos,
5693 						      instr,
5694 						      data);
5695 
5696 	if (!strcmp(tokens[tpos], "mov"))
5697 		return instr_mov_translate(p,
5698 					   action,
5699 					   &tokens[tpos],
5700 					   n_tokens - tpos,
5701 					   instr,
5702 					   data);
5703 
5704 	if (!strcmp(tokens[tpos], "add"))
5705 		return instr_alu_add_translate(p,
5706 					       action,
5707 					       &tokens[tpos],
5708 					       n_tokens - tpos,
5709 					       instr,
5710 					       data);
5711 
5712 	if (!strcmp(tokens[tpos], "sub"))
5713 		return instr_alu_sub_translate(p,
5714 					       action,
5715 					       &tokens[tpos],
5716 					       n_tokens - tpos,
5717 					       instr,
5718 					       data);
5719 
5720 	if (!strcmp(tokens[tpos], "ckadd"))
5721 		return instr_alu_ckadd_translate(p,
5722 						 action,
5723 						 &tokens[tpos],
5724 						 n_tokens - tpos,
5725 						 instr,
5726 						 data);
5727 
5728 	if (!strcmp(tokens[tpos], "cksub"))
5729 		return instr_alu_cksub_translate(p,
5730 						 action,
5731 						 &tokens[tpos],
5732 						 n_tokens - tpos,
5733 						 instr,
5734 						 data);
5735 
5736 	if (!strcmp(tokens[tpos], "and"))
5737 		return instr_alu_and_translate(p,
5738 					       action,
5739 					       &tokens[tpos],
5740 					       n_tokens - tpos,
5741 					       instr,
5742 					       data);
5743 
5744 	if (!strcmp(tokens[tpos], "or"))
5745 		return instr_alu_or_translate(p,
5746 					      action,
5747 					      &tokens[tpos],
5748 					      n_tokens - tpos,
5749 					      instr,
5750 					      data);
5751 
5752 	if (!strcmp(tokens[tpos], "xor"))
5753 		return instr_alu_xor_translate(p,
5754 					       action,
5755 					       &tokens[tpos],
5756 					       n_tokens - tpos,
5757 					       instr,
5758 					       data);
5759 
5760 	if (!strcmp(tokens[tpos], "shl"))
5761 		return instr_alu_shl_translate(p,
5762 					       action,
5763 					       &tokens[tpos],
5764 					       n_tokens - tpos,
5765 					       instr,
5766 					       data);
5767 
5768 	if (!strcmp(tokens[tpos], "shr"))
5769 		return instr_alu_shr_translate(p,
5770 					       action,
5771 					       &tokens[tpos],
5772 					       n_tokens - tpos,
5773 					       instr,
5774 					       data);
5775 
5776 	if (!strcmp(tokens[tpos], "regprefetch"))
5777 		return instr_regprefetch_translate(p,
5778 						   action,
5779 						   &tokens[tpos],
5780 						   n_tokens - tpos,
5781 						   instr,
5782 						   data);
5783 
5784 	if (!strcmp(tokens[tpos], "regrd"))
5785 		return instr_regrd_translate(p,
5786 					     action,
5787 					     &tokens[tpos],
5788 					     n_tokens - tpos,
5789 					     instr,
5790 					     data);
5791 
5792 	if (!strcmp(tokens[tpos], "regwr"))
5793 		return instr_regwr_translate(p,
5794 					     action,
5795 					     &tokens[tpos],
5796 					     n_tokens - tpos,
5797 					     instr,
5798 					     data);
5799 
5800 	if (!strcmp(tokens[tpos], "regadd"))
5801 		return instr_regadd_translate(p,
5802 					      action,
5803 					      &tokens[tpos],
5804 					      n_tokens - tpos,
5805 					      instr,
5806 					      data);
5807 
5808 	if (!strcmp(tokens[tpos], "metprefetch"))
5809 		return instr_metprefetch_translate(p,
5810 						   action,
5811 						   &tokens[tpos],
5812 						   n_tokens - tpos,
5813 						   instr,
5814 						   data);
5815 
5816 	if (!strcmp(tokens[tpos], "meter"))
5817 		return instr_meter_translate(p,
5818 					     action,
5819 					     &tokens[tpos],
5820 					     n_tokens - tpos,
5821 					     instr,
5822 					     data);
5823 
5824 	if (!strcmp(tokens[tpos], "table"))
5825 		return instr_table_translate(p,
5826 					     action,
5827 					     &tokens[tpos],
5828 					     n_tokens - tpos,
5829 					     instr,
5830 					     data);
5831 
5832 	if (!strcmp(tokens[tpos], "learn"))
5833 		return instr_learn_translate(p,
5834 					     action,
5835 					     &tokens[tpos],
5836 					     n_tokens - tpos,
5837 					     instr,
5838 					     data);
5839 
5840 	if (!strcmp(tokens[tpos], "forget"))
5841 		return instr_forget_translate(p,
5842 					      action,
5843 					      &tokens[tpos],
5844 					      n_tokens - tpos,
5845 					      instr,
5846 					      data);
5847 
5848 	if (!strcmp(tokens[tpos], "extern"))
5849 		return instr_extern_translate(p,
5850 					      action,
5851 					      &tokens[tpos],
5852 					      n_tokens - tpos,
5853 					      instr,
5854 					      data);
5855 
5856 	if (!strcmp(tokens[tpos], "jmp"))
5857 		return instr_jmp_translate(p,
5858 					   action,
5859 					   &tokens[tpos],
5860 					   n_tokens - tpos,
5861 					   instr,
5862 					   data);
5863 
5864 	if (!strcmp(tokens[tpos], "jmpv"))
5865 		return instr_jmp_valid_translate(p,
5866 						 action,
5867 						 &tokens[tpos],
5868 						 n_tokens - tpos,
5869 						 instr,
5870 						 data);
5871 
5872 	if (!strcmp(tokens[tpos], "jmpnv"))
5873 		return instr_jmp_invalid_translate(p,
5874 						   action,
5875 						   &tokens[tpos],
5876 						   n_tokens - tpos,
5877 						   instr,
5878 						   data);
5879 
5880 	if (!strcmp(tokens[tpos], "jmph"))
5881 		return instr_jmp_hit_translate(p,
5882 					       action,
5883 					       &tokens[tpos],
5884 					       n_tokens - tpos,
5885 					       instr,
5886 					       data);
5887 
5888 	if (!strcmp(tokens[tpos], "jmpnh"))
5889 		return instr_jmp_miss_translate(p,
5890 						action,
5891 						&tokens[tpos],
5892 						n_tokens - tpos,
5893 						instr,
5894 						data);
5895 
5896 	if (!strcmp(tokens[tpos], "jmpa"))
5897 		return instr_jmp_action_hit_translate(p,
5898 						      action,
5899 						      &tokens[tpos],
5900 						      n_tokens - tpos,
5901 						      instr,
5902 						      data);
5903 
5904 	if (!strcmp(tokens[tpos], "jmpna"))
5905 		return instr_jmp_action_miss_translate(p,
5906 						       action,
5907 						       &tokens[tpos],
5908 						       n_tokens - tpos,
5909 						       instr,
5910 						       data);
5911 
5912 	if (!strcmp(tokens[tpos], "jmpeq"))
5913 		return instr_jmp_eq_translate(p,
5914 					      action,
5915 					      &tokens[tpos],
5916 					      n_tokens - tpos,
5917 					      instr,
5918 					      data);
5919 
5920 	if (!strcmp(tokens[tpos], "jmpneq"))
5921 		return instr_jmp_neq_translate(p,
5922 					       action,
5923 					       &tokens[tpos],
5924 					       n_tokens - tpos,
5925 					       instr,
5926 					       data);
5927 
5928 	if (!strcmp(tokens[tpos], "jmplt"))
5929 		return instr_jmp_lt_translate(p,
5930 					      action,
5931 					      &tokens[tpos],
5932 					      n_tokens - tpos,
5933 					      instr,
5934 					      data);
5935 
5936 	if (!strcmp(tokens[tpos], "jmpgt"))
5937 		return instr_jmp_gt_translate(p,
5938 					      action,
5939 					      &tokens[tpos],
5940 					      n_tokens - tpos,
5941 					      instr,
5942 					      data);
5943 
5944 	if (!strcmp(tokens[tpos], "return"))
5945 		return instr_return_translate(p,
5946 					      action,
5947 					      &tokens[tpos],
5948 					      n_tokens - tpos,
5949 					      instr,
5950 					      data);
5951 
5952 	return -EINVAL;
5953 }
5954 
5955 static struct instruction_data *
5956 label_find(struct instruction_data *data, uint32_t n, const char *label)
5957 {
5958 	uint32_t i;
5959 
5960 	for (i = 0; i < n; i++)
5961 		if (!strcmp(label, data[i].label))
5962 			return &data[i];
5963 
5964 	return NULL;
5965 }
5966 
5967 static uint32_t
5968 label_is_used(struct instruction_data *data, uint32_t n, const char *label)
5969 {
5970 	uint32_t count = 0, i;
5971 
5972 	if (!label[0])
5973 		return 0;
5974 
5975 	for (i = 0; i < n; i++)
5976 		if (!strcmp(label, data[i].jmp_label))
5977 			count++;
5978 
5979 	return count;
5980 }
5981 
5982 static int
5983 instr_label_check(struct instruction_data *instruction_data,
5984 		  uint32_t n_instructions)
5985 {
5986 	uint32_t i;
5987 
5988 	/* Check that all instruction labels are unique. */
5989 	for (i = 0; i < n_instructions; i++) {
5990 		struct instruction_data *data = &instruction_data[i];
5991 		char *label = data->label;
5992 		uint32_t j;
5993 
5994 		if (!label[0])
5995 			continue;
5996 
5997 		for (j = i + 1; j < n_instructions; j++)
5998 			CHECK(strcmp(label, instruction_data[j].label), EINVAL);
5999 	}
6000 
6001 	/* Check that no jump instruction (either conditional or not) can jump to itself (loop). */
6002 	for (i = 0; i < n_instructions; i++) {
6003 		struct instruction_data *data = &instruction_data[i];
6004 		char *label = data->label;
6005 		char *jmp_label = data->jmp_label;
6006 
6007 		/* Continue if this instruction does not have a label or it is not a jump. */
6008 		if (!label[0] || !jmp_label[0])
6009 			continue;
6010 
6011 		CHECK(strcmp(label, jmp_label), EINVAL);
6012 	}
6013 
6014 	/* Get users for each instruction label. */
6015 	for (i = 0; i < n_instructions; i++) {
6016 		struct instruction_data *data = &instruction_data[i];
6017 		char *label = data->label;
6018 
6019 		data->n_users = label_is_used(instruction_data,
6020 					      n_instructions,
6021 					      label);
6022 	}
6023 
6024 	return 0;
6025 }
6026 
6027 static int
6028 instr_jmp_resolve(struct instruction *instructions,
6029 		  struct instruction_data *instruction_data,
6030 		  uint32_t n_instructions)
6031 {
6032 	uint32_t i;
6033 
6034 	for (i = 0; i < n_instructions; i++) {
6035 		struct instruction *instr = &instructions[i];
6036 		struct instruction_data *data = &instruction_data[i];
6037 		struct instruction_data *found;
6038 
6039 		if (!instruction_is_jmp(instr))
6040 			continue;
6041 
6042 		found = label_find(instruction_data,
6043 				   n_instructions,
6044 				   data->jmp_label);
6045 		CHECK(found, EINVAL);
6046 
6047 		instr->jmp.ip = &instructions[found - instruction_data];
6048 	}
6049 
6050 	return 0;
6051 }
6052 
6053 static int
6054 instr_verify(struct rte_swx_pipeline *p __rte_unused,
6055 	     struct action *a,
6056 	     struct instruction *instr,
6057 	     struct instruction_data *data __rte_unused,
6058 	     uint32_t n_instructions)
6059 {
6060 	if (!a) {
6061 		enum instruction_type type;
6062 		uint32_t i;
6063 
6064 		/* Check that the first instruction is rx. */
6065 		CHECK(instr[0].type == INSTR_RX, EINVAL);
6066 
6067 		/* Check that there is at least one tx instruction. */
6068 		for (i = 0; i < n_instructions; i++) {
6069 			type = instr[i].type;
6070 
6071 			if (instruction_is_tx(type))
6072 				break;
6073 		}
6074 		CHECK(i < n_instructions, EINVAL);
6075 
6076 		/* Check that the last instruction is either tx or unconditional
6077 		 * jump.
6078 		 */
6079 		type = instr[n_instructions - 1].type;
6080 		CHECK(instruction_is_tx(type) || (type == INSTR_JMP), EINVAL);
6081 	}
6082 
6083 	if (a) {
6084 		enum instruction_type type;
6085 		uint32_t i;
6086 
6087 		/* Check that there is at least one return or tx instruction. */
6088 		for (i = 0; i < n_instructions; i++) {
6089 			type = instr[i].type;
6090 
6091 			if ((type == INSTR_RETURN) || instruction_is_tx(type))
6092 				break;
6093 		}
6094 		CHECK(i < n_instructions, EINVAL);
6095 	}
6096 
6097 	return 0;
6098 }
6099 
6100 static uint32_t
6101 instr_compact(struct instruction *instructions,
6102 	      struct instruction_data *instruction_data,
6103 	      uint32_t n_instructions)
6104 {
6105 	uint32_t i, pos = 0;
6106 
6107 	/* Eliminate the invalid instructions that have been optimized out. */
6108 	for (i = 0; i < n_instructions; i++) {
6109 		struct instruction *instr = &instructions[i];
6110 		struct instruction_data *data = &instruction_data[i];
6111 
6112 		if (data->invalid)
6113 			continue;
6114 
6115 		if (i != pos) {
6116 			memcpy(&instructions[pos], instr, sizeof(*instr));
6117 			memcpy(&instruction_data[pos], data, sizeof(*data));
6118 		}
6119 
6120 		pos++;
6121 	}
6122 
6123 	return pos;
6124 }
6125 
6126 static int
6127 instr_pattern_extract_many_search(struct instruction *instr,
6128 				  struct instruction_data *data,
6129 				  uint32_t n_instr,
6130 				  uint32_t *n_pattern_instr)
6131 {
6132 	uint32_t i;
6133 
6134 	for (i = 0; i < n_instr; i++) {
6135 		if (data[i].invalid)
6136 			break;
6137 
6138 		if (instr[i].type != INSTR_HDR_EXTRACT)
6139 			break;
6140 
6141 		if (i == RTE_DIM(instr->io.hdr.header_id))
6142 			break;
6143 
6144 		if (i && data[i].n_users)
6145 			break;
6146 	}
6147 
6148 	if (i < 2)
6149 		return 0;
6150 
6151 	*n_pattern_instr = i;
6152 	return 1;
6153 }
6154 
6155 static void
6156 instr_pattern_extract_many_replace(struct instruction *instr,
6157 				   struct instruction_data *data,
6158 				   uint32_t n_instr)
6159 {
6160 	uint32_t i;
6161 
6162 	for (i = 1; i < n_instr; i++) {
6163 		instr[0].type++;
6164 		instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0];
6165 		instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0];
6166 		instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0];
6167 
6168 		data[i].invalid = 1;
6169 	}
6170 }
6171 
6172 static uint32_t
6173 instr_pattern_extract_many_optimize(struct instruction *instructions,
6174 				    struct instruction_data *instruction_data,
6175 				    uint32_t n_instructions)
6176 {
6177 	uint32_t i;
6178 
6179 	for (i = 0; i < n_instructions; ) {
6180 		struct instruction *instr = &instructions[i];
6181 		struct instruction_data *data = &instruction_data[i];
6182 		uint32_t n_instr = 0;
6183 		int detected;
6184 
6185 		/* Extract many. */
6186 		detected = instr_pattern_extract_many_search(instr,
6187 							     data,
6188 							     n_instructions - i,
6189 							     &n_instr);
6190 		if (detected) {
6191 			instr_pattern_extract_many_replace(instr,
6192 							   data,
6193 							   n_instr);
6194 			i += n_instr;
6195 			continue;
6196 		}
6197 
6198 		/* No pattern starting at the current instruction. */
6199 		i++;
6200 	}
6201 
6202 	/* Eliminate the invalid instructions that have been optimized out. */
6203 	n_instructions = instr_compact(instructions,
6204 				       instruction_data,
6205 				       n_instructions);
6206 
6207 	return n_instructions;
6208 }
6209 
6210 static int
6211 instr_pattern_emit_many_tx_search(struct instruction *instr,
6212 				  struct instruction_data *data,
6213 				  uint32_t n_instr,
6214 				  uint32_t *n_pattern_instr)
6215 {
6216 	uint32_t i;
6217 
6218 	for (i = 0; i < n_instr; i++) {
6219 		if (data[i].invalid)
6220 			break;
6221 
6222 		if (instr[i].type != INSTR_HDR_EMIT)
6223 			break;
6224 
6225 		if (i == RTE_DIM(instr->io.hdr.header_id))
6226 			break;
6227 
6228 		if (i && data[i].n_users)
6229 			break;
6230 	}
6231 
6232 	if (!i)
6233 		return 0;
6234 
6235 	if (instr[i].type != INSTR_TX)
6236 		return 0;
6237 
6238 	if (data[i].n_users)
6239 		return 0;
6240 
6241 	i++;
6242 
6243 	*n_pattern_instr = i;
6244 	return 1;
6245 }
6246 
6247 static void
6248 instr_pattern_emit_many_tx_replace(struct instruction *instr,
6249 				   struct instruction_data *data,
6250 				   uint32_t n_instr)
6251 {
6252 	uint32_t i;
6253 
6254 	/* Any emit instruction in addition to the first one. */
6255 	for (i = 1; i < n_instr - 1; i++) {
6256 		instr[0].type++;
6257 		instr[0].io.hdr.header_id[i] = instr[i].io.hdr.header_id[0];
6258 		instr[0].io.hdr.struct_id[i] = instr[i].io.hdr.struct_id[0];
6259 		instr[0].io.hdr.n_bytes[i] = instr[i].io.hdr.n_bytes[0];
6260 
6261 		data[i].invalid = 1;
6262 	}
6263 
6264 	/* The TX instruction is the last one in the pattern. */
6265 	instr[0].type++;
6266 	instr[0].io.io.offset = instr[i].io.io.offset;
6267 	instr[0].io.io.n_bits = instr[i].io.io.n_bits;
6268 	data[i].invalid = 1;
6269 }
6270 
6271 static uint32_t
6272 instr_pattern_emit_many_tx_optimize(struct instruction *instructions,
6273 				    struct instruction_data *instruction_data,
6274 				    uint32_t n_instructions)
6275 {
6276 	uint32_t i;
6277 
6278 	for (i = 0; i < n_instructions; ) {
6279 		struct instruction *instr = &instructions[i];
6280 		struct instruction_data *data = &instruction_data[i];
6281 		uint32_t n_instr = 0;
6282 		int detected;
6283 
6284 		/* Emit many + TX. */
6285 		detected = instr_pattern_emit_many_tx_search(instr,
6286 							     data,
6287 							     n_instructions - i,
6288 							     &n_instr);
6289 		if (detected) {
6290 			instr_pattern_emit_many_tx_replace(instr,
6291 							   data,
6292 							   n_instr);
6293 			i += n_instr;
6294 			continue;
6295 		}
6296 
6297 		/* No pattern starting at the current instruction. */
6298 		i++;
6299 	}
6300 
6301 	/* Eliminate the invalid instructions that have been optimized out. */
6302 	n_instructions = instr_compact(instructions,
6303 				       instruction_data,
6304 				       n_instructions);
6305 
6306 	return n_instructions;
6307 }
6308 
6309 static uint32_t
6310 action_arg_src_mov_count(struct action *a,
6311 			 uint32_t arg_id,
6312 			 struct instruction *instructions,
6313 			 struct instruction_data *instruction_data,
6314 			 uint32_t n_instructions);
6315 
6316 static int
6317 instr_pattern_mov_all_validate_search(struct rte_swx_pipeline *p,
6318 				      struct action *a,
6319 				      struct instruction *instr,
6320 				      struct instruction_data *data,
6321 				      uint32_t n_instr,
6322 				      struct instruction *instructions,
6323 				      struct instruction_data *instruction_data,
6324 				      uint32_t n_instructions,
6325 				      uint32_t *n_pattern_instr)
6326 {
6327 	struct header *h;
6328 	uint32_t src_field_id, i, j;
6329 
6330 	/* Prerequisites. */
6331 	if (!a || !a->st)
6332 		return 0;
6333 
6334 	/* First instruction: MOV_HM. */
6335 	if (data[0].invalid || (instr[0].type != INSTR_MOV_HM))
6336 		return 0;
6337 
6338 	h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id);
6339 	if (!h || h->st->var_size)
6340 		return 0;
6341 
6342 	for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++)
6343 		if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8)
6344 			break;
6345 
6346 	if (src_field_id == a->st->n_fields)
6347 		return 0;
6348 
6349 	if (instr[0].mov.dst.offset ||
6350 	    (instr[0].mov.dst.n_bits != h->st->fields[0].n_bits) ||
6351 	    instr[0].mov.src.struct_id ||
6352 	    (instr[0].mov.src.n_bits != a->st->fields[src_field_id].n_bits) ||
6353 	    (instr[0].mov.dst.n_bits != instr[0].mov.src.n_bits))
6354 		return 0;
6355 
6356 	if ((n_instr < h->st->n_fields + 1) ||
6357 	     (a->st->n_fields < src_field_id + h->st->n_fields + 1))
6358 		return 0;
6359 
6360 	/* Subsequent instructions: MOV_HM. */
6361 	for (i = 1; i < h->st->n_fields; i++)
6362 		if (data[i].invalid ||
6363 		    data[i].n_users ||
6364 		    (instr[i].type != INSTR_MOV_HM) ||
6365 		    (instr[i].mov.dst.struct_id != h->struct_id) ||
6366 		    (instr[i].mov.dst.offset != h->st->fields[i].offset / 8) ||
6367 		    (instr[i].mov.dst.n_bits != h->st->fields[i].n_bits) ||
6368 		    instr[i].mov.src.struct_id ||
6369 		    (instr[i].mov.src.offset != a->st->fields[src_field_id + i].offset / 8) ||
6370 		    (instr[i].mov.src.n_bits != a->st->fields[src_field_id + i].n_bits) ||
6371 		    (instr[i].mov.dst.n_bits != instr[i].mov.src.n_bits))
6372 			return 0;
6373 
6374 	/* Last instruction: HDR_VALIDATE. */
6375 	if ((instr[i].type != INSTR_HDR_VALIDATE) ||
6376 	    (instr[i].valid.header_id != h->id))
6377 		return 0;
6378 
6379 	/* Check that none of the action args that are used as source for this
6380 	 * DMA transfer are not used as source in any other mov instruction.
6381 	 */
6382 	for (j = src_field_id; j < src_field_id + h->st->n_fields; j++) {
6383 		uint32_t n_users;
6384 
6385 		n_users = action_arg_src_mov_count(a,
6386 						   j,
6387 						   instructions,
6388 						   instruction_data,
6389 						   n_instructions);
6390 		if (n_users > 1)
6391 			return 0;
6392 	}
6393 
6394 	*n_pattern_instr = 1 + i;
6395 	return 1;
6396 }
6397 
6398 static void
6399 instr_pattern_mov_all_validate_replace(struct rte_swx_pipeline *p,
6400 				       struct action *a,
6401 				       struct instruction *instr,
6402 				       struct instruction_data *data,
6403 				       uint32_t n_instr)
6404 {
6405 	struct header *h;
6406 	uint32_t src_field_id, src_offset, i;
6407 
6408 	/* Read from the instructions before they are modified. */
6409 	h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id);
6410 	if (!h)
6411 		return;
6412 
6413 	for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++)
6414 		if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8)
6415 			break;
6416 
6417 	if (src_field_id == a->st->n_fields)
6418 		return;
6419 
6420 	src_offset = instr[0].mov.src.offset;
6421 
6422 	/* Modify the instructions. */
6423 	instr[0].type = INSTR_DMA_HT;
6424 	instr[0].dma.dst.header_id[0] = h->id;
6425 	instr[0].dma.dst.struct_id[0] = h->struct_id;
6426 	instr[0].dma.src.offset[0] = (uint8_t)src_offset;
6427 	instr[0].dma.n_bytes[0] = h->st->n_bits / 8;
6428 
6429 	for (i = 1; i < n_instr; i++)
6430 		data[i].invalid = 1;
6431 
6432 	/* Update the endianness of the action arguments to header endianness. */
6433 	for (i = 0; i < h->st->n_fields; i++)
6434 		a->args_endianness[src_field_id + i] = 1;
6435 }
6436 
6437 static uint32_t
6438 instr_pattern_mov_all_validate_optimize(struct rte_swx_pipeline *p,
6439 					struct action *a,
6440 					struct instruction *instructions,
6441 					struct instruction_data *instruction_data,
6442 					uint32_t n_instructions)
6443 {
6444 	uint32_t i;
6445 
6446 	if (!a || !a->st)
6447 		return n_instructions;
6448 
6449 	for (i = 0; i < n_instructions; ) {
6450 		struct instruction *instr = &instructions[i];
6451 		struct instruction_data *data = &instruction_data[i];
6452 		uint32_t n_instr = 0;
6453 		int detected;
6454 
6455 		/* Mov all + validate. */
6456 		detected = instr_pattern_mov_all_validate_search(p,
6457 								 a,
6458 								 instr,
6459 								 data,
6460 								 n_instructions - i,
6461 								 instructions,
6462 								 instruction_data,
6463 								 n_instructions,
6464 								 &n_instr);
6465 		if (detected) {
6466 			instr_pattern_mov_all_validate_replace(p, a, instr, data, n_instr);
6467 			i += n_instr;
6468 			continue;
6469 		}
6470 
6471 		/* No pattern starting at the current instruction. */
6472 		i++;
6473 	}
6474 
6475 	/* Eliminate the invalid instructions that have been optimized out. */
6476 	n_instructions = instr_compact(instructions,
6477 				       instruction_data,
6478 				       n_instructions);
6479 
6480 	return n_instructions;
6481 }
6482 
6483 static int
6484 instr_pattern_dma_many_search(struct instruction *instr,
6485 			      struct instruction_data *data,
6486 			      uint32_t n_instr,
6487 			      uint32_t *n_pattern_instr)
6488 {
6489 	uint32_t i;
6490 
6491 	for (i = 0; i < n_instr; i++) {
6492 		if (data[i].invalid)
6493 			break;
6494 
6495 		if (instr[i].type != INSTR_DMA_HT)
6496 			break;
6497 
6498 		if (i == RTE_DIM(instr->dma.dst.header_id))
6499 			break;
6500 
6501 		if (i && data[i].n_users)
6502 			break;
6503 	}
6504 
6505 	if (i < 2)
6506 		return 0;
6507 
6508 	*n_pattern_instr = i;
6509 	return 1;
6510 }
6511 
6512 static void
6513 instr_pattern_dma_many_replace(struct instruction *instr,
6514 			       struct instruction_data *data,
6515 			       uint32_t n_instr)
6516 {
6517 	uint32_t i;
6518 
6519 	for (i = 1; i < n_instr; i++) {
6520 		instr[0].type++;
6521 		instr[0].dma.dst.header_id[i] = instr[i].dma.dst.header_id[0];
6522 		instr[0].dma.dst.struct_id[i] = instr[i].dma.dst.struct_id[0];
6523 		instr[0].dma.src.offset[i] = instr[i].dma.src.offset[0];
6524 		instr[0].dma.n_bytes[i] = instr[i].dma.n_bytes[0];
6525 
6526 		data[i].invalid = 1;
6527 	}
6528 }
6529 
6530 static uint32_t
6531 instr_pattern_dma_many_optimize(struct instruction *instructions,
6532 	       struct instruction_data *instruction_data,
6533 	       uint32_t n_instructions)
6534 {
6535 	uint32_t i;
6536 
6537 	for (i = 0; i < n_instructions; ) {
6538 		struct instruction *instr = &instructions[i];
6539 		struct instruction_data *data = &instruction_data[i];
6540 		uint32_t n_instr = 0;
6541 		int detected;
6542 
6543 		/* DMA many. */
6544 		detected = instr_pattern_dma_many_search(instr,
6545 							 data,
6546 							 n_instructions - i,
6547 							 &n_instr);
6548 		if (detected) {
6549 			instr_pattern_dma_many_replace(instr, data, n_instr);
6550 			i += n_instr;
6551 			continue;
6552 		}
6553 
6554 		/* No pattern starting at the current instruction. */
6555 		i++;
6556 	}
6557 
6558 	/* Eliminate the invalid instructions that have been optimized out. */
6559 	n_instructions = instr_compact(instructions,
6560 				       instruction_data,
6561 				       n_instructions);
6562 
6563 	return n_instructions;
6564 }
6565 
6566 static uint32_t
6567 instr_optimize(struct rte_swx_pipeline *p,
6568 	       struct action *a,
6569 	       struct instruction *instructions,
6570 	       struct instruction_data *instruction_data,
6571 	       uint32_t n_instructions)
6572 {
6573 	/* Extract many. */
6574 	n_instructions = instr_pattern_extract_many_optimize(instructions,
6575 							     instruction_data,
6576 							     n_instructions);
6577 
6578 	/* Emit many + TX. */
6579 	n_instructions = instr_pattern_emit_many_tx_optimize(instructions,
6580 							     instruction_data,
6581 							     n_instructions);
6582 
6583 	/* Mov all + validate. */
6584 	n_instructions = instr_pattern_mov_all_validate_optimize(p,
6585 								 a,
6586 								 instructions,
6587 								 instruction_data,
6588 								 n_instructions);
6589 
6590 	/* DMA many. */
6591 	n_instructions = instr_pattern_dma_many_optimize(instructions,
6592 							 instruction_data,
6593 							 n_instructions);
6594 
6595 	return n_instructions;
6596 }
6597 
6598 static int
6599 instruction_config(struct rte_swx_pipeline *p,
6600 		   struct action *a,
6601 		   const char **instructions,
6602 		   uint32_t n_instructions)
6603 {
6604 	struct instruction *instr = NULL;
6605 	struct instruction_data *data = NULL;
6606 	int err = 0;
6607 	uint32_t i;
6608 
6609 	CHECK(n_instructions, EINVAL);
6610 	CHECK(instructions, EINVAL);
6611 	for (i = 0; i < n_instructions; i++)
6612 		CHECK_INSTRUCTION(instructions[i], EINVAL);
6613 
6614 	/* Memory allocation. */
6615 	instr = calloc(n_instructions, sizeof(struct instruction));
6616 	if (!instr) {
6617 		err = -ENOMEM;
6618 		goto error;
6619 	}
6620 
6621 	data = calloc(n_instructions, sizeof(struct instruction_data));
6622 	if (!data) {
6623 		err = -ENOMEM;
6624 		goto error;
6625 	}
6626 
6627 	for (i = 0; i < n_instructions; i++) {
6628 		char *string = strdup(instructions[i]);
6629 		if (!string) {
6630 			err = -ENOMEM;
6631 			goto error;
6632 		}
6633 
6634 		err = instr_translate(p, a, string, &instr[i], &data[i]);
6635 		if (err) {
6636 			free(string);
6637 			goto error;
6638 		}
6639 
6640 		free(string);
6641 	}
6642 
6643 	err = instr_label_check(data, n_instructions);
6644 	if (err)
6645 		goto error;
6646 
6647 	err = instr_verify(p, a, instr, data, n_instructions);
6648 	if (err)
6649 		goto error;
6650 
6651 	n_instructions = instr_optimize(p, a, instr, data, n_instructions);
6652 
6653 	err = instr_jmp_resolve(instr, data, n_instructions);
6654 	if (err)
6655 		goto error;
6656 
6657 	if (a) {
6658 		a->instructions = instr;
6659 		a->instruction_data = data;
6660 		a->n_instructions = n_instructions;
6661 	} else {
6662 		p->instructions = instr;
6663 		p->instruction_data = data;
6664 		p->n_instructions = n_instructions;
6665 	}
6666 
6667 	return 0;
6668 
6669 error:
6670 	free(data);
6671 	free(instr);
6672 	return err;
6673 }
6674 
6675 static instr_exec_t instruction_table[] = {
6676 	[INSTR_RX] = instr_rx_exec,
6677 	[INSTR_TX] = instr_tx_exec,
6678 	[INSTR_TX_I] = instr_tx_i_exec,
6679 	[INSTR_DROP] = instr_drop_exec,
6680 
6681 	[INSTR_HDR_EXTRACT] = instr_hdr_extract_exec,
6682 	[INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec,
6683 	[INSTR_HDR_EXTRACT3] = instr_hdr_extract3_exec,
6684 	[INSTR_HDR_EXTRACT4] = instr_hdr_extract4_exec,
6685 	[INSTR_HDR_EXTRACT5] = instr_hdr_extract5_exec,
6686 	[INSTR_HDR_EXTRACT6] = instr_hdr_extract6_exec,
6687 	[INSTR_HDR_EXTRACT7] = instr_hdr_extract7_exec,
6688 	[INSTR_HDR_EXTRACT8] = instr_hdr_extract8_exec,
6689 	[INSTR_HDR_EXTRACT_M] = instr_hdr_extract_m_exec,
6690 	[INSTR_HDR_LOOKAHEAD] = instr_hdr_lookahead_exec,
6691 
6692 	[INSTR_HDR_EMIT] = instr_hdr_emit_exec,
6693 	[INSTR_HDR_EMIT_TX] = instr_hdr_emit_tx_exec,
6694 	[INSTR_HDR_EMIT2_TX] = instr_hdr_emit2_tx_exec,
6695 	[INSTR_HDR_EMIT3_TX] = instr_hdr_emit3_tx_exec,
6696 	[INSTR_HDR_EMIT4_TX] = instr_hdr_emit4_tx_exec,
6697 	[INSTR_HDR_EMIT5_TX] = instr_hdr_emit5_tx_exec,
6698 	[INSTR_HDR_EMIT6_TX] = instr_hdr_emit6_tx_exec,
6699 	[INSTR_HDR_EMIT7_TX] = instr_hdr_emit7_tx_exec,
6700 	[INSTR_HDR_EMIT8_TX] = instr_hdr_emit8_tx_exec,
6701 
6702 	[INSTR_HDR_VALIDATE] = instr_hdr_validate_exec,
6703 	[INSTR_HDR_INVALIDATE] = instr_hdr_invalidate_exec,
6704 
6705 	[INSTR_MOV] = instr_mov_exec,
6706 	[INSTR_MOV_MH] = instr_mov_mh_exec,
6707 	[INSTR_MOV_HM] = instr_mov_hm_exec,
6708 	[INSTR_MOV_HH] = instr_mov_hh_exec,
6709 	[INSTR_MOV_I] = instr_mov_i_exec,
6710 
6711 	[INSTR_DMA_HT] = instr_dma_ht_exec,
6712 	[INSTR_DMA_HT2] = instr_dma_ht2_exec,
6713 	[INSTR_DMA_HT3] = instr_dma_ht3_exec,
6714 	[INSTR_DMA_HT4] = instr_dma_ht4_exec,
6715 	[INSTR_DMA_HT5] = instr_dma_ht5_exec,
6716 	[INSTR_DMA_HT6] = instr_dma_ht6_exec,
6717 	[INSTR_DMA_HT7] = instr_dma_ht7_exec,
6718 	[INSTR_DMA_HT8] = instr_dma_ht8_exec,
6719 
6720 	[INSTR_ALU_ADD] = instr_alu_add_exec,
6721 	[INSTR_ALU_ADD_MH] = instr_alu_add_mh_exec,
6722 	[INSTR_ALU_ADD_HM] = instr_alu_add_hm_exec,
6723 	[INSTR_ALU_ADD_HH] = instr_alu_add_hh_exec,
6724 	[INSTR_ALU_ADD_MI] = instr_alu_add_mi_exec,
6725 	[INSTR_ALU_ADD_HI] = instr_alu_add_hi_exec,
6726 
6727 	[INSTR_ALU_SUB] = instr_alu_sub_exec,
6728 	[INSTR_ALU_SUB_MH] = instr_alu_sub_mh_exec,
6729 	[INSTR_ALU_SUB_HM] = instr_alu_sub_hm_exec,
6730 	[INSTR_ALU_SUB_HH] = instr_alu_sub_hh_exec,
6731 	[INSTR_ALU_SUB_MI] = instr_alu_sub_mi_exec,
6732 	[INSTR_ALU_SUB_HI] = instr_alu_sub_hi_exec,
6733 
6734 	[INSTR_ALU_CKADD_FIELD] = instr_alu_ckadd_field_exec,
6735 	[INSTR_ALU_CKADD_STRUCT] = instr_alu_ckadd_struct_exec,
6736 	[INSTR_ALU_CKADD_STRUCT20] = instr_alu_ckadd_struct20_exec,
6737 	[INSTR_ALU_CKSUB_FIELD] = instr_alu_cksub_field_exec,
6738 
6739 	[INSTR_ALU_AND] = instr_alu_and_exec,
6740 	[INSTR_ALU_AND_MH] = instr_alu_and_mh_exec,
6741 	[INSTR_ALU_AND_HM] = instr_alu_and_hm_exec,
6742 	[INSTR_ALU_AND_HH] = instr_alu_and_hh_exec,
6743 	[INSTR_ALU_AND_I] = instr_alu_and_i_exec,
6744 
6745 	[INSTR_ALU_OR] = instr_alu_or_exec,
6746 	[INSTR_ALU_OR_MH] = instr_alu_or_mh_exec,
6747 	[INSTR_ALU_OR_HM] = instr_alu_or_hm_exec,
6748 	[INSTR_ALU_OR_HH] = instr_alu_or_hh_exec,
6749 	[INSTR_ALU_OR_I] = instr_alu_or_i_exec,
6750 
6751 	[INSTR_ALU_XOR] = instr_alu_xor_exec,
6752 	[INSTR_ALU_XOR_MH] = instr_alu_xor_mh_exec,
6753 	[INSTR_ALU_XOR_HM] = instr_alu_xor_hm_exec,
6754 	[INSTR_ALU_XOR_HH] = instr_alu_xor_hh_exec,
6755 	[INSTR_ALU_XOR_I] = instr_alu_xor_i_exec,
6756 
6757 	[INSTR_ALU_SHL] = instr_alu_shl_exec,
6758 	[INSTR_ALU_SHL_MH] = instr_alu_shl_mh_exec,
6759 	[INSTR_ALU_SHL_HM] = instr_alu_shl_hm_exec,
6760 	[INSTR_ALU_SHL_HH] = instr_alu_shl_hh_exec,
6761 	[INSTR_ALU_SHL_MI] = instr_alu_shl_mi_exec,
6762 	[INSTR_ALU_SHL_HI] = instr_alu_shl_hi_exec,
6763 
6764 	[INSTR_ALU_SHR] = instr_alu_shr_exec,
6765 	[INSTR_ALU_SHR_MH] = instr_alu_shr_mh_exec,
6766 	[INSTR_ALU_SHR_HM] = instr_alu_shr_hm_exec,
6767 	[INSTR_ALU_SHR_HH] = instr_alu_shr_hh_exec,
6768 	[INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec,
6769 	[INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec,
6770 
6771 	[INSTR_REGPREFETCH_RH] = instr_regprefetch_rh_exec,
6772 	[INSTR_REGPREFETCH_RM] = instr_regprefetch_rm_exec,
6773 	[INSTR_REGPREFETCH_RI] = instr_regprefetch_ri_exec,
6774 
6775 	[INSTR_REGRD_HRH] = instr_regrd_hrh_exec,
6776 	[INSTR_REGRD_HRM] = instr_regrd_hrm_exec,
6777 	[INSTR_REGRD_MRH] = instr_regrd_mrh_exec,
6778 	[INSTR_REGRD_MRM] = instr_regrd_mrm_exec,
6779 	[INSTR_REGRD_HRI] = instr_regrd_hri_exec,
6780 	[INSTR_REGRD_MRI] = instr_regrd_mri_exec,
6781 
6782 	[INSTR_REGWR_RHH] = instr_regwr_rhh_exec,
6783 	[INSTR_REGWR_RHM] = instr_regwr_rhm_exec,
6784 	[INSTR_REGWR_RMH] = instr_regwr_rmh_exec,
6785 	[INSTR_REGWR_RMM] = instr_regwr_rmm_exec,
6786 	[INSTR_REGWR_RHI] = instr_regwr_rhi_exec,
6787 	[INSTR_REGWR_RMI] = instr_regwr_rmi_exec,
6788 	[INSTR_REGWR_RIH] = instr_regwr_rih_exec,
6789 	[INSTR_REGWR_RIM] = instr_regwr_rim_exec,
6790 	[INSTR_REGWR_RII] = instr_regwr_rii_exec,
6791 
6792 	[INSTR_REGADD_RHH] = instr_regadd_rhh_exec,
6793 	[INSTR_REGADD_RHM] = instr_regadd_rhm_exec,
6794 	[INSTR_REGADD_RMH] = instr_regadd_rmh_exec,
6795 	[INSTR_REGADD_RMM] = instr_regadd_rmm_exec,
6796 	[INSTR_REGADD_RHI] = instr_regadd_rhi_exec,
6797 	[INSTR_REGADD_RMI] = instr_regadd_rmi_exec,
6798 	[INSTR_REGADD_RIH] = instr_regadd_rih_exec,
6799 	[INSTR_REGADD_RIM] = instr_regadd_rim_exec,
6800 	[INSTR_REGADD_RII] = instr_regadd_rii_exec,
6801 
6802 	[INSTR_METPREFETCH_H] = instr_metprefetch_h_exec,
6803 	[INSTR_METPREFETCH_M] = instr_metprefetch_m_exec,
6804 	[INSTR_METPREFETCH_I] = instr_metprefetch_i_exec,
6805 
6806 	[INSTR_METER_HHM] = instr_meter_hhm_exec,
6807 	[INSTR_METER_HHI] = instr_meter_hhi_exec,
6808 	[INSTR_METER_HMM] = instr_meter_hmm_exec,
6809 	[INSTR_METER_HMI] = instr_meter_hmi_exec,
6810 	[INSTR_METER_MHM] = instr_meter_mhm_exec,
6811 	[INSTR_METER_MHI] = instr_meter_mhi_exec,
6812 	[INSTR_METER_MMM] = instr_meter_mmm_exec,
6813 	[INSTR_METER_MMI] = instr_meter_mmi_exec,
6814 	[INSTR_METER_IHM] = instr_meter_ihm_exec,
6815 	[INSTR_METER_IHI] = instr_meter_ihi_exec,
6816 	[INSTR_METER_IMM] = instr_meter_imm_exec,
6817 	[INSTR_METER_IMI] = instr_meter_imi_exec,
6818 
6819 	[INSTR_TABLE] = instr_table_exec,
6820 	[INSTR_TABLE_AF] = instr_table_af_exec,
6821 	[INSTR_SELECTOR] = instr_selector_exec,
6822 	[INSTR_LEARNER] = instr_learner_exec,
6823 	[INSTR_LEARNER_AF] = instr_learner_af_exec,
6824 	[INSTR_LEARNER_LEARN] = instr_learn_exec,
6825 	[INSTR_LEARNER_FORGET] = instr_forget_exec,
6826 	[INSTR_EXTERN_OBJ] = instr_extern_obj_exec,
6827 	[INSTR_EXTERN_FUNC] = instr_extern_func_exec,
6828 
6829 	[INSTR_JMP] = instr_jmp_exec,
6830 	[INSTR_JMP_VALID] = instr_jmp_valid_exec,
6831 	[INSTR_JMP_INVALID] = instr_jmp_invalid_exec,
6832 	[INSTR_JMP_HIT] = instr_jmp_hit_exec,
6833 	[INSTR_JMP_MISS] = instr_jmp_miss_exec,
6834 	[INSTR_JMP_ACTION_HIT] = instr_jmp_action_hit_exec,
6835 	[INSTR_JMP_ACTION_MISS] = instr_jmp_action_miss_exec,
6836 
6837 	[INSTR_JMP_EQ] = instr_jmp_eq_exec,
6838 	[INSTR_JMP_EQ_MH] = instr_jmp_eq_mh_exec,
6839 	[INSTR_JMP_EQ_HM] = instr_jmp_eq_hm_exec,
6840 	[INSTR_JMP_EQ_HH] = instr_jmp_eq_hh_exec,
6841 	[INSTR_JMP_EQ_I] = instr_jmp_eq_i_exec,
6842 
6843 	[INSTR_JMP_NEQ] = instr_jmp_neq_exec,
6844 	[INSTR_JMP_NEQ_MH] = instr_jmp_neq_mh_exec,
6845 	[INSTR_JMP_NEQ_HM] = instr_jmp_neq_hm_exec,
6846 	[INSTR_JMP_NEQ_HH] = instr_jmp_neq_hh_exec,
6847 	[INSTR_JMP_NEQ_I] = instr_jmp_neq_i_exec,
6848 
6849 	[INSTR_JMP_LT] = instr_jmp_lt_exec,
6850 	[INSTR_JMP_LT_MH] = instr_jmp_lt_mh_exec,
6851 	[INSTR_JMP_LT_HM] = instr_jmp_lt_hm_exec,
6852 	[INSTR_JMP_LT_HH] = instr_jmp_lt_hh_exec,
6853 	[INSTR_JMP_LT_MI] = instr_jmp_lt_mi_exec,
6854 	[INSTR_JMP_LT_HI] = instr_jmp_lt_hi_exec,
6855 
6856 	[INSTR_JMP_GT] = instr_jmp_gt_exec,
6857 	[INSTR_JMP_GT_MH] = instr_jmp_gt_mh_exec,
6858 	[INSTR_JMP_GT_HM] = instr_jmp_gt_hm_exec,
6859 	[INSTR_JMP_GT_HH] = instr_jmp_gt_hh_exec,
6860 	[INSTR_JMP_GT_MI] = instr_jmp_gt_mi_exec,
6861 	[INSTR_JMP_GT_HI] = instr_jmp_gt_hi_exec,
6862 
6863 	[INSTR_RETURN] = instr_return_exec,
6864 };
6865 
6866 static int
6867 instruction_table_build(struct rte_swx_pipeline *p)
6868 {
6869 	p->instruction_table = calloc(RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX,
6870 				      sizeof(struct instr_exec_t *));
6871 	if (!p->instruction_table)
6872 		return -EINVAL;
6873 
6874 	memcpy(p->instruction_table, instruction_table, sizeof(instruction_table));
6875 
6876 	return 0;
6877 }
6878 
6879 static void
6880 instruction_table_build_free(struct rte_swx_pipeline *p)
6881 {
6882 	if (!p->instruction_table)
6883 		return;
6884 
6885 	free(p->instruction_table);
6886 	p->instruction_table = NULL;
6887 }
6888 
6889 static void
6890 instruction_table_free(struct rte_swx_pipeline *p)
6891 {
6892 	instruction_table_build_free(p);
6893 }
6894 
6895 static inline void
6896 instr_exec(struct rte_swx_pipeline *p)
6897 {
6898 	struct thread *t = &p->threads[p->thread_id];
6899 	struct instruction *ip = t->ip;
6900 	instr_exec_t instr = p->instruction_table[ip->type];
6901 
6902 	instr(p);
6903 }
6904 
6905 /*
6906  * Action.
6907  */
6908 static struct action *
6909 action_find(struct rte_swx_pipeline *p, const char *name)
6910 {
6911 	struct action *elem;
6912 
6913 	if (!name)
6914 		return NULL;
6915 
6916 	TAILQ_FOREACH(elem, &p->actions, node)
6917 		if (strcmp(elem->name, name) == 0)
6918 			return elem;
6919 
6920 	return NULL;
6921 }
6922 
6923 static struct action *
6924 action_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
6925 {
6926 	struct action *action = NULL;
6927 
6928 	TAILQ_FOREACH(action, &p->actions, node)
6929 		if (action->id == id)
6930 			return action;
6931 
6932 	return NULL;
6933 }
6934 
6935 static struct field *
6936 action_field_find(struct action *a, const char *name)
6937 {
6938 	return a->st ? struct_type_field_find(a->st, name) : NULL;
6939 }
6940 
6941 static struct field *
6942 action_field_parse(struct action *action, const char *name)
6943 {
6944 	if (name[0] != 't' || name[1] != '.')
6945 		return NULL;
6946 
6947 	return action_field_find(action, &name[2]);
6948 }
6949 
6950 static int
6951 action_has_nbo_args(struct action *a)
6952 {
6953 	uint32_t i;
6954 
6955 	/* Return if the action does not have any args. */
6956 	if (!a->st)
6957 		return 0; /* FALSE */
6958 
6959 	for (i = 0; i < a->st->n_fields; i++)
6960 		if (a->args_endianness[i])
6961 			return 1; /* TRUE */
6962 
6963 	return 0; /* FALSE */
6964 }
6965 
6966 static int
6967 action_does_learning(struct action *a)
6968 {
6969 	uint32_t i;
6970 
6971 	for (i = 0; i < a->n_instructions; i++)
6972 		switch (a->instructions[i].type) {
6973 		case INSTR_LEARNER_LEARN:
6974 			return 1; /* TRUE */
6975 
6976 		case INSTR_LEARNER_FORGET:
6977 			return 1; /* TRUE */
6978 
6979 		default:
6980 			continue;
6981 		}
6982 
6983 	return 0; /* FALSE */
6984 }
6985 
6986 int
6987 rte_swx_pipeline_action_config(struct rte_swx_pipeline *p,
6988 			       const char *name,
6989 			       const char *args_struct_type_name,
6990 			       const char **instructions,
6991 			       uint32_t n_instructions)
6992 {
6993 	struct struct_type *args_struct_type = NULL;
6994 	struct action *a;
6995 	int err;
6996 
6997 	CHECK(p, EINVAL);
6998 
6999 	CHECK_NAME(name, EINVAL);
7000 	CHECK(!action_find(p, name), EEXIST);
7001 
7002 	if (args_struct_type_name) {
7003 		CHECK_NAME(args_struct_type_name, EINVAL);
7004 		args_struct_type = struct_type_find(p, args_struct_type_name);
7005 		CHECK(args_struct_type, EINVAL);
7006 		CHECK(!args_struct_type->var_size, EINVAL);
7007 	}
7008 
7009 	/* Node allocation. */
7010 	a = calloc(1, sizeof(struct action));
7011 	CHECK(a, ENOMEM);
7012 	if (args_struct_type) {
7013 		a->args_endianness = calloc(args_struct_type->n_fields, sizeof(int));
7014 		if (!a->args_endianness) {
7015 			free(a);
7016 			CHECK(0, ENOMEM);
7017 		}
7018 	}
7019 
7020 	/* Node initialization. */
7021 	strcpy(a->name, name);
7022 	a->st = args_struct_type;
7023 	a->id = p->n_actions;
7024 
7025 	/* Instruction translation. */
7026 	err = instruction_config(p, a, instructions, n_instructions);
7027 	if (err) {
7028 		free(a->args_endianness);
7029 		free(a);
7030 		return err;
7031 	}
7032 
7033 	/* Node add to tailq. */
7034 	TAILQ_INSERT_TAIL(&p->actions, a, node);
7035 	p->n_actions++;
7036 
7037 	return 0;
7038 }
7039 
7040 static int
7041 action_build(struct rte_swx_pipeline *p)
7042 {
7043 	struct action *action;
7044 
7045 	/* p->action_instructions. */
7046 	p->action_instructions = calloc(p->n_actions, sizeof(struct instruction *));
7047 	CHECK(p->action_instructions, ENOMEM);
7048 
7049 	TAILQ_FOREACH(action, &p->actions, node)
7050 		p->action_instructions[action->id] = action->instructions;
7051 
7052 	/* p->action_funcs. */
7053 	p->action_funcs = calloc(p->n_actions, sizeof(action_func_t));
7054 	CHECK(p->action_funcs, ENOMEM);
7055 
7056 	return 0;
7057 }
7058 
7059 static void
7060 action_build_free(struct rte_swx_pipeline *p)
7061 {
7062 	free(p->action_funcs);
7063 	p->action_funcs = NULL;
7064 
7065 	free(p->action_instructions);
7066 	p->action_instructions = NULL;
7067 }
7068 
7069 static void
7070 action_free(struct rte_swx_pipeline *p)
7071 {
7072 	action_build_free(p);
7073 
7074 	for ( ; ; ) {
7075 		struct action *action;
7076 
7077 		action = TAILQ_FIRST(&p->actions);
7078 		if (!action)
7079 			break;
7080 
7081 		TAILQ_REMOVE(&p->actions, action, node);
7082 		free(action->instruction_data);
7083 		free(action->instructions);
7084 		free(action);
7085 	}
7086 }
7087 
7088 static uint32_t
7089 action_arg_src_mov_count(struct action *a,
7090 			 uint32_t arg_id,
7091 			 struct instruction *instructions,
7092 			 struct instruction_data *instruction_data,
7093 			 uint32_t n_instructions)
7094 {
7095 	uint32_t offset, n_users = 0, i;
7096 
7097 	if (!a->st ||
7098 	    (arg_id >= a->st->n_fields) ||
7099 	    !instructions ||
7100 	    !instruction_data ||
7101 	    !n_instructions)
7102 		return 0;
7103 
7104 	offset = a->st->fields[arg_id].offset / 8;
7105 
7106 	for (i = 0; i < n_instructions; i++) {
7107 		struct instruction *instr = &instructions[i];
7108 		struct instruction_data *data = &instruction_data[i];
7109 
7110 		if (data->invalid ||
7111 		    ((instr->type != INSTR_MOV) && (instr->type != INSTR_MOV_HM)) ||
7112 		    instr->mov.src.struct_id ||
7113 		    (instr->mov.src.offset != offset))
7114 			continue;
7115 
7116 		n_users++;
7117 	}
7118 
7119 	return n_users;
7120 }
7121 
7122 /*
7123  * Table.
7124  */
7125 static struct table_type *
7126 table_type_find(struct rte_swx_pipeline *p, const char *name)
7127 {
7128 	struct table_type *elem;
7129 
7130 	TAILQ_FOREACH(elem, &p->table_types, node)
7131 		if (strcmp(elem->name, name) == 0)
7132 			return elem;
7133 
7134 	return NULL;
7135 }
7136 
7137 static struct table_type *
7138 table_type_resolve(struct rte_swx_pipeline *p,
7139 		   const char *recommended_type_name,
7140 		   enum rte_swx_table_match_type match_type)
7141 {
7142 	struct table_type *elem;
7143 
7144 	/* Only consider the recommended type if the match type is correct. */
7145 	if (recommended_type_name)
7146 		TAILQ_FOREACH(elem, &p->table_types, node)
7147 			if (!strcmp(elem->name, recommended_type_name) &&
7148 			    (elem->match_type == match_type))
7149 				return elem;
7150 
7151 	/* Ignore the recommended type and get the first element with this match
7152 	 * type.
7153 	 */
7154 	TAILQ_FOREACH(elem, &p->table_types, node)
7155 		if (elem->match_type == match_type)
7156 			return elem;
7157 
7158 	return NULL;
7159 }
7160 
7161 static struct table *
7162 table_find(struct rte_swx_pipeline *p, const char *name)
7163 {
7164 	struct table *elem;
7165 
7166 	TAILQ_FOREACH(elem, &p->tables, node)
7167 		if (strcmp(elem->name, name) == 0)
7168 			return elem;
7169 
7170 	return NULL;
7171 }
7172 
7173 static struct table *
7174 table_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
7175 {
7176 	struct table *table = NULL;
7177 
7178 	TAILQ_FOREACH(table, &p->tables, node)
7179 		if (table->id == id)
7180 			return table;
7181 
7182 	return NULL;
7183 }
7184 
7185 int
7186 rte_swx_pipeline_table_type_register(struct rte_swx_pipeline *p,
7187 				     const char *name,
7188 				     enum rte_swx_table_match_type match_type,
7189 				     struct rte_swx_table_ops *ops)
7190 {
7191 	struct table_type *elem;
7192 
7193 	CHECK(p, EINVAL);
7194 
7195 	CHECK_NAME(name, EINVAL);
7196 	CHECK(!table_type_find(p, name), EEXIST);
7197 
7198 	CHECK(ops, EINVAL);
7199 	CHECK(ops->create, EINVAL);
7200 	CHECK(ops->lkp, EINVAL);
7201 	CHECK(ops->free, EINVAL);
7202 
7203 	/* Node allocation. */
7204 	elem = calloc(1, sizeof(struct table_type));
7205 	CHECK(elem, ENOMEM);
7206 
7207 	/* Node initialization. */
7208 	strcpy(elem->name, name);
7209 	elem->match_type = match_type;
7210 	memcpy(&elem->ops, ops, sizeof(*ops));
7211 
7212 	/* Node add to tailq. */
7213 	TAILQ_INSERT_TAIL(&p->table_types, elem, node);
7214 
7215 	return 0;
7216 }
7217 
7218 static int
7219 table_match_type_resolve(struct rte_swx_match_field_params *fields,
7220 			 uint32_t n_fields,
7221 			 enum rte_swx_table_match_type *match_type)
7222 {
7223 	uint32_t n_fields_em = 0, n_fields_lpm = 0, i;
7224 
7225 	for (i = 0; i < n_fields; i++) {
7226 		struct rte_swx_match_field_params  *f = &fields[i];
7227 
7228 		if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT)
7229 			n_fields_em++;
7230 
7231 		if (f->match_type == RTE_SWX_TABLE_MATCH_LPM)
7232 			n_fields_lpm++;
7233 	}
7234 
7235 	if ((n_fields_lpm > 1) ||
7236 	    (n_fields_lpm && (n_fields_em != n_fields - 1)))
7237 		return -EINVAL;
7238 
7239 	*match_type = (n_fields_em == n_fields) ?
7240 		       RTE_SWX_TABLE_MATCH_EXACT :
7241 		       RTE_SWX_TABLE_MATCH_WILDCARD;
7242 
7243 	return 0;
7244 }
7245 
7246 static int
7247 table_match_fields_check(struct rte_swx_pipeline *p,
7248 			 struct rte_swx_pipeline_table_params *params,
7249 			 struct header **header)
7250 {
7251 	struct header *h0 = NULL;
7252 	struct field *hf, *mf;
7253 	uint32_t *offset = NULL, i;
7254 	int status = 0;
7255 
7256 	/* Return if no match fields. */
7257 	if (!params->n_fields) {
7258 		if (params->fields) {
7259 			status = -EINVAL;
7260 			goto end;
7261 		}
7262 
7263 		if (header)
7264 			*header = NULL;
7265 
7266 		return 0;
7267 	}
7268 
7269 	/* Memory allocation. */
7270 	offset = calloc(params->n_fields, sizeof(uint32_t));
7271 	if (!offset) {
7272 		status = -ENOMEM;
7273 		goto end;
7274 	}
7275 
7276 	/* Check that all the match fields belong to either the same header or
7277 	 * to the meta-data.
7278 	 */
7279 	hf = header_field_parse(p, params->fields[0].name, &h0);
7280 	mf = metadata_field_parse(p, params->fields[0].name);
7281 	if ((!hf && !mf) || (hf && hf->var_size)) {
7282 		status = -EINVAL;
7283 		goto end;
7284 	}
7285 
7286 	offset[0] = h0 ? hf->offset : mf->offset;
7287 
7288 	for (i = 1; i < params->n_fields; i++)
7289 		if (h0) {
7290 			struct header *h;
7291 
7292 			hf = header_field_parse(p, params->fields[i].name, &h);
7293 			if (!hf || (h->id != h0->id) || hf->var_size) {
7294 				status = -EINVAL;
7295 				goto end;
7296 			}
7297 
7298 			offset[i] = hf->offset;
7299 		} else {
7300 			mf = metadata_field_parse(p, params->fields[i].name);
7301 			if (!mf) {
7302 				status = -EINVAL;
7303 				goto end;
7304 			}
7305 
7306 			offset[i] = mf->offset;
7307 		}
7308 
7309 	/* Check that there are no duplicated match fields. */
7310 	for (i = 0; i < params->n_fields; i++) {
7311 		uint32_t j;
7312 
7313 		for (j = 0; j < i; j++)
7314 			if (offset[j] == offset[i]) {
7315 				status = -EINVAL;
7316 				goto end;
7317 			}
7318 	}
7319 
7320 	/* Return. */
7321 	if (header)
7322 		*header = h0;
7323 
7324 end:
7325 	free(offset);
7326 	return status;
7327 }
7328 
7329 int
7330 rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,
7331 			      const char *name,
7332 			      struct rte_swx_pipeline_table_params *params,
7333 			      const char *recommended_table_type_name,
7334 			      const char *args,
7335 			      uint32_t size)
7336 {
7337 	struct table_type *type;
7338 	struct table *t = NULL;
7339 	struct action *default_action;
7340 	struct header *header = NULL;
7341 	uint32_t action_data_size_max = 0, i;
7342 	int status = 0;
7343 
7344 	CHECK(p, EINVAL);
7345 
7346 	CHECK_NAME(name, EINVAL);
7347 	CHECK(!table_find(p, name), EEXIST);
7348 	CHECK(!selector_find(p, name), EEXIST);
7349 	CHECK(!learner_find(p, name), EEXIST);
7350 
7351 	CHECK(params, EINVAL);
7352 
7353 	/* Match checks. */
7354 	status = table_match_fields_check(p, params, &header);
7355 	if (status)
7356 		return status;
7357 
7358 	/* Action checks. */
7359 	CHECK(params->n_actions, EINVAL);
7360 	CHECK(params->action_names, EINVAL);
7361 	for (i = 0; i < params->n_actions; i++) {
7362 		const char *action_name = params->action_names[i];
7363 		struct action *a;
7364 		uint32_t action_data_size;
7365 		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
7366 
7367 		CHECK_NAME(action_name, EINVAL);
7368 
7369 		a = action_find(p, action_name);
7370 		CHECK(a, EINVAL);
7371 		CHECK(!action_does_learning(a), EINVAL);
7372 
7373 		action_data_size = a->st ? a->st->n_bits / 8 : 0;
7374 		if (action_data_size > action_data_size_max)
7375 			action_data_size_max = action_data_size;
7376 
7377 		if (params->action_is_for_table_entries)
7378 			action_is_for_table_entries = params->action_is_for_table_entries[i];
7379 		if (params->action_is_for_default_entry)
7380 			action_is_for_default_entry = params->action_is_for_default_entry[i];
7381 		CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL);
7382 	}
7383 
7384 	CHECK_NAME(params->default_action_name, EINVAL);
7385 	for (i = 0; i < p->n_actions; i++)
7386 		if (!strcmp(params->action_names[i],
7387 			    params->default_action_name))
7388 			break;
7389 	CHECK(i < params->n_actions, EINVAL);
7390 	CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i],
7391 	      EINVAL);
7392 
7393 	default_action = action_find(p, params->default_action_name);
7394 	CHECK((default_action->st && params->default_action_data) ||
7395 	      !params->default_action_data, EINVAL);
7396 
7397 	/* Table type checks. */
7398 	if (recommended_table_type_name)
7399 		CHECK_NAME(recommended_table_type_name, EINVAL);
7400 
7401 	if (params->n_fields) {
7402 		enum rte_swx_table_match_type match_type;
7403 
7404 		status = table_match_type_resolve(params->fields, params->n_fields, &match_type);
7405 		if (status)
7406 			return status;
7407 
7408 		type = table_type_resolve(p, recommended_table_type_name, match_type);
7409 		CHECK(type, EINVAL);
7410 	} else {
7411 		type = NULL;
7412 	}
7413 
7414 	/* Memory allocation. */
7415 	t = calloc(1, sizeof(struct table));
7416 	if (!t)
7417 		goto nomem;
7418 
7419 	t->fields = calloc(params->n_fields, sizeof(struct match_field));
7420 	if (!t->fields)
7421 		goto nomem;
7422 
7423 	t->actions = calloc(params->n_actions, sizeof(struct action *));
7424 	if (!t->actions)
7425 		goto nomem;
7426 
7427 	if (action_data_size_max) {
7428 		t->default_action_data = calloc(1, action_data_size_max);
7429 		if (!t->default_action_data)
7430 			goto nomem;
7431 	}
7432 
7433 	t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
7434 	if (!t->action_is_for_table_entries)
7435 		goto nomem;
7436 
7437 	t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
7438 	if (!t->action_is_for_default_entry)
7439 		goto nomem;
7440 
7441 	/* Node initialization. */
7442 	strcpy(t->name, name);
7443 	if (args && args[0])
7444 		strcpy(t->args, args);
7445 	t->type = type;
7446 
7447 	for (i = 0; i < params->n_fields; i++) {
7448 		struct rte_swx_match_field_params *field = &params->fields[i];
7449 		struct match_field *f = &t->fields[i];
7450 
7451 		f->match_type = field->match_type;
7452 		f->field = header ?
7453 			header_field_parse(p, field->name, NULL) :
7454 			metadata_field_parse(p, field->name);
7455 	}
7456 	t->n_fields = params->n_fields;
7457 	t->header = header;
7458 
7459 	for (i = 0; i < params->n_actions; i++) {
7460 		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
7461 
7462 		if (params->action_is_for_table_entries)
7463 			action_is_for_table_entries = params->action_is_for_table_entries[i];
7464 		if (params->action_is_for_default_entry)
7465 			action_is_for_default_entry = params->action_is_for_default_entry[i];
7466 
7467 		t->actions[i] = action_find(p, params->action_names[i]);
7468 		t->action_is_for_table_entries[i] = action_is_for_table_entries;
7469 		t->action_is_for_default_entry[i] = action_is_for_default_entry;
7470 	}
7471 	t->default_action = default_action;
7472 	if (default_action->st)
7473 		memcpy(t->default_action_data,
7474 		       params->default_action_data,
7475 		       default_action->st->n_bits / 8);
7476 	t->n_actions = params->n_actions;
7477 	t->default_action_is_const = params->default_action_is_const;
7478 	t->action_data_size_max = action_data_size_max;
7479 
7480 	t->size = size;
7481 	t->id = p->n_tables;
7482 
7483 	/* Node add to tailq. */
7484 	TAILQ_INSERT_TAIL(&p->tables, t, node);
7485 	p->n_tables++;
7486 
7487 	return 0;
7488 
7489 nomem:
7490 	if (!t)
7491 		return -ENOMEM;
7492 
7493 	free(t->action_is_for_default_entry);
7494 	free(t->action_is_for_table_entries);
7495 	free(t->default_action_data);
7496 	free(t->actions);
7497 	free(t->fields);
7498 	free(t);
7499 
7500 	return -ENOMEM;
7501 }
7502 
7503 static struct rte_swx_table_params *
7504 table_params_get(struct table *table)
7505 {
7506 	struct rte_swx_table_params *params;
7507 	struct field *first, *last;
7508 	uint8_t *key_mask;
7509 	uint32_t key_size, key_offset, action_data_size, i;
7510 
7511 	/* Memory allocation. */
7512 	params = calloc(1, sizeof(struct rte_swx_table_params));
7513 	if (!params)
7514 		return NULL;
7515 
7516 	/* Find first (smallest offset) and last (biggest offset) match fields. */
7517 	first = table->fields[0].field;
7518 	last = table->fields[0].field;
7519 
7520 	for (i = 0; i < table->n_fields; i++) {
7521 		struct field *f = table->fields[i].field;
7522 
7523 		if (f->offset < first->offset)
7524 			first = f;
7525 
7526 		if (f->offset > last->offset)
7527 			last = f;
7528 	}
7529 
7530 	/* Key offset and size. */
7531 	key_offset = first->offset / 8;
7532 	key_size = (last->offset + last->n_bits - first->offset) / 8;
7533 
7534 	/* Memory allocation. */
7535 	key_mask = calloc(1, key_size);
7536 	if (!key_mask) {
7537 		free(params);
7538 		return NULL;
7539 	}
7540 
7541 	/* Key mask. */
7542 	for (i = 0; i < table->n_fields; i++) {
7543 		struct field *f = table->fields[i].field;
7544 		uint32_t start = (f->offset - first->offset) / 8;
7545 		size_t size = f->n_bits / 8;
7546 
7547 		memset(&key_mask[start], 0xFF, size);
7548 	}
7549 
7550 	/* Action data size. */
7551 	action_data_size = 0;
7552 	for (i = 0; i < table->n_actions; i++) {
7553 		struct action *action = table->actions[i];
7554 		uint32_t ads = action->st ? action->st->n_bits / 8 : 0;
7555 
7556 		if (ads > action_data_size)
7557 			action_data_size = ads;
7558 	}
7559 
7560 	/* Fill in. */
7561 	params->match_type = table->type->match_type;
7562 	params->key_size = key_size;
7563 	params->key_offset = key_offset;
7564 	params->key_mask0 = key_mask;
7565 	params->action_data_size = action_data_size;
7566 	params->n_keys_max = table->size;
7567 
7568 	return params;
7569 }
7570 
7571 static void
7572 table_params_free(struct rte_swx_table_params *params)
7573 {
7574 	if (!params)
7575 		return;
7576 
7577 	free(params->key_mask0);
7578 	free(params);
7579 }
7580 
7581 static int
7582 table_stub_lkp(void *table __rte_unused,
7583 	       void *mailbox __rte_unused,
7584 	       uint8_t **key __rte_unused,
7585 	       uint64_t *action_id __rte_unused,
7586 	       uint8_t **action_data __rte_unused,
7587 	       int *hit)
7588 {
7589 	*hit = 0;
7590 	return 1; /* DONE. */
7591 }
7592 
7593 static int
7594 table_build(struct rte_swx_pipeline *p)
7595 {
7596 	uint32_t i;
7597 
7598 	/* Per pipeline: table statistics. */
7599 	p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics));
7600 	CHECK(p->table_stats, ENOMEM);
7601 
7602 	for (i = 0; i < p->n_tables; i++) {
7603 		p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t));
7604 		CHECK(p->table_stats[i].n_pkts_action, ENOMEM);
7605 	}
7606 
7607 	/* Per thread: table runt-time. */
7608 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7609 		struct thread *t = &p->threads[i];
7610 		struct table *table;
7611 
7612 		t->tables = calloc(p->n_tables, sizeof(struct table_runtime));
7613 		CHECK(t->tables, ENOMEM);
7614 
7615 		TAILQ_FOREACH(table, &p->tables, node) {
7616 			struct table_runtime *r = &t->tables[table->id];
7617 
7618 			if (table->type) {
7619 				uint64_t size;
7620 
7621 				size = table->type->ops.mailbox_size_get();
7622 
7623 				/* r->func. */
7624 				r->func = table->type->ops.lkp;
7625 
7626 				/* r->mailbox. */
7627 				if (size) {
7628 					r->mailbox = calloc(1, size);
7629 					CHECK(r->mailbox, ENOMEM);
7630 				}
7631 
7632 				/* r->key. */
7633 				r->key = table->header ?
7634 					&t->structs[table->header->struct_id] :
7635 					&t->structs[p->metadata_struct_id];
7636 			} else {
7637 				r->func = table_stub_lkp;
7638 			}
7639 		}
7640 	}
7641 
7642 	return 0;
7643 }
7644 
7645 static void
7646 table_build_free(struct rte_swx_pipeline *p)
7647 {
7648 	uint32_t i;
7649 
7650 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7651 		struct thread *t = &p->threads[i];
7652 		uint32_t j;
7653 
7654 		if (!t->tables)
7655 			continue;
7656 
7657 		for (j = 0; j < p->n_tables; j++) {
7658 			struct table_runtime *r = &t->tables[j];
7659 
7660 			free(r->mailbox);
7661 		}
7662 
7663 		free(t->tables);
7664 		t->tables = NULL;
7665 	}
7666 
7667 	if (p->table_stats) {
7668 		for (i = 0; i < p->n_tables; i++)
7669 			free(p->table_stats[i].n_pkts_action);
7670 
7671 		free(p->table_stats);
7672 	}
7673 }
7674 
7675 static void
7676 table_free(struct rte_swx_pipeline *p)
7677 {
7678 	table_build_free(p);
7679 
7680 	/* Tables. */
7681 	for ( ; ; ) {
7682 		struct table *elem;
7683 
7684 		elem = TAILQ_FIRST(&p->tables);
7685 		if (!elem)
7686 			break;
7687 
7688 		TAILQ_REMOVE(&p->tables, elem, node);
7689 		free(elem->fields);
7690 		free(elem->actions);
7691 		free(elem->default_action_data);
7692 		free(elem);
7693 	}
7694 
7695 	/* Table types. */
7696 	for ( ; ; ) {
7697 		struct table_type *elem;
7698 
7699 		elem = TAILQ_FIRST(&p->table_types);
7700 		if (!elem)
7701 			break;
7702 
7703 		TAILQ_REMOVE(&p->table_types, elem, node);
7704 		free(elem);
7705 	}
7706 }
7707 
7708 /*
7709  * Selector.
7710  */
7711 static struct selector *
7712 selector_find(struct rte_swx_pipeline *p, const char *name)
7713 {
7714 	struct selector *s;
7715 
7716 	TAILQ_FOREACH(s, &p->selectors, node)
7717 		if (strcmp(s->name, name) == 0)
7718 			return s;
7719 
7720 	return NULL;
7721 }
7722 
7723 static struct selector *
7724 selector_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
7725 {
7726 	struct selector *s = NULL;
7727 
7728 	TAILQ_FOREACH(s, &p->selectors, node)
7729 		if (s->id == id)
7730 			return s;
7731 
7732 	return NULL;
7733 }
7734 
7735 static int
7736 selector_fields_check(struct rte_swx_pipeline *p,
7737 		      struct rte_swx_pipeline_selector_params *params,
7738 		      struct header **header)
7739 {
7740 	struct header *h0 = NULL;
7741 	struct field *hf, *mf;
7742 	uint32_t i;
7743 
7744 	/* Return if no selector fields. */
7745 	if (!params->n_selector_fields || !params->selector_field_names)
7746 		return -EINVAL;
7747 
7748 	/* Check that all the selector fields either belong to the same header
7749 	 * or are all meta-data fields.
7750 	 */
7751 	hf = header_field_parse(p, params->selector_field_names[0], &h0);
7752 	mf = metadata_field_parse(p, params->selector_field_names[0]);
7753 	if (!hf && !mf)
7754 		return -EINVAL;
7755 
7756 	for (i = 1; i < params->n_selector_fields; i++)
7757 		if (h0) {
7758 			struct header *h;
7759 
7760 			hf = header_field_parse(p, params->selector_field_names[i], &h);
7761 			if (!hf || (h->id != h0->id))
7762 				return -EINVAL;
7763 		} else {
7764 			mf = metadata_field_parse(p, params->selector_field_names[i]);
7765 			if (!mf)
7766 				return -EINVAL;
7767 		}
7768 
7769 	/* Check that there are no duplicated match fields. */
7770 	for (i = 0; i < params->n_selector_fields; i++) {
7771 		const char *field_name = params->selector_field_names[i];
7772 		uint32_t j;
7773 
7774 		for (j = i + 1; j < params->n_selector_fields; j++)
7775 			if (!strcmp(params->selector_field_names[j], field_name))
7776 				return -EINVAL;
7777 	}
7778 
7779 	/* Return. */
7780 	if (header)
7781 		*header = h0;
7782 
7783 	return 0;
7784 }
7785 
7786 int
7787 rte_swx_pipeline_selector_config(struct rte_swx_pipeline *p,
7788 				 const char *name,
7789 				 struct rte_swx_pipeline_selector_params *params)
7790 {
7791 	struct selector *s;
7792 	struct header *selector_header = NULL;
7793 	struct field *group_id_field, *member_id_field;
7794 	uint32_t i;
7795 	int status = 0;
7796 
7797 	CHECK(p, EINVAL);
7798 
7799 	CHECK_NAME(name, EINVAL);
7800 	CHECK(!table_find(p, name), EEXIST);
7801 	CHECK(!selector_find(p, name), EEXIST);
7802 	CHECK(!learner_find(p, name), EEXIST);
7803 
7804 	CHECK(params, EINVAL);
7805 
7806 	CHECK_NAME(params->group_id_field_name, EINVAL);
7807 	group_id_field = metadata_field_parse(p, params->group_id_field_name);
7808 	CHECK(group_id_field, EINVAL);
7809 
7810 	for (i = 0; i < params->n_selector_fields; i++) {
7811 		const char *field_name = params->selector_field_names[i];
7812 
7813 		CHECK_NAME(field_name, EINVAL);
7814 	}
7815 	status = selector_fields_check(p, params, &selector_header);
7816 	if (status)
7817 		return status;
7818 
7819 	CHECK_NAME(params->member_id_field_name, EINVAL);
7820 	member_id_field = metadata_field_parse(p, params->member_id_field_name);
7821 	CHECK(member_id_field, EINVAL);
7822 
7823 	CHECK(params->n_groups_max, EINVAL);
7824 
7825 	CHECK(params->n_members_per_group_max, EINVAL);
7826 
7827 	/* Memory allocation. */
7828 	s = calloc(1, sizeof(struct selector));
7829 	if (!s) {
7830 		status = -ENOMEM;
7831 		goto error;
7832 	}
7833 
7834 	s->selector_fields = calloc(params->n_selector_fields, sizeof(struct field *));
7835 	if (!s->selector_fields) {
7836 		status = -ENOMEM;
7837 		goto error;
7838 	}
7839 
7840 	/* Node initialization. */
7841 	strcpy(s->name, name);
7842 
7843 	s->group_id_field = group_id_field;
7844 
7845 	for (i = 0; i < params->n_selector_fields; i++) {
7846 		const char *field_name = params->selector_field_names[i];
7847 
7848 		s->selector_fields[i] = selector_header ?
7849 			header_field_parse(p, field_name, NULL) :
7850 			metadata_field_parse(p, field_name);
7851 	}
7852 
7853 	s->n_selector_fields = params->n_selector_fields;
7854 
7855 	s->selector_header = selector_header;
7856 
7857 	s->member_id_field = member_id_field;
7858 
7859 	s->n_groups_max = params->n_groups_max;
7860 
7861 	s->n_members_per_group_max = params->n_members_per_group_max;
7862 
7863 	s->id = p->n_selectors;
7864 
7865 	/* Node add to tailq. */
7866 	TAILQ_INSERT_TAIL(&p->selectors, s, node);
7867 	p->n_selectors++;
7868 
7869 	return 0;
7870 
7871 error:
7872 	if (!s)
7873 		return status;
7874 
7875 	free(s->selector_fields);
7876 
7877 	free(s);
7878 
7879 	return status;
7880 }
7881 
7882 static void
7883 selector_params_free(struct rte_swx_table_selector_params *params)
7884 {
7885 	if (!params)
7886 		return;
7887 
7888 	free(params->selector_mask);
7889 
7890 	free(params);
7891 }
7892 
7893 static struct rte_swx_table_selector_params *
7894 selector_table_params_get(struct selector *s)
7895 {
7896 	struct rte_swx_table_selector_params *params = NULL;
7897 	struct field *first, *last;
7898 	uint32_t i;
7899 
7900 	/* Memory allocation. */
7901 	params = calloc(1, sizeof(struct rte_swx_table_selector_params));
7902 	if (!params)
7903 		goto error;
7904 
7905 	/* Group ID. */
7906 	params->group_id_offset = s->group_id_field->offset / 8;
7907 
7908 	/* Find first (smallest offset) and last (biggest offset) selector fields. */
7909 	first = s->selector_fields[0];
7910 	last = s->selector_fields[0];
7911 
7912 	for (i = 0; i < s->n_selector_fields; i++) {
7913 		struct field *f = s->selector_fields[i];
7914 
7915 		if (f->offset < first->offset)
7916 			first = f;
7917 
7918 		if (f->offset > last->offset)
7919 			last = f;
7920 	}
7921 
7922 	/* Selector offset and size. */
7923 	params->selector_offset = first->offset / 8;
7924 	params->selector_size = (last->offset + last->n_bits - first->offset) / 8;
7925 
7926 	/* Memory allocation. */
7927 	params->selector_mask = calloc(1, params->selector_size);
7928 	if (!params->selector_mask)
7929 		goto error;
7930 
7931 	/* Selector mask. */
7932 	for (i = 0; i < s->n_selector_fields; i++) {
7933 		struct field *f = s->selector_fields[i];
7934 		uint32_t start = (f->offset - first->offset) / 8;
7935 		size_t size = f->n_bits / 8;
7936 
7937 		memset(&params->selector_mask[start], 0xFF, size);
7938 	}
7939 
7940 	/* Member ID. */
7941 	params->member_id_offset = s->member_id_field->offset / 8;
7942 
7943 	/* Maximum number of groups. */
7944 	params->n_groups_max = s->n_groups_max;
7945 
7946 	/* Maximum number of members per group. */
7947 	params->n_members_per_group_max = s->n_members_per_group_max;
7948 
7949 	return params;
7950 
7951 error:
7952 	selector_params_free(params);
7953 	return NULL;
7954 }
7955 
7956 static void
7957 selector_build_free(struct rte_swx_pipeline *p)
7958 {
7959 	uint32_t i;
7960 
7961 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7962 		struct thread *t = &p->threads[i];
7963 		uint32_t j;
7964 
7965 		if (!t->selectors)
7966 			continue;
7967 
7968 		for (j = 0; j < p->n_selectors; j++) {
7969 			struct selector_runtime *r = &t->selectors[j];
7970 
7971 			free(r->mailbox);
7972 		}
7973 
7974 		free(t->selectors);
7975 		t->selectors = NULL;
7976 	}
7977 
7978 	free(p->selector_stats);
7979 	p->selector_stats = NULL;
7980 }
7981 
7982 static int
7983 selector_build(struct rte_swx_pipeline *p)
7984 {
7985 	uint32_t i;
7986 	int status = 0;
7987 
7988 	/* Per pipeline: selector statistics. */
7989 	p->selector_stats = calloc(p->n_selectors, sizeof(struct selector_statistics));
7990 	if (!p->selector_stats) {
7991 		status = -ENOMEM;
7992 		goto error;
7993 	}
7994 
7995 	/* Per thread: selector run-time. */
7996 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
7997 		struct thread *t = &p->threads[i];
7998 		struct selector *s;
7999 
8000 		t->selectors = calloc(p->n_selectors, sizeof(struct selector_runtime));
8001 		if (!t->selectors) {
8002 			status = -ENOMEM;
8003 			goto error;
8004 		}
8005 
8006 		TAILQ_FOREACH(s, &p->selectors, node) {
8007 			struct selector_runtime *r = &t->selectors[s->id];
8008 			uint64_t size;
8009 
8010 			/* r->mailbox. */
8011 			size = rte_swx_table_selector_mailbox_size_get();
8012 			if (size) {
8013 				r->mailbox = calloc(1, size);
8014 				if (!r->mailbox) {
8015 					status = -ENOMEM;
8016 					goto error;
8017 				}
8018 			}
8019 
8020 			/* r->group_id_buffer. */
8021 			r->group_id_buffer = &t->structs[p->metadata_struct_id];
8022 
8023 			/* r->selector_buffer. */
8024 			r->selector_buffer = s->selector_header ?
8025 				&t->structs[s->selector_header->struct_id] :
8026 				&t->structs[p->metadata_struct_id];
8027 
8028 			/* r->member_id_buffer. */
8029 			r->member_id_buffer = &t->structs[p->metadata_struct_id];
8030 		}
8031 	}
8032 
8033 	return 0;
8034 
8035 error:
8036 	selector_build_free(p);
8037 	return status;
8038 }
8039 
8040 static void
8041 selector_free(struct rte_swx_pipeline *p)
8042 {
8043 	selector_build_free(p);
8044 
8045 	/* Selector tables. */
8046 	for ( ; ; ) {
8047 		struct selector *elem;
8048 
8049 		elem = TAILQ_FIRST(&p->selectors);
8050 		if (!elem)
8051 			break;
8052 
8053 		TAILQ_REMOVE(&p->selectors, elem, node);
8054 		free(elem->selector_fields);
8055 		free(elem);
8056 	}
8057 }
8058 
8059 /*
8060  * Learner table.
8061  */
8062 static struct learner *
8063 learner_find(struct rte_swx_pipeline *p, const char *name)
8064 {
8065 	struct learner *l;
8066 
8067 	TAILQ_FOREACH(l, &p->learners, node)
8068 		if (!strcmp(l->name, name))
8069 			return l;
8070 
8071 	return NULL;
8072 }
8073 
8074 static struct learner *
8075 learner_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
8076 {
8077 	struct learner *l = NULL;
8078 
8079 	TAILQ_FOREACH(l, &p->learners, node)
8080 		if (l->id == id)
8081 			return l;
8082 
8083 	return NULL;
8084 }
8085 
8086 static int
8087 learner_match_fields_check(struct rte_swx_pipeline *p,
8088 			   struct rte_swx_pipeline_learner_params *params,
8089 			   struct header **header)
8090 {
8091 	struct header *h0 = NULL;
8092 	struct field *hf, *mf;
8093 	uint32_t i;
8094 
8095 	/* Return if no match fields. */
8096 	if (!params->n_fields || !params->field_names)
8097 		return -EINVAL;
8098 
8099 	/* Check that all the match fields either belong to the same header
8100 	 * or are all meta-data fields.
8101 	 */
8102 	hf = header_field_parse(p, params->field_names[0], &h0);
8103 	mf = metadata_field_parse(p, params->field_names[0]);
8104 	if (!hf && !mf)
8105 		return -EINVAL;
8106 
8107 	for (i = 1; i < params->n_fields; i++)
8108 		if (h0) {
8109 			struct header *h;
8110 
8111 			hf = header_field_parse(p, params->field_names[i], &h);
8112 			if (!hf || (h->id != h0->id))
8113 				return -EINVAL;
8114 		} else {
8115 			mf = metadata_field_parse(p, params->field_names[i]);
8116 			if (!mf)
8117 				return -EINVAL;
8118 		}
8119 
8120 	/* Check that there are no duplicated match fields. */
8121 	for (i = 0; i < params->n_fields; i++) {
8122 		const char *field_name = params->field_names[i];
8123 		uint32_t j;
8124 
8125 		for (j = i + 1; j < params->n_fields; j++)
8126 			if (!strcmp(params->field_names[j], field_name))
8127 				return -EINVAL;
8128 	}
8129 
8130 	/* Return. */
8131 	if (header)
8132 		*header = h0;
8133 
8134 	return 0;
8135 }
8136 
8137 static int
8138 learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name)
8139 {
8140 	struct struct_type *mst = p->metadata_st, *ast = a->st;
8141 	struct field *mf, *af;
8142 	uint32_t mf_pos, i;
8143 
8144 	if (!ast) {
8145 		if (mf_name)
8146 			return -EINVAL;
8147 
8148 		return 0;
8149 	}
8150 
8151 	/* Check that mf_name is the name of a valid meta-data field. */
8152 	CHECK_NAME(mf_name, EINVAL);
8153 	mf = metadata_field_parse(p, mf_name);
8154 	CHECK(mf, EINVAL);
8155 
8156 	/* Check that there are enough meta-data fields, starting with the mf_name field, to cover
8157 	 * all the action arguments.
8158 	 */
8159 	mf_pos = mf - mst->fields;
8160 	CHECK(mst->n_fields - mf_pos >= ast->n_fields, EINVAL);
8161 
8162 	/* Check that the size of each of the identified meta-data fields matches exactly the size
8163 	 * of the corresponding action argument.
8164 	 */
8165 	for (i = 0; i < ast->n_fields; i++) {
8166 		mf = &mst->fields[mf_pos + i];
8167 		af = &ast->fields[i];
8168 
8169 		CHECK(mf->n_bits == af->n_bits, EINVAL);
8170 	}
8171 
8172 	return 0;
8173 }
8174 
8175 static int
8176 learner_action_learning_check(struct rte_swx_pipeline *p,
8177 			      struct action *action,
8178 			      const char **action_names,
8179 			      uint32_t n_actions)
8180 {
8181 	uint32_t i;
8182 
8183 	/* For each "learn" instruction of the current action, check that the learned action (i.e.
8184 	 * the action passed as argument to the "learn" instruction) is also enabled for the
8185 	 * current learner table.
8186 	 */
8187 	for (i = 0; i < action->n_instructions; i++) {
8188 		struct instruction *instr = &action->instructions[i];
8189 		uint32_t found = 0, j;
8190 
8191 		if (instr->type != INSTR_LEARNER_LEARN)
8192 			continue;
8193 
8194 		for (j = 0; j < n_actions; j++) {
8195 			struct action *a;
8196 
8197 			a = action_find(p, action_names[j]);
8198 			if (!a)
8199 				return -EINVAL;
8200 
8201 			if (a->id == instr->learn.action_id)
8202 				found = 1;
8203 		}
8204 
8205 		if (!found)
8206 			return -EINVAL;
8207 	}
8208 
8209 	return 0;
8210 }
8211 
8212 int
8213 rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p,
8214 			      const char *name,
8215 			      struct rte_swx_pipeline_learner_params *params,
8216 			      uint32_t size,
8217 			      uint32_t timeout)
8218 {
8219 	struct learner *l = NULL;
8220 	struct action *default_action;
8221 	struct header *header = NULL;
8222 	uint32_t action_data_size_max = 0, i;
8223 	int status = 0;
8224 
8225 	CHECK(p, EINVAL);
8226 
8227 	CHECK_NAME(name, EINVAL);
8228 	CHECK(!table_find(p, name), EEXIST);
8229 	CHECK(!selector_find(p, name), EEXIST);
8230 	CHECK(!learner_find(p, name), EEXIST);
8231 
8232 	CHECK(params, EINVAL);
8233 
8234 	/* Match checks. */
8235 	status = learner_match_fields_check(p, params, &header);
8236 	if (status)
8237 		return status;
8238 
8239 	/* Action checks. */
8240 	CHECK(params->n_actions, EINVAL);
8241 	CHECK(params->action_names, EINVAL);
8242 	for (i = 0; i < params->n_actions; i++) {
8243 		const char *action_name = params->action_names[i];
8244 		struct action *a;
8245 		uint32_t action_data_size;
8246 		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
8247 
8248 		CHECK_NAME(action_name, EINVAL);
8249 
8250 		a = action_find(p, action_name);
8251 		CHECK(a, EINVAL);
8252 
8253 		status = learner_action_learning_check(p,
8254 						       a,
8255 						       params->action_names,
8256 						       params->n_actions);
8257 		if (status)
8258 			return status;
8259 
8260 		action_data_size = a->st ? a->st->n_bits / 8 : 0;
8261 		if (action_data_size > action_data_size_max)
8262 			action_data_size_max = action_data_size;
8263 
8264 		if (params->action_is_for_table_entries)
8265 			action_is_for_table_entries = params->action_is_for_table_entries[i];
8266 		if (params->action_is_for_default_entry)
8267 			action_is_for_default_entry = params->action_is_for_default_entry[i];
8268 		CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL);
8269 	}
8270 
8271 	CHECK_NAME(params->default_action_name, EINVAL);
8272 	for (i = 0; i < p->n_actions; i++)
8273 		if (!strcmp(params->action_names[i],
8274 			    params->default_action_name))
8275 			break;
8276 	CHECK(i < params->n_actions, EINVAL);
8277 	CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i],
8278 	      EINVAL);
8279 
8280 	default_action = action_find(p, params->default_action_name);
8281 	CHECK((default_action->st && params->default_action_data) ||
8282 	      !params->default_action_data, EINVAL);
8283 
8284 	/* Any other checks. */
8285 	CHECK(size, EINVAL);
8286 	CHECK(timeout, EINVAL);
8287 
8288 	/* Memory allocation. */
8289 	l = calloc(1, sizeof(struct learner));
8290 	if (!l)
8291 		goto nomem;
8292 
8293 	l->fields = calloc(params->n_fields, sizeof(struct field *));
8294 	if (!l->fields)
8295 		goto nomem;
8296 
8297 	l->actions = calloc(params->n_actions, sizeof(struct action *));
8298 	if (!l->actions)
8299 		goto nomem;
8300 
8301 	if (action_data_size_max) {
8302 		l->default_action_data = calloc(1, action_data_size_max);
8303 		if (!l->default_action_data)
8304 			goto nomem;
8305 	}
8306 
8307 	l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
8308 	if (!l->action_is_for_table_entries)
8309 		goto nomem;
8310 
8311 	l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
8312 	if (!l->action_is_for_default_entry)
8313 		goto nomem;
8314 
8315 	/* Node initialization. */
8316 	strcpy(l->name, name);
8317 
8318 	for (i = 0; i < params->n_fields; i++) {
8319 		const char *field_name = params->field_names[i];
8320 
8321 		l->fields[i] = header ?
8322 			header_field_parse(p, field_name, NULL) :
8323 			metadata_field_parse(p, field_name);
8324 	}
8325 
8326 	l->n_fields = params->n_fields;
8327 
8328 	l->header = header;
8329 
8330 	for (i = 0; i < params->n_actions; i++) {
8331 		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
8332 
8333 		if (params->action_is_for_table_entries)
8334 			action_is_for_table_entries = params->action_is_for_table_entries[i];
8335 		if (params->action_is_for_default_entry)
8336 			action_is_for_default_entry = params->action_is_for_default_entry[i];
8337 
8338 		l->actions[i] = action_find(p, params->action_names[i]);
8339 		l->action_is_for_table_entries[i] = action_is_for_table_entries;
8340 		l->action_is_for_default_entry[i] = action_is_for_default_entry;
8341 	}
8342 
8343 	l->default_action = default_action;
8344 
8345 	if (default_action->st)
8346 		memcpy(l->default_action_data,
8347 		       params->default_action_data,
8348 		       default_action->st->n_bits / 8);
8349 
8350 	l->n_actions = params->n_actions;
8351 
8352 	l->default_action_is_const = params->default_action_is_const;
8353 
8354 	l->action_data_size_max = action_data_size_max;
8355 
8356 	l->size = size;
8357 
8358 	l->timeout = timeout;
8359 
8360 	l->id = p->n_learners;
8361 
8362 	/* Node add to tailq. */
8363 	TAILQ_INSERT_TAIL(&p->learners, l, node);
8364 	p->n_learners++;
8365 
8366 	return 0;
8367 
8368 nomem:
8369 	if (!l)
8370 		return -ENOMEM;
8371 
8372 	free(l->action_is_for_default_entry);
8373 	free(l->action_is_for_table_entries);
8374 	free(l->default_action_data);
8375 	free(l->actions);
8376 	free(l->fields);
8377 	free(l);
8378 
8379 	return -ENOMEM;
8380 }
8381 
8382 static void
8383 learner_params_free(struct rte_swx_table_learner_params *params)
8384 {
8385 	if (!params)
8386 		return;
8387 
8388 	free(params->key_mask0);
8389 
8390 	free(params);
8391 }
8392 
8393 static struct rte_swx_table_learner_params *
8394 learner_params_get(struct learner *l)
8395 {
8396 	struct rte_swx_table_learner_params *params = NULL;
8397 	struct field *first, *last;
8398 	uint32_t i;
8399 
8400 	/* Memory allocation. */
8401 	params = calloc(1, sizeof(struct rte_swx_table_learner_params));
8402 	if (!params)
8403 		goto error;
8404 
8405 	/* Find first (smallest offset) and last (biggest offset) match fields. */
8406 	first = l->fields[0];
8407 	last = l->fields[0];
8408 
8409 	for (i = 0; i < l->n_fields; i++) {
8410 		struct field *f = l->fields[i];
8411 
8412 		if (f->offset < first->offset)
8413 			first = f;
8414 
8415 		if (f->offset > last->offset)
8416 			last = f;
8417 	}
8418 
8419 	/* Key offset and size. */
8420 	params->key_offset = first->offset / 8;
8421 	params->key_size = (last->offset + last->n_bits - first->offset) / 8;
8422 
8423 	/* Memory allocation. */
8424 	params->key_mask0 = calloc(1, params->key_size);
8425 	if (!params->key_mask0)
8426 		goto error;
8427 
8428 	/* Key mask. */
8429 	for (i = 0; i < l->n_fields; i++) {
8430 		struct field *f = l->fields[i];
8431 		uint32_t start = (f->offset - first->offset) / 8;
8432 		size_t size = f->n_bits / 8;
8433 
8434 		memset(&params->key_mask0[start], 0xFF, size);
8435 	}
8436 
8437 	/* Action data size. */
8438 	params->action_data_size = l->action_data_size_max;
8439 
8440 	/* Maximum number of keys. */
8441 	params->n_keys_max = l->size;
8442 
8443 	/* Timeout. */
8444 	params->key_timeout = l->timeout;
8445 
8446 	return params;
8447 
8448 error:
8449 	learner_params_free(params);
8450 	return NULL;
8451 }
8452 
8453 static void
8454 learner_build_free(struct rte_swx_pipeline *p)
8455 {
8456 	uint32_t i;
8457 
8458 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
8459 		struct thread *t = &p->threads[i];
8460 		uint32_t j;
8461 
8462 		if (!t->learners)
8463 			continue;
8464 
8465 		for (j = 0; j < p->n_learners; j++) {
8466 			struct learner_runtime *r = &t->learners[j];
8467 
8468 			free(r->mailbox);
8469 		}
8470 
8471 		free(t->learners);
8472 		t->learners = NULL;
8473 	}
8474 
8475 	if (p->learner_stats) {
8476 		for (i = 0; i < p->n_learners; i++)
8477 			free(p->learner_stats[i].n_pkts_action);
8478 
8479 		free(p->learner_stats);
8480 	}
8481 }
8482 
8483 static int
8484 learner_build(struct rte_swx_pipeline *p)
8485 {
8486 	uint32_t i;
8487 	int status = 0;
8488 
8489 	/* Per pipeline: learner statistics. */
8490 	p->learner_stats = calloc(p->n_learners, sizeof(struct learner_statistics));
8491 	CHECK(p->learner_stats, ENOMEM);
8492 
8493 	for (i = 0; i < p->n_learners; i++) {
8494 		p->learner_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t));
8495 		CHECK(p->learner_stats[i].n_pkts_action, ENOMEM);
8496 	}
8497 
8498 	/* Per thread: learner run-time. */
8499 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
8500 		struct thread *t = &p->threads[i];
8501 		struct learner *l;
8502 
8503 		t->learners = calloc(p->n_learners, sizeof(struct learner_runtime));
8504 		if (!t->learners) {
8505 			status = -ENOMEM;
8506 			goto error;
8507 		}
8508 
8509 		TAILQ_FOREACH(l, &p->learners, node) {
8510 			struct learner_runtime *r = &t->learners[l->id];
8511 			uint64_t size;
8512 
8513 			/* r->mailbox. */
8514 			size = rte_swx_table_learner_mailbox_size_get();
8515 			if (size) {
8516 				r->mailbox = calloc(1, size);
8517 				if (!r->mailbox) {
8518 					status = -ENOMEM;
8519 					goto error;
8520 				}
8521 			}
8522 
8523 			/* r->key. */
8524 			r->key = l->header ?
8525 				&t->structs[l->header->struct_id] :
8526 				&t->structs[p->metadata_struct_id];
8527 		}
8528 	}
8529 
8530 	return 0;
8531 
8532 error:
8533 	learner_build_free(p);
8534 	return status;
8535 }
8536 
8537 static void
8538 learner_free(struct rte_swx_pipeline *p)
8539 {
8540 	learner_build_free(p);
8541 
8542 	/* Learner tables. */
8543 	for ( ; ; ) {
8544 		struct learner *l;
8545 
8546 		l = TAILQ_FIRST(&p->learners);
8547 		if (!l)
8548 			break;
8549 
8550 		TAILQ_REMOVE(&p->learners, l, node);
8551 		free(l->fields);
8552 		free(l->actions);
8553 		free(l->default_action_data);
8554 		free(l);
8555 	}
8556 }
8557 
8558 /*
8559  * Table state.
8560  */
8561 static int
8562 table_state_build(struct rte_swx_pipeline *p)
8563 {
8564 	struct table *table;
8565 	struct selector *s;
8566 	struct learner *l;
8567 
8568 	p->table_state = calloc(p->n_tables + p->n_selectors + p->n_learners,
8569 				sizeof(struct rte_swx_table_state));
8570 	CHECK(p->table_state, ENOMEM);
8571 
8572 	TAILQ_FOREACH(table, &p->tables, node) {
8573 		struct rte_swx_table_state *ts = &p->table_state[table->id];
8574 
8575 		if (table->type) {
8576 			struct rte_swx_table_params *params;
8577 
8578 			/* ts->obj. */
8579 			params = table_params_get(table);
8580 			CHECK(params, ENOMEM);
8581 
8582 			ts->obj = table->type->ops.create(params,
8583 				NULL,
8584 				table->args,
8585 				p->numa_node);
8586 
8587 			table_params_free(params);
8588 			CHECK(ts->obj, ENODEV);
8589 		}
8590 
8591 		/* ts->default_action_data. */
8592 		if (table->action_data_size_max) {
8593 			ts->default_action_data =
8594 				malloc(table->action_data_size_max);
8595 			CHECK(ts->default_action_data, ENOMEM);
8596 
8597 			memcpy(ts->default_action_data,
8598 			       table->default_action_data,
8599 			       table->action_data_size_max);
8600 		}
8601 
8602 		/* ts->default_action_id. */
8603 		ts->default_action_id = table->default_action->id;
8604 	}
8605 
8606 	TAILQ_FOREACH(s, &p->selectors, node) {
8607 		struct rte_swx_table_state *ts = &p->table_state[p->n_tables + s->id];
8608 		struct rte_swx_table_selector_params *params;
8609 
8610 		/* ts->obj. */
8611 		params = selector_table_params_get(s);
8612 		CHECK(params, ENOMEM);
8613 
8614 		ts->obj = rte_swx_table_selector_create(params, NULL, p->numa_node);
8615 
8616 		selector_params_free(params);
8617 		CHECK(ts->obj, ENODEV);
8618 	}
8619 
8620 	TAILQ_FOREACH(l, &p->learners, node) {
8621 		struct rte_swx_table_state *ts = &p->table_state[p->n_tables +
8622 			p->n_selectors + l->id];
8623 		struct rte_swx_table_learner_params *params;
8624 
8625 		/* ts->obj. */
8626 		params = learner_params_get(l);
8627 		CHECK(params, ENOMEM);
8628 
8629 		ts->obj = rte_swx_table_learner_create(params, p->numa_node);
8630 		learner_params_free(params);
8631 		CHECK(ts->obj, ENODEV);
8632 
8633 		/* ts->default_action_data. */
8634 		if (l->action_data_size_max) {
8635 			ts->default_action_data = malloc(l->action_data_size_max);
8636 			CHECK(ts->default_action_data, ENOMEM);
8637 
8638 			memcpy(ts->default_action_data,
8639 			       l->default_action_data,
8640 			       l->action_data_size_max);
8641 		}
8642 
8643 		/* ts->default_action_id. */
8644 		ts->default_action_id = l->default_action->id;
8645 	}
8646 
8647 	return 0;
8648 }
8649 
8650 static void
8651 table_state_build_free(struct rte_swx_pipeline *p)
8652 {
8653 	uint32_t i;
8654 
8655 	if (!p->table_state)
8656 		return;
8657 
8658 	for (i = 0; i < p->n_tables; i++) {
8659 		struct rte_swx_table_state *ts = &p->table_state[i];
8660 		struct table *table = table_find_by_id(p, i);
8661 
8662 		/* ts->obj. */
8663 		if (table->type && ts->obj)
8664 			table->type->ops.free(ts->obj);
8665 
8666 		/* ts->default_action_data. */
8667 		free(ts->default_action_data);
8668 	}
8669 
8670 	for (i = 0; i < p->n_selectors; i++) {
8671 		struct rte_swx_table_state *ts = &p->table_state[p->n_tables + i];
8672 
8673 		/* ts->obj. */
8674 		if (ts->obj)
8675 			rte_swx_table_selector_free(ts->obj);
8676 	}
8677 
8678 	for (i = 0; i < p->n_learners; i++) {
8679 		struct rte_swx_table_state *ts = &p->table_state[p->n_tables + p->n_selectors + i];
8680 
8681 		/* ts->obj. */
8682 		if (ts->obj)
8683 			rte_swx_table_learner_free(ts->obj);
8684 
8685 		/* ts->default_action_data. */
8686 		free(ts->default_action_data);
8687 	}
8688 
8689 	free(p->table_state);
8690 	p->table_state = NULL;
8691 }
8692 
8693 static void
8694 table_state_free(struct rte_swx_pipeline *p)
8695 {
8696 	table_state_build_free(p);
8697 }
8698 
8699 /*
8700  * Register array.
8701  */
8702 static struct regarray *
8703 regarray_find(struct rte_swx_pipeline *p, const char *name)
8704 {
8705 	struct regarray *elem;
8706 
8707 	TAILQ_FOREACH(elem, &p->regarrays, node)
8708 		if (!strcmp(elem->name, name))
8709 			return elem;
8710 
8711 	return NULL;
8712 }
8713 
8714 static struct regarray *
8715 regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
8716 {
8717 	struct regarray *elem = NULL;
8718 
8719 	TAILQ_FOREACH(elem, &p->regarrays, node)
8720 		if (elem->id == id)
8721 			return elem;
8722 
8723 	return NULL;
8724 }
8725 
8726 int
8727 rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,
8728 			      const char *name,
8729 			      uint32_t size,
8730 			      uint64_t init_val)
8731 {
8732 	struct regarray *r;
8733 
8734 	CHECK(p, EINVAL);
8735 
8736 	CHECK_NAME(name, EINVAL);
8737 	CHECK(!regarray_find(p, name), EEXIST);
8738 
8739 	CHECK(size, EINVAL);
8740 	size = rte_align32pow2(size);
8741 
8742 	/* Memory allocation. */
8743 	r = calloc(1, sizeof(struct regarray));
8744 	CHECK(r, ENOMEM);
8745 
8746 	/* Node initialization. */
8747 	strcpy(r->name, name);
8748 	r->init_val = init_val;
8749 	r->size = size;
8750 	r->id = p->n_regarrays;
8751 
8752 	/* Node add to tailq. */
8753 	TAILQ_INSERT_TAIL(&p->regarrays, r, node);
8754 	p->n_regarrays++;
8755 
8756 	return 0;
8757 }
8758 
8759 static int
8760 regarray_build(struct rte_swx_pipeline *p)
8761 {
8762 	struct regarray *regarray;
8763 
8764 	if (!p->n_regarrays)
8765 		return 0;
8766 
8767 	p->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime));
8768 	CHECK(p->regarray_runtime, ENOMEM);
8769 
8770 	TAILQ_FOREACH(regarray, &p->regarrays, node) {
8771 		struct regarray_runtime *r = &p->regarray_runtime[regarray->id];
8772 		uint32_t i;
8773 
8774 		r->regarray = env_malloc(regarray->size * sizeof(uint64_t),
8775 					 RTE_CACHE_LINE_SIZE,
8776 					 p->numa_node);
8777 		CHECK(r->regarray, ENOMEM);
8778 
8779 		if (regarray->init_val)
8780 			for (i = 0; i < regarray->size; i++)
8781 				r->regarray[i] = regarray->init_val;
8782 
8783 		r->size_mask = regarray->size - 1;
8784 	}
8785 
8786 	return 0;
8787 }
8788 
8789 static void
8790 regarray_build_free(struct rte_swx_pipeline *p)
8791 {
8792 	uint32_t i;
8793 
8794 	if (!p->regarray_runtime)
8795 		return;
8796 
8797 	for (i = 0; i < p->n_regarrays; i++) {
8798 		struct regarray *regarray = regarray_find_by_id(p, i);
8799 		struct regarray_runtime *r = &p->regarray_runtime[i];
8800 
8801 		env_free(r->regarray, regarray->size * sizeof(uint64_t));
8802 	}
8803 
8804 	free(p->regarray_runtime);
8805 	p->regarray_runtime = NULL;
8806 }
8807 
8808 static void
8809 regarray_free(struct rte_swx_pipeline *p)
8810 {
8811 	regarray_build_free(p);
8812 
8813 	for ( ; ; ) {
8814 		struct regarray *elem;
8815 
8816 		elem = TAILQ_FIRST(&p->regarrays);
8817 		if (!elem)
8818 			break;
8819 
8820 		TAILQ_REMOVE(&p->regarrays, elem, node);
8821 		free(elem);
8822 	}
8823 }
8824 
8825 /*
8826  * Meter array.
8827  */
8828 static struct meter_profile *
8829 meter_profile_find(struct rte_swx_pipeline *p, const char *name)
8830 {
8831 	struct meter_profile *elem;
8832 
8833 	TAILQ_FOREACH(elem, &p->meter_profiles, node)
8834 		if (!strcmp(elem->name, name))
8835 			return elem;
8836 
8837 	return NULL;
8838 }
8839 
8840 static struct metarray *
8841 metarray_find(struct rte_swx_pipeline *p, const char *name)
8842 {
8843 	struct metarray *elem;
8844 
8845 	TAILQ_FOREACH(elem, &p->metarrays, node)
8846 		if (!strcmp(elem->name, name))
8847 			return elem;
8848 
8849 	return NULL;
8850 }
8851 
8852 static struct metarray *
8853 metarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id)
8854 {
8855 	struct metarray *elem = NULL;
8856 
8857 	TAILQ_FOREACH(elem, &p->metarrays, node)
8858 		if (elem->id == id)
8859 			return elem;
8860 
8861 	return NULL;
8862 }
8863 
8864 int
8865 rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p,
8866 				 const char *name,
8867 				 uint32_t size)
8868 {
8869 	struct metarray *m;
8870 
8871 	CHECK(p, EINVAL);
8872 
8873 	CHECK_NAME(name, EINVAL);
8874 	CHECK(!metarray_find(p, name), EEXIST);
8875 
8876 	CHECK(size, EINVAL);
8877 	size = rte_align32pow2(size);
8878 
8879 	/* Memory allocation. */
8880 	m = calloc(1, sizeof(struct metarray));
8881 	CHECK(m, ENOMEM);
8882 
8883 	/* Node initialization. */
8884 	strcpy(m->name, name);
8885 	m->size = size;
8886 	m->id = p->n_metarrays;
8887 
8888 	/* Node add to tailq. */
8889 	TAILQ_INSERT_TAIL(&p->metarrays, m, node);
8890 	p->n_metarrays++;
8891 
8892 	return 0;
8893 }
8894 
8895 struct meter_profile meter_profile_default = {
8896 	.node = {0},
8897 	.name = "",
8898 	.params = {0},
8899 
8900 	.profile = {
8901 		.cbs = 10000,
8902 		.pbs = 10000,
8903 		.cir_period = 1,
8904 		.cir_bytes_per_period = 1,
8905 		.pir_period = 1,
8906 		.pir_bytes_per_period = 1,
8907 	},
8908 
8909 	.n_users = 0,
8910 };
8911 
8912 static void
8913 meter_init(struct meter *m)
8914 {
8915 	memset(m, 0, sizeof(struct meter));
8916 	rte_meter_trtcm_config(&m->m, &meter_profile_default.profile);
8917 	m->profile = &meter_profile_default;
8918 	m->color_mask = RTE_COLOR_GREEN;
8919 
8920 	meter_profile_default.n_users++;
8921 }
8922 
8923 static int
8924 metarray_build(struct rte_swx_pipeline *p)
8925 {
8926 	struct metarray *m;
8927 
8928 	if (!p->n_metarrays)
8929 		return 0;
8930 
8931 	p->metarray_runtime = calloc(p->n_metarrays, sizeof(struct metarray_runtime));
8932 	CHECK(p->metarray_runtime, ENOMEM);
8933 
8934 	TAILQ_FOREACH(m, &p->metarrays, node) {
8935 		struct metarray_runtime *r = &p->metarray_runtime[m->id];
8936 		uint32_t i;
8937 
8938 		r->metarray = env_malloc(m->size * sizeof(struct meter),
8939 					 RTE_CACHE_LINE_SIZE,
8940 					 p->numa_node);
8941 		CHECK(r->metarray, ENOMEM);
8942 
8943 		for (i = 0; i < m->size; i++)
8944 			meter_init(&r->metarray[i]);
8945 
8946 		r->size_mask = m->size - 1;
8947 	}
8948 
8949 	return 0;
8950 }
8951 
8952 static void
8953 metarray_build_free(struct rte_swx_pipeline *p)
8954 {
8955 	uint32_t i;
8956 
8957 	if (!p->metarray_runtime)
8958 		return;
8959 
8960 	for (i = 0; i < p->n_metarrays; i++) {
8961 		struct metarray *m = metarray_find_by_id(p, i);
8962 		struct metarray_runtime *r = &p->metarray_runtime[i];
8963 
8964 		env_free(r->metarray, m->size * sizeof(struct meter));
8965 	}
8966 
8967 	free(p->metarray_runtime);
8968 	p->metarray_runtime = NULL;
8969 }
8970 
8971 static void
8972 metarray_free(struct rte_swx_pipeline *p)
8973 {
8974 	metarray_build_free(p);
8975 
8976 	/* Meter arrays. */
8977 	for ( ; ; ) {
8978 		struct metarray *elem;
8979 
8980 		elem = TAILQ_FIRST(&p->metarrays);
8981 		if (!elem)
8982 			break;
8983 
8984 		TAILQ_REMOVE(&p->metarrays, elem, node);
8985 		free(elem);
8986 	}
8987 
8988 	/* Meter profiles. */
8989 	for ( ; ; ) {
8990 		struct meter_profile *elem;
8991 
8992 		elem = TAILQ_FIRST(&p->meter_profiles);
8993 		if (!elem)
8994 			break;
8995 
8996 		TAILQ_REMOVE(&p->meter_profiles, elem, node);
8997 		free(elem);
8998 	}
8999 }
9000 
9001 /*
9002  * Pipeline.
9003  */
9004 void
9005 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
9006 {
9007 	void *lib;
9008 
9009 	if (!p)
9010 		return;
9011 
9012 	lib = p->lib;
9013 
9014 	free(p->instruction_data);
9015 	free(p->instructions);
9016 
9017 	metarray_free(p);
9018 	regarray_free(p);
9019 	table_state_free(p);
9020 	learner_free(p);
9021 	selector_free(p);
9022 	table_free(p);
9023 	action_free(p);
9024 	instruction_table_free(p);
9025 	metadata_free(p);
9026 	header_free(p);
9027 	extern_func_free(p);
9028 	extern_obj_free(p);
9029 	port_out_free(p);
9030 	port_in_free(p);
9031 	struct_free(p);
9032 
9033 	free(p);
9034 
9035 	if (lib)
9036 		dlclose(lib);
9037 }
9038 
9039 static int
9040 port_in_types_register(struct rte_swx_pipeline *p)
9041 {
9042 	int status;
9043 
9044 	status = rte_swx_pipeline_port_in_type_register(p,
9045 		"ethdev",
9046 		&rte_swx_port_ethdev_reader_ops);
9047 	if (status)
9048 		return status;
9049 
9050 	status = rte_swx_pipeline_port_in_type_register(p,
9051 		"ring",
9052 		&rte_swx_port_ring_reader_ops);
9053 	if (status)
9054 		return status;
9055 
9056 #ifdef RTE_PORT_PCAP
9057 	status = rte_swx_pipeline_port_in_type_register(p,
9058 		"source",
9059 		&rte_swx_port_source_ops);
9060 	if (status)
9061 		return status;
9062 #endif
9063 
9064 	status = rte_swx_pipeline_port_in_type_register(p,
9065 		"fd",
9066 		&rte_swx_port_fd_reader_ops);
9067 	if (status)
9068 		return status;
9069 
9070 	return 0;
9071 }
9072 
9073 static int
9074 port_out_types_register(struct rte_swx_pipeline *p)
9075 {
9076 	int status;
9077 
9078 	status = rte_swx_pipeline_port_out_type_register(p,
9079 		"ethdev",
9080 		&rte_swx_port_ethdev_writer_ops);
9081 	if (status)
9082 		return status;
9083 
9084 	status = rte_swx_pipeline_port_out_type_register(p,
9085 		"ring",
9086 		&rte_swx_port_ring_writer_ops);
9087 	if (status)
9088 		return status;
9089 
9090 	status = rte_swx_pipeline_port_out_type_register(p,
9091 		"sink",
9092 		&rte_swx_port_sink_ops);
9093 	if (status)
9094 		return status;
9095 
9096 	status = rte_swx_pipeline_port_out_type_register(p,
9097 		"fd",
9098 		&rte_swx_port_fd_writer_ops);
9099 	if (status)
9100 		return status;
9101 
9102 	return 0;
9103 }
9104 
9105 static int
9106 table_types_register(struct rte_swx_pipeline *p)
9107 {
9108 	int status;
9109 
9110 	status = rte_swx_pipeline_table_type_register(p,
9111 		"exact",
9112 		RTE_SWX_TABLE_MATCH_EXACT,
9113 		&rte_swx_table_exact_match_ops);
9114 	if (status)
9115 		return status;
9116 
9117 	status = rte_swx_pipeline_table_type_register(p,
9118 		"wildcard",
9119 		RTE_SWX_TABLE_MATCH_WILDCARD,
9120 		&rte_swx_table_wildcard_match_ops);
9121 	if (status)
9122 		return status;
9123 
9124 	return 0;
9125 }
9126 
9127 int
9128 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
9129 {
9130 	struct rte_swx_pipeline *pipeline = NULL;
9131 	int status = 0;
9132 
9133 	/* Check input parameters. */
9134 	CHECK(p, EINVAL);
9135 
9136 	/* Memory allocation. */
9137 	pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
9138 	if (!pipeline) {
9139 		status = -ENOMEM;
9140 		goto error;
9141 	}
9142 
9143 	/* Initialization. */
9144 	TAILQ_INIT(&pipeline->struct_types);
9145 	TAILQ_INIT(&pipeline->port_in_types);
9146 	TAILQ_INIT(&pipeline->ports_in);
9147 	TAILQ_INIT(&pipeline->port_out_types);
9148 	TAILQ_INIT(&pipeline->ports_out);
9149 	TAILQ_INIT(&pipeline->extern_types);
9150 	TAILQ_INIT(&pipeline->extern_objs);
9151 	TAILQ_INIT(&pipeline->extern_funcs);
9152 	TAILQ_INIT(&pipeline->headers);
9153 	TAILQ_INIT(&pipeline->actions);
9154 	TAILQ_INIT(&pipeline->table_types);
9155 	TAILQ_INIT(&pipeline->tables);
9156 	TAILQ_INIT(&pipeline->selectors);
9157 	TAILQ_INIT(&pipeline->learners);
9158 	TAILQ_INIT(&pipeline->regarrays);
9159 	TAILQ_INIT(&pipeline->meter_profiles);
9160 	TAILQ_INIT(&pipeline->metarrays);
9161 
9162 	pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
9163 	pipeline->numa_node = numa_node;
9164 
9165 	status = port_in_types_register(pipeline);
9166 	if (status)
9167 		goto error;
9168 
9169 	status = port_out_types_register(pipeline);
9170 	if (status)
9171 		goto error;
9172 
9173 	status = table_types_register(pipeline);
9174 	if (status)
9175 		goto error;
9176 
9177 	*p = pipeline;
9178 	return 0;
9179 
9180 error:
9181 	rte_swx_pipeline_free(pipeline);
9182 	return status;
9183 }
9184 
9185 int
9186 rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
9187 				     const char **instructions,
9188 				     uint32_t n_instructions)
9189 {
9190 	int err;
9191 	uint32_t i;
9192 
9193 	err = instruction_config(p, NULL, instructions, n_instructions);
9194 	if (err)
9195 		return err;
9196 
9197 	/* Thread instruction pointer reset. */
9198 	for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
9199 		struct thread *t = &p->threads[i];
9200 
9201 		thread_ip_reset(p, t);
9202 	}
9203 
9204 	return 0;
9205 }
9206 
9207 static int
9208 pipeline_compile(struct rte_swx_pipeline *p);
9209 
9210 int
9211 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
9212 {
9213 	struct rte_swx_port_sink_params drop_port_params = {
9214 		.file_name = NULL,
9215 	};
9216 	int status;
9217 
9218 	CHECK(p, EINVAL);
9219 	CHECK(p->build_done == 0, EEXIST);
9220 
9221 	status = port_in_build(p);
9222 	if (status)
9223 		goto error;
9224 
9225 	/* Drop port. */
9226 	status = rte_swx_pipeline_port_out_config(p,
9227 						  p->n_ports_out,
9228 						  "sink",
9229 						  &drop_port_params);
9230 	if (status)
9231 		goto error;
9232 
9233 	status = port_out_build(p);
9234 	if (status)
9235 		goto error;
9236 
9237 	status = struct_build(p);
9238 	if (status)
9239 		goto error;
9240 
9241 	status = extern_obj_build(p);
9242 	if (status)
9243 		goto error;
9244 
9245 	status = extern_func_build(p);
9246 	if (status)
9247 		goto error;
9248 
9249 	status = header_build(p);
9250 	if (status)
9251 		goto error;
9252 
9253 	status = metadata_build(p);
9254 	if (status)
9255 		goto error;
9256 
9257 	status = instruction_table_build(p);
9258 	if (status)
9259 		goto error;
9260 
9261 	status = action_build(p);
9262 	if (status)
9263 		goto error;
9264 
9265 	status = table_build(p);
9266 	if (status)
9267 		goto error;
9268 
9269 	status = selector_build(p);
9270 	if (status)
9271 		goto error;
9272 
9273 	status = learner_build(p);
9274 	if (status)
9275 		goto error;
9276 
9277 	status = table_state_build(p);
9278 	if (status)
9279 		goto error;
9280 
9281 	status = regarray_build(p);
9282 	if (status)
9283 		goto error;
9284 
9285 	status = metarray_build(p);
9286 	if (status)
9287 		goto error;
9288 
9289 	p->build_done = 1;
9290 
9291 	pipeline_compile(p);
9292 
9293 	return 0;
9294 
9295 error:
9296 	metarray_build_free(p);
9297 	regarray_build_free(p);
9298 	table_state_build_free(p);
9299 	learner_build_free(p);
9300 	selector_build_free(p);
9301 	table_build_free(p);
9302 	action_build_free(p);
9303 	instruction_table_build_free(p);
9304 	metadata_build_free(p);
9305 	header_build_free(p);
9306 	extern_func_build_free(p);
9307 	extern_obj_build_free(p);
9308 	port_out_build_free(p);
9309 	port_in_build_free(p);
9310 	struct_build_free(p);
9311 
9312 	return status;
9313 }
9314 
9315 void
9316 rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions)
9317 {
9318 	uint32_t i;
9319 
9320 	for (i = 0; i < n_instructions; i++)
9321 		instr_exec(p);
9322 }
9323 
9324 void
9325 rte_swx_pipeline_flush(struct rte_swx_pipeline *p)
9326 {
9327 	uint32_t i;
9328 
9329 	for (i = 0; i < p->n_ports_out; i++) {
9330 		struct port_out_runtime *port = &p->out[i];
9331 
9332 		if (port->flush)
9333 			port->flush(port->obj);
9334 	}
9335 }
9336 
9337 /*
9338  * Control.
9339  */
9340 int
9341 rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
9342 			      struct rte_swx_ctl_pipeline_info *pipeline)
9343 {
9344 	struct action *action;
9345 	struct table *table;
9346 	uint32_t n_actions = 0, n_tables = 0;
9347 
9348 	if (!p || !pipeline)
9349 		return -EINVAL;
9350 
9351 	TAILQ_FOREACH(action, &p->actions, node)
9352 		n_actions++;
9353 
9354 	TAILQ_FOREACH(table, &p->tables, node)
9355 		n_tables++;
9356 
9357 	pipeline->n_ports_in = p->n_ports_in;
9358 	pipeline->n_ports_out = p->n_ports_out;
9359 	pipeline->n_actions = n_actions;
9360 	pipeline->n_tables = n_tables;
9361 	pipeline->n_selectors = p->n_selectors;
9362 	pipeline->n_learners = p->n_learners;
9363 	pipeline->n_regarrays = p->n_regarrays;
9364 	pipeline->n_metarrays = p->n_metarrays;
9365 
9366 	return 0;
9367 }
9368 
9369 int
9370 rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node)
9371 {
9372 	if (!p || !numa_node)
9373 		return -EINVAL;
9374 
9375 	*numa_node = p->numa_node;
9376 	return 0;
9377 }
9378 
9379 int
9380 rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p,
9381 			    uint32_t action_id,
9382 			    struct rte_swx_ctl_action_info *action)
9383 {
9384 	struct action *a = NULL;
9385 
9386 	if (!p || (action_id >= p->n_actions) || !action)
9387 		return -EINVAL;
9388 
9389 	a = action_find_by_id(p, action_id);
9390 	if (!a)
9391 		return -EINVAL;
9392 
9393 	strcpy(action->name, a->name);
9394 	action->n_args = a->st ? a->st->n_fields : 0;
9395 	return 0;
9396 }
9397 
9398 int
9399 rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p,
9400 				uint32_t action_id,
9401 				uint32_t action_arg_id,
9402 				struct rte_swx_ctl_action_arg_info *action_arg)
9403 {
9404 	struct action *a = NULL;
9405 	struct field *arg = NULL;
9406 
9407 	if (!p || (action_id >= p->n_actions) || !action_arg)
9408 		return -EINVAL;
9409 
9410 	a = action_find_by_id(p, action_id);
9411 	if (!a || !a->st || (action_arg_id >= a->st->n_fields))
9412 		return -EINVAL;
9413 
9414 	arg = &a->st->fields[action_arg_id];
9415 	strcpy(action_arg->name, arg->name);
9416 	action_arg->n_bits = arg->n_bits;
9417 	action_arg->is_network_byte_order = a->args_endianness[action_arg_id];
9418 
9419 	return 0;
9420 }
9421 
9422 int
9423 rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p,
9424 			   uint32_t table_id,
9425 			   struct rte_swx_ctl_table_info *table)
9426 {
9427 	struct table *t = NULL;
9428 
9429 	if (!p || !table)
9430 		return -EINVAL;
9431 
9432 	t = table_find_by_id(p, table_id);
9433 	if (!t)
9434 		return -EINVAL;
9435 
9436 	strcpy(table->name, t->name);
9437 	strcpy(table->args, t->args);
9438 	table->n_match_fields = t->n_fields;
9439 	table->n_actions = t->n_actions;
9440 	table->default_action_is_const = t->default_action_is_const;
9441 	table->size = t->size;
9442 	return 0;
9443 }
9444 
9445 int
9446 rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p,
9447 	uint32_t table_id,
9448 	uint32_t match_field_id,
9449 	struct rte_swx_ctl_table_match_field_info *match_field)
9450 {
9451 	struct table *t;
9452 	struct match_field *f;
9453 
9454 	if (!p || (table_id >= p->n_tables) || !match_field)
9455 		return -EINVAL;
9456 
9457 	t = table_find_by_id(p, table_id);
9458 	if (!t || (match_field_id >= t->n_fields))
9459 		return -EINVAL;
9460 
9461 	f = &t->fields[match_field_id];
9462 	match_field->match_type = f->match_type;
9463 	match_field->is_header = t->header ? 1 : 0;
9464 	match_field->n_bits = f->field->n_bits;
9465 	match_field->offset = f->field->offset;
9466 
9467 	return 0;
9468 }
9469 
9470 int
9471 rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p,
9472 	uint32_t table_id,
9473 	uint32_t table_action_id,
9474 	struct rte_swx_ctl_table_action_info *table_action)
9475 {
9476 	struct table *t;
9477 
9478 	if (!p || (table_id >= p->n_tables) || !table_action)
9479 		return -EINVAL;
9480 
9481 	t = table_find_by_id(p, table_id);
9482 	if (!t || (table_action_id >= t->n_actions))
9483 		return -EINVAL;
9484 
9485 	table_action->action_id = t->actions[table_action_id]->id;
9486 
9487 	table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id];
9488 	table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id];
9489 
9490 	return 0;
9491 }
9492 
9493 int
9494 rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p,
9495 			  uint32_t table_id,
9496 			  struct rte_swx_table_ops *table_ops,
9497 			  int *is_stub)
9498 {
9499 	struct table *t;
9500 
9501 	if (!p || (table_id >= p->n_tables))
9502 		return -EINVAL;
9503 
9504 	t = table_find_by_id(p, table_id);
9505 	if (!t)
9506 		return -EINVAL;
9507 
9508 	if (t->type) {
9509 		if (table_ops)
9510 			memcpy(table_ops, &t->type->ops, sizeof(*table_ops));
9511 		*is_stub = 0;
9512 	} else {
9513 		*is_stub = 1;
9514 	}
9515 
9516 	return 0;
9517 }
9518 
9519 int
9520 rte_swx_ctl_selector_info_get(struct rte_swx_pipeline *p,
9521 			      uint32_t selector_id,
9522 			      struct rte_swx_ctl_selector_info *selector)
9523 {
9524 	struct selector *s = NULL;
9525 
9526 	if (!p || !selector)
9527 		return -EINVAL;
9528 
9529 	s = selector_find_by_id(p, selector_id);
9530 	if (!s)
9531 		return -EINVAL;
9532 
9533 	strcpy(selector->name, s->name);
9534 
9535 	selector->n_selector_fields = s->n_selector_fields;
9536 	selector->n_groups_max = s->n_groups_max;
9537 	selector->n_members_per_group_max = s->n_members_per_group_max;
9538 
9539 	return 0;
9540 }
9541 
9542 int
9543 rte_swx_ctl_selector_group_id_field_info_get(struct rte_swx_pipeline *p,
9544 	 uint32_t selector_id,
9545 	 struct rte_swx_ctl_table_match_field_info *field)
9546 {
9547 	struct selector *s;
9548 
9549 	if (!p || (selector_id >= p->n_selectors) || !field)
9550 		return -EINVAL;
9551 
9552 	s = selector_find_by_id(p, selector_id);
9553 	if (!s)
9554 		return -EINVAL;
9555 
9556 	field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9557 	field->is_header = 0;
9558 	field->n_bits = s->group_id_field->n_bits;
9559 	field->offset = s->group_id_field->offset;
9560 
9561 	return 0;
9562 }
9563 
9564 int
9565 rte_swx_ctl_selector_field_info_get(struct rte_swx_pipeline *p,
9566 	 uint32_t selector_id,
9567 	 uint32_t selector_field_id,
9568 	 struct rte_swx_ctl_table_match_field_info *field)
9569 {
9570 	struct selector *s;
9571 	struct field *f;
9572 
9573 	if (!p || (selector_id >= p->n_selectors) || !field)
9574 		return -EINVAL;
9575 
9576 	s = selector_find_by_id(p, selector_id);
9577 	if (!s || (selector_field_id >= s->n_selector_fields))
9578 		return -EINVAL;
9579 
9580 	f = s->selector_fields[selector_field_id];
9581 	field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9582 	field->is_header = s->selector_header ? 1 : 0;
9583 	field->n_bits = f->n_bits;
9584 	field->offset = f->offset;
9585 
9586 	return 0;
9587 }
9588 
9589 int
9590 rte_swx_ctl_selector_member_id_field_info_get(struct rte_swx_pipeline *p,
9591 	 uint32_t selector_id,
9592 	 struct rte_swx_ctl_table_match_field_info *field)
9593 {
9594 	struct selector *s;
9595 
9596 	if (!p || (selector_id >= p->n_selectors) || !field)
9597 		return -EINVAL;
9598 
9599 	s = selector_find_by_id(p, selector_id);
9600 	if (!s)
9601 		return -EINVAL;
9602 
9603 	field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9604 	field->is_header = 0;
9605 	field->n_bits = s->member_id_field->n_bits;
9606 	field->offset = s->member_id_field->offset;
9607 
9608 	return 0;
9609 }
9610 
9611 int
9612 rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p,
9613 			     uint32_t learner_id,
9614 			     struct rte_swx_ctl_learner_info *learner)
9615 {
9616 	struct learner *l = NULL;
9617 
9618 	if (!p || !learner)
9619 		return -EINVAL;
9620 
9621 	l = learner_find_by_id(p, learner_id);
9622 	if (!l)
9623 		return -EINVAL;
9624 
9625 	strcpy(learner->name, l->name);
9626 
9627 	learner->n_match_fields = l->n_fields;
9628 	learner->n_actions = l->n_actions;
9629 	learner->default_action_is_const = l->default_action_is_const;
9630 	learner->size = l->size;
9631 
9632 	return 0;
9633 }
9634 
9635 int
9636 rte_swx_ctl_learner_match_field_info_get(struct rte_swx_pipeline *p,
9637 					 uint32_t learner_id,
9638 					 uint32_t match_field_id,
9639 					 struct rte_swx_ctl_table_match_field_info *match_field)
9640 {
9641 	struct learner *l;
9642 	struct field *f;
9643 
9644 	if (!p || (learner_id >= p->n_learners) || !match_field)
9645 		return -EINVAL;
9646 
9647 	l = learner_find_by_id(p, learner_id);
9648 	if (!l || (match_field_id >= l->n_fields))
9649 		return -EINVAL;
9650 
9651 	f = l->fields[match_field_id];
9652 	match_field->match_type = RTE_SWX_TABLE_MATCH_EXACT;
9653 	match_field->is_header = l->header ? 1 : 0;
9654 	match_field->n_bits = f->n_bits;
9655 	match_field->offset = f->offset;
9656 
9657 	return 0;
9658 }
9659 
9660 int
9661 rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p,
9662 				    uint32_t learner_id,
9663 				    uint32_t learner_action_id,
9664 				    struct rte_swx_ctl_table_action_info *learner_action)
9665 {
9666 	struct learner *l;
9667 
9668 	if (!p || (learner_id >= p->n_learners) || !learner_action)
9669 		return -EINVAL;
9670 
9671 	l = learner_find_by_id(p, learner_id);
9672 	if (!l || (learner_action_id >= l->n_actions))
9673 		return -EINVAL;
9674 
9675 	learner_action->action_id = l->actions[learner_action_id]->id;
9676 
9677 	learner_action->action_is_for_table_entries =
9678 		l->action_is_for_table_entries[learner_action_id];
9679 
9680 	learner_action->action_is_for_default_entry =
9681 		l->action_is_for_default_entry[learner_action_id];
9682 
9683 	return 0;
9684 }
9685 
9686 int
9687 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p,
9688 				 struct rte_swx_table_state **table_state)
9689 {
9690 	if (!p || !table_state || !p->build_done)
9691 		return -EINVAL;
9692 
9693 	*table_state = p->table_state;
9694 	return 0;
9695 }
9696 
9697 int
9698 rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
9699 				 struct rte_swx_table_state *table_state)
9700 {
9701 	if (!p || !table_state || !p->build_done)
9702 		return -EINVAL;
9703 
9704 	p->table_state = table_state;
9705 	return 0;
9706 }
9707 
9708 int
9709 rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p,
9710 					uint32_t port_id,
9711 					struct rte_swx_port_in_stats *stats)
9712 {
9713 	struct port_in *port;
9714 
9715 	if (!p || !stats)
9716 		return -EINVAL;
9717 
9718 	port = port_in_find(p, port_id);
9719 	if (!port)
9720 		return -EINVAL;
9721 
9722 	port->type->ops.stats_read(port->obj, stats);
9723 	return 0;
9724 }
9725 
9726 int
9727 rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p,
9728 					 uint32_t port_id,
9729 					 struct rte_swx_port_out_stats *stats)
9730 {
9731 	struct port_out *port;
9732 
9733 	if (!p || !stats)
9734 		return -EINVAL;
9735 
9736 	port = port_out_find(p, port_id);
9737 	if (!port)
9738 		return -EINVAL;
9739 
9740 	port->type->ops.stats_read(port->obj, stats);
9741 	return 0;
9742 }
9743 
9744 int
9745 rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p,
9746 				      const char *table_name,
9747 				      struct rte_swx_table_stats *stats)
9748 {
9749 	struct table *table;
9750 	struct table_statistics *table_stats;
9751 
9752 	if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action)
9753 		return -EINVAL;
9754 
9755 	table = table_find(p, table_name);
9756 	if (!table)
9757 		return -EINVAL;
9758 
9759 	table_stats = &p->table_stats[table->id];
9760 
9761 	memcpy(stats->n_pkts_action,
9762 	       table_stats->n_pkts_action,
9763 	       p->n_actions * sizeof(uint64_t));
9764 
9765 	stats->n_pkts_hit = table_stats->n_pkts_hit[1];
9766 	stats->n_pkts_miss = table_stats->n_pkts_hit[0];
9767 
9768 	return 0;
9769 }
9770 
9771 int
9772 rte_swx_ctl_pipeline_selector_stats_read(struct rte_swx_pipeline *p,
9773 	const char *selector_name,
9774 	struct rte_swx_pipeline_selector_stats *stats)
9775 {
9776 	struct selector *s;
9777 
9778 	if (!p || !selector_name || !selector_name[0] || !stats)
9779 		return -EINVAL;
9780 
9781 	s = selector_find(p, selector_name);
9782 	if (!s)
9783 		return -EINVAL;
9784 
9785 	stats->n_pkts = p->selector_stats[s->id].n_pkts;
9786 
9787 	return 0;
9788 }
9789 
9790 int
9791 rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p,
9792 					const char *learner_name,
9793 					struct rte_swx_learner_stats *stats)
9794 {
9795 	struct learner *l;
9796 	struct learner_statistics *learner_stats;
9797 
9798 	if (!p || !learner_name || !learner_name[0] || !stats || !stats->n_pkts_action)
9799 		return -EINVAL;
9800 
9801 	l = learner_find(p, learner_name);
9802 	if (!l)
9803 		return -EINVAL;
9804 
9805 	learner_stats = &p->learner_stats[l->id];
9806 
9807 	memcpy(stats->n_pkts_action,
9808 	       learner_stats->n_pkts_action,
9809 	       p->n_actions * sizeof(uint64_t));
9810 
9811 	stats->n_pkts_hit = learner_stats->n_pkts_hit[1];
9812 	stats->n_pkts_miss = learner_stats->n_pkts_hit[0];
9813 
9814 	stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0];
9815 	stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1];
9816 
9817 	stats->n_pkts_forget = learner_stats->n_pkts_forget;
9818 
9819 	return 0;
9820 }
9821 
9822 int
9823 rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,
9824 			      uint32_t regarray_id,
9825 			      struct rte_swx_ctl_regarray_info *regarray)
9826 {
9827 	struct regarray *r;
9828 
9829 	if (!p || !regarray)
9830 		return -EINVAL;
9831 
9832 	r = regarray_find_by_id(p, regarray_id);
9833 	if (!r)
9834 		return -EINVAL;
9835 
9836 	strcpy(regarray->name, r->name);
9837 	regarray->size = r->size;
9838 	return 0;
9839 }
9840 
9841 int
9842 rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p,
9843 				   const char *regarray_name,
9844 				   uint32_t regarray_index,
9845 				   uint64_t *value)
9846 {
9847 	struct regarray *regarray;
9848 	struct regarray_runtime *r;
9849 
9850 	if (!p || !regarray_name || !value)
9851 		return -EINVAL;
9852 
9853 	regarray = regarray_find(p, regarray_name);
9854 	if (!regarray || (regarray_index >= regarray->size))
9855 		return -EINVAL;
9856 
9857 	r = &p->regarray_runtime[regarray->id];
9858 	*value = r->regarray[regarray_index];
9859 	return 0;
9860 }
9861 
9862 int
9863 rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,
9864 				   const char *regarray_name,
9865 				   uint32_t regarray_index,
9866 				   uint64_t value)
9867 {
9868 	struct regarray *regarray;
9869 	struct regarray_runtime *r;
9870 
9871 	if (!p || !regarray_name)
9872 		return -EINVAL;
9873 
9874 	regarray = regarray_find(p, regarray_name);
9875 	if (!regarray || (regarray_index >= regarray->size))
9876 		return -EINVAL;
9877 
9878 	r = &p->regarray_runtime[regarray->id];
9879 	r->regarray[regarray_index] = value;
9880 	return 0;
9881 }
9882 
9883 int
9884 rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p,
9885 			      uint32_t metarray_id,
9886 			      struct rte_swx_ctl_metarray_info *metarray)
9887 {
9888 	struct metarray *m;
9889 
9890 	if (!p || !metarray)
9891 		return -EINVAL;
9892 
9893 	m = metarray_find_by_id(p, metarray_id);
9894 	if (!m)
9895 		return -EINVAL;
9896 
9897 	strcpy(metarray->name, m->name);
9898 	metarray->size = m->size;
9899 	return 0;
9900 }
9901 
9902 int
9903 rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p,
9904 			      const char *name,
9905 			      struct rte_meter_trtcm_params *params)
9906 {
9907 	struct meter_profile *mp;
9908 	int status;
9909 
9910 	CHECK(p, EINVAL);
9911 	CHECK_NAME(name, EINVAL);
9912 	CHECK(params, EINVAL);
9913 	CHECK(!meter_profile_find(p, name), EEXIST);
9914 
9915 	/* Node allocation. */
9916 	mp = calloc(1, sizeof(struct meter_profile));
9917 	CHECK(mp, ENOMEM);
9918 
9919 	/* Node initialization. */
9920 	strcpy(mp->name, name);
9921 	memcpy(&mp->params, params, sizeof(struct rte_meter_trtcm_params));
9922 	status = rte_meter_trtcm_profile_config(&mp->profile, params);
9923 	if (status) {
9924 		free(mp);
9925 		CHECK(0, EINVAL);
9926 	}
9927 
9928 	/* Node add to tailq. */
9929 	TAILQ_INSERT_TAIL(&p->meter_profiles, mp, node);
9930 
9931 	return 0;
9932 }
9933 
9934 int
9935 rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p,
9936 				 const char *name)
9937 {
9938 	struct meter_profile *mp;
9939 
9940 	CHECK(p, EINVAL);
9941 	CHECK_NAME(name, EINVAL);
9942 
9943 	mp = meter_profile_find(p, name);
9944 	CHECK(mp, EINVAL);
9945 	CHECK(!mp->n_users, EBUSY);
9946 
9947 	/* Remove node from tailq. */
9948 	TAILQ_REMOVE(&p->meter_profiles, mp, node);
9949 	free(mp);
9950 
9951 	return 0;
9952 }
9953 
9954 int
9955 rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p,
9956 			const char *metarray_name,
9957 			uint32_t metarray_index)
9958 {
9959 	struct meter_profile *mp_old;
9960 	struct metarray *metarray;
9961 	struct metarray_runtime *metarray_runtime;
9962 	struct meter *m;
9963 
9964 	CHECK(p, EINVAL);
9965 	CHECK_NAME(metarray_name, EINVAL);
9966 
9967 	metarray = metarray_find(p, metarray_name);
9968 	CHECK(metarray, EINVAL);
9969 	CHECK(metarray_index < metarray->size, EINVAL);
9970 
9971 	metarray_runtime = &p->metarray_runtime[metarray->id];
9972 	m = &metarray_runtime->metarray[metarray_index];
9973 	mp_old = m->profile;
9974 
9975 	meter_init(m);
9976 
9977 	mp_old->n_users--;
9978 
9979 	return 0;
9980 }
9981 
9982 int
9983 rte_swx_ctl_meter_set(struct rte_swx_pipeline *p,
9984 		      const char *metarray_name,
9985 		      uint32_t metarray_index,
9986 		      const char *profile_name)
9987 {
9988 	struct meter_profile *mp, *mp_old;
9989 	struct metarray *metarray;
9990 	struct metarray_runtime *metarray_runtime;
9991 	struct meter *m;
9992 
9993 	CHECK(p, EINVAL);
9994 	CHECK_NAME(metarray_name, EINVAL);
9995 
9996 	metarray = metarray_find(p, metarray_name);
9997 	CHECK(metarray, EINVAL);
9998 	CHECK(metarray_index < metarray->size, EINVAL);
9999 
10000 	mp = meter_profile_find(p, profile_name);
10001 	CHECK(mp, EINVAL);
10002 
10003 	metarray_runtime = &p->metarray_runtime[metarray->id];
10004 	m = &metarray_runtime->metarray[metarray_index];
10005 	mp_old = m->profile;
10006 
10007 	memset(m, 0, sizeof(struct meter));
10008 	rte_meter_trtcm_config(&m->m, &mp->profile);
10009 	m->profile = mp;
10010 	m->color_mask = RTE_COLORS;
10011 
10012 	mp->n_users++;
10013 	mp_old->n_users--;
10014 
10015 	return 0;
10016 }
10017 
10018 int
10019 rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p,
10020 			     const char *metarray_name,
10021 			     uint32_t metarray_index,
10022 			     struct rte_swx_ctl_meter_stats *stats)
10023 {
10024 	struct metarray *metarray;
10025 	struct metarray_runtime *metarray_runtime;
10026 	struct meter *m;
10027 
10028 	CHECK(p, EINVAL);
10029 	CHECK_NAME(metarray_name, EINVAL);
10030 
10031 	metarray = metarray_find(p, metarray_name);
10032 	CHECK(metarray, EINVAL);
10033 	CHECK(metarray_index < metarray->size, EINVAL);
10034 
10035 	CHECK(stats, EINVAL);
10036 
10037 	metarray_runtime = &p->metarray_runtime[metarray->id];
10038 	m = &metarray_runtime->metarray[metarray_index];
10039 
10040 	memcpy(stats->n_pkts, m->n_pkts, sizeof(m->n_pkts));
10041 	memcpy(stats->n_bytes, m->n_bytes, sizeof(m->n_bytes));
10042 
10043 	return 0;
10044 }
10045 
10046 /*
10047  * Pipeline compilation.
10048  */
10049 static const char *
10050 instr_type_to_name(struct instruction *instr)
10051 {
10052 	switch (instr->type) {
10053 	case INSTR_RX: return "INSTR_RX";
10054 
10055 	case INSTR_TX: return "INSTR_TX";
10056 	case INSTR_TX_I: return "INSTR_TX_I";
10057 	case INSTR_DROP: return "INSTR_DROP";
10058 
10059 	case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT";
10060 	case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2";
10061 	case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3";
10062 	case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4";
10063 	case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5";
10064 	case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6";
10065 	case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7";
10066 	case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8";
10067 
10068 	case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M";
10069 
10070 	case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD";
10071 
10072 	case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT";
10073 	case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX";
10074 	case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX";
10075 	case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX";
10076 	case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX";
10077 	case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX";
10078 	case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX";
10079 	case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX";
10080 	case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX";
10081 
10082 	case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE";
10083 	case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE";
10084 
10085 	case INSTR_MOV: return "INSTR_MOV";
10086 	case INSTR_MOV_MH: return "INSTR_MOV_MH";
10087 	case INSTR_MOV_HM: return "INSTR_MOV_HM";
10088 	case INSTR_MOV_HH: return "INSTR_MOV_HH";
10089 	case INSTR_MOV_I: return "INSTR_MOV_I";
10090 
10091 	case INSTR_DMA_HT: return "INSTR_DMA_HT";
10092 	case INSTR_DMA_HT2: return "INSTR_DMA_HT2";
10093 	case INSTR_DMA_HT3: return "INSTR_DMA_HT3";
10094 	case INSTR_DMA_HT4: return "INSTR_DMA_HT4";
10095 	case INSTR_DMA_HT5: return "INSTR_DMA_HT5";
10096 	case INSTR_DMA_HT6: return "INSTR_DMA_HT6";
10097 	case INSTR_DMA_HT7: return "INSTR_DMA_HT7";
10098 	case INSTR_DMA_HT8: return "INSTR_DMA_HT8";
10099 
10100 	case INSTR_ALU_ADD: return "INSTR_ALU_ADD";
10101 	case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH";
10102 	case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM";
10103 	case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH";
10104 	case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI";
10105 	case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI";
10106 
10107 	case INSTR_ALU_SUB: return "INSTR_ALU_SUB";
10108 	case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH";
10109 	case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM";
10110 	case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH";
10111 	case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI";
10112 	case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI";
10113 
10114 	case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD";
10115 	case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20";
10116 	case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT";
10117 	case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD";
10118 
10119 	case INSTR_ALU_AND: return "INSTR_ALU_AND";
10120 	case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH";
10121 	case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM";
10122 	case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH";
10123 	case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I";
10124 
10125 	case INSTR_ALU_OR: return "INSTR_ALU_OR";
10126 	case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH";
10127 	case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM";
10128 	case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH";
10129 	case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I";
10130 
10131 	case INSTR_ALU_XOR: return "INSTR_ALU_XOR";
10132 	case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH";
10133 	case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM";
10134 	case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH";
10135 	case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I";
10136 
10137 	case INSTR_ALU_SHL: return "INSTR_ALU_SHL";
10138 	case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH";
10139 	case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM";
10140 	case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH";
10141 	case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI";
10142 	case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI";
10143 
10144 	case INSTR_ALU_SHR: return "INSTR_ALU_SHR";
10145 	case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH";
10146 	case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM";
10147 	case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH";
10148 	case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI";
10149 	case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI";
10150 
10151 	case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH";
10152 	case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM";
10153 	case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI";
10154 
10155 	case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH";
10156 	case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM";
10157 	case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI";
10158 	case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH";
10159 	case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM";
10160 	case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI";
10161 
10162 	case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH";
10163 	case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM";
10164 	case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI";
10165 	case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH";
10166 	case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM";
10167 	case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI";
10168 	case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH";
10169 	case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM";
10170 	case INSTR_REGWR_RII: return "INSTR_REGWR_RII";
10171 
10172 	case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH";
10173 	case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM";
10174 	case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI";
10175 	case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH";
10176 	case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM";
10177 	case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI";
10178 	case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH";
10179 	case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM";
10180 	case INSTR_REGADD_RII: return "INSTR_REGADD_RII";
10181 
10182 	case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H";
10183 	case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M";
10184 	case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I";
10185 
10186 	case INSTR_METER_HHM: return "INSTR_METER_HHM";
10187 	case INSTR_METER_HHI: return "INSTR_METER_HHI";
10188 	case INSTR_METER_HMM: return "INSTR_METER_HMM";
10189 	case INSTR_METER_HMI: return "INSTR_METER_HMI";
10190 	case INSTR_METER_MHM: return "INSTR_METER_MHM";
10191 	case INSTR_METER_MHI: return "INSTR_METER_MHI";
10192 	case INSTR_METER_MMM: return "INSTR_METER_MMM";
10193 	case INSTR_METER_MMI: return "INSTR_METER_MMI";
10194 	case INSTR_METER_IHM: return "INSTR_METER_IHM";
10195 	case INSTR_METER_IHI: return "INSTR_METER_IHI";
10196 	case INSTR_METER_IMM: return "INSTR_METER_IMM";
10197 	case INSTR_METER_IMI: return "INSTR_METER_IMI";
10198 
10199 	case INSTR_TABLE: return "INSTR_TABLE";
10200 	case INSTR_TABLE_AF: return "INSTR_TABLE_AF";
10201 	case INSTR_SELECTOR: return "INSTR_SELECTOR";
10202 	case INSTR_LEARNER: return "INSTR_LEARNER";
10203 	case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF";
10204 
10205 	case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN";
10206 	case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET";
10207 
10208 	case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ";
10209 	case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC";
10210 
10211 	case INSTR_JMP: return "INSTR_JMP";
10212 	case INSTR_JMP_VALID: return "INSTR_JMP_VALID";
10213 	case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID";
10214 	case INSTR_JMP_HIT: return "INSTR_JMP_HIT";
10215 	case INSTR_JMP_MISS: return "INSTR_JMP_MISS";
10216 	case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT";
10217 	case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS";
10218 	case INSTR_JMP_EQ: return "INSTR_JMP_EQ";
10219 	case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH";
10220 	case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM";
10221 	case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH";
10222 	case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I";
10223 	case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ";
10224 	case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH";
10225 	case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM";
10226 	case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH";
10227 	case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I";
10228 	case INSTR_JMP_LT: return "INSTR_JMP_LT";
10229 	case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH";
10230 	case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM";
10231 	case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH";
10232 	case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI";
10233 	case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI";
10234 	case INSTR_JMP_GT: return "INSTR_JMP_GT";
10235 	case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH";
10236 	case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM";
10237 	case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH";
10238 	case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI";
10239 	case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI";
10240 
10241 	case INSTR_RETURN: return "INSTR_RETURN";
10242 
10243 	default: return "INSTR_UNKNOWN";
10244 	}
10245 }
10246 
10247 typedef void
10248 (*instruction_export_t)(struct instruction *, FILE *);
10249 
10250 static void
10251 instr_io_export(struct instruction *instr, FILE *f)
10252 {
10253 	uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i;
10254 
10255 	/* n_io, n_io_imm, n_hdrs. */
10256 	if (instr->type == INSTR_RX ||
10257 	    instr->type == INSTR_TX ||
10258 	    instr->type == INSTR_HDR_EXTRACT_M ||
10259 	    (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX))
10260 		n_io = 1;
10261 
10262 	if (instr->type == INSTR_TX_I)
10263 		n_io_imm = 1;
10264 
10265 	if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8)
10266 		n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT);
10267 
10268 	if (instr->type == INSTR_HDR_EXTRACT_M ||
10269 	    instr->type == INSTR_HDR_LOOKAHEAD ||
10270 	    instr->type == INSTR_HDR_EMIT)
10271 		n_hdrs = 1;
10272 
10273 	if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)
10274 		n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX);
10275 
10276 	/* instr. */
10277 	fprintf(f,
10278 		"\t{\n"
10279 		"\t\t.type = %s,\n",
10280 		instr_type_to_name(instr));
10281 
10282 	/* instr.io. */
10283 	if (n_io || n_io_imm || n_hdrs)
10284 		fprintf(f,
10285 			"\t\t.io = {\n");
10286 
10287 	/* instr.io.io. */
10288 	if (n_io)
10289 		fprintf(f,
10290 			"\t\t\t.io = {\n"
10291 			"\t\t\t\t.offset = %u,\n"
10292 			"\t\t\t\t.n_bits = %u,\n"
10293 			"\t\t\t},\n",
10294 			instr->io.io.offset,
10295 			instr->io.io.n_bits);
10296 
10297 	if (n_io_imm)
10298 		fprintf(f,
10299 			"\t\t\t.io = {\n"
10300 			"\t\t\t\t.val = %u,\n"
10301 			"\t\t\t},\n",
10302 			instr->io.io.val);
10303 
10304 	/* instr.io.hdr. */
10305 	if (n_hdrs) {
10306 		fprintf(f,
10307 			"\t\t.hdr = {\n");
10308 
10309 		/* instr.io.hdr.header_id. */
10310 		fprintf(f,
10311 			"\t\t\t.header_id = {");
10312 
10313 		for (i = 0; i < n_hdrs; i++)
10314 			fprintf(f,
10315 				"%u, ",
10316 				instr->io.hdr.header_id[i]);
10317 
10318 		fprintf(f,
10319 			"},\n");
10320 
10321 		/* instr.io.hdr.struct_id. */
10322 		fprintf(f,
10323 			"\t\t\t.struct_id = {");
10324 
10325 		for (i = 0; i < n_hdrs; i++)
10326 			fprintf(f,
10327 				"%u, ",
10328 				instr->io.hdr.struct_id[i]);
10329 
10330 		fprintf(f,
10331 			"},\n");
10332 
10333 		/* instr.io.hdr.n_bytes. */
10334 		fprintf(f,
10335 			"\t\t\t.n_bytes = {");
10336 
10337 		for (i = 0; i < n_hdrs; i++)
10338 			fprintf(f,
10339 				"%u, ",
10340 				instr->io.hdr.n_bytes[i]);
10341 
10342 		fprintf(f,
10343 			"},\n");
10344 
10345 		/* instr.io.hdr - closing curly brace. */
10346 		fprintf(f,
10347 			"\t\t\t}\n,");
10348 	}
10349 
10350 	/* instr.io - closing curly brace. */
10351 	if (n_io || n_io_imm || n_hdrs)
10352 		fprintf(f,
10353 			"\t\t},\n");
10354 
10355 	/* instr - closing curly brace. */
10356 	fprintf(f,
10357 		"\t},\n");
10358 }
10359 
10360 static void
10361 instr_hdr_validate_export(struct instruction *instr, FILE *f)
10362 {
10363 	fprintf(f,
10364 		"\t{\n"
10365 		"\t\t.type = %s,\n"
10366 		"\t\t.valid = {\n"
10367 		"\t\t\t.header_id = %u,\n"
10368 		"\t\t},\n"
10369 		"\t},\n",
10370 		instr_type_to_name(instr),
10371 		instr->valid.header_id);
10372 }
10373 
10374 static void
10375 instr_mov_export(struct instruction *instr, FILE *f)
10376 {
10377 	if (instr->type != INSTR_MOV_I)
10378 		fprintf(f,
10379 			"\t{\n"
10380 			"\t\t.type = %s,\n"
10381 			"\t\t.mov = {\n"
10382 			"\t\t\t.dst = {\n"
10383 			"\t\t\t\t.struct_id = %u,\n"
10384 			"\t\t\t\t.n_bits = %u,\n"
10385 			"\t\t\t\t.offset = %u,\n"
10386 			"\t\t\t},\n"
10387 			"\t\t\t.src = {\n"
10388 			"\t\t\t\t.struct_id = %u,\n"
10389 			"\t\t\t\t.n_bits = %u,\n"
10390 			"\t\t\t\t.offset = %u,\n"
10391 			"\t\t\t},\n"
10392 			"\t\t},\n"
10393 			"\t},\n",
10394 			instr_type_to_name(instr),
10395 			instr->mov.dst.struct_id,
10396 			instr->mov.dst.n_bits,
10397 			instr->mov.dst.offset,
10398 			instr->mov.src.struct_id,
10399 			instr->mov.src.n_bits,
10400 			instr->mov.src.offset);
10401 	else
10402 		fprintf(f,
10403 			"\t{\n"
10404 			"\t\t.type = %s,\n"
10405 			"\t\t.mov = {\n"
10406 			"\t\t\t.dst = {\n"
10407 			"\t\t\t\t.struct_id = %u,\n"
10408 			"\t\t\t\t.n_bits = %u,\n"
10409 			"\t\t\t\t.offset = %u,\n"
10410 			"\t\t\t}\n,"
10411 			"\t\t\t.src_val = %" PRIu64 ",\n"
10412 			"\t\t},\n"
10413 			"\t},\n",
10414 			instr_type_to_name(instr),
10415 			instr->mov.dst.struct_id,
10416 			instr->mov.dst.n_bits,
10417 			instr->mov.dst.offset,
10418 			instr->mov.src_val);
10419 }
10420 
10421 static void
10422 instr_dma_ht_export(struct instruction *instr, FILE *f)
10423 {
10424 	uint32_t n_dma = 0, i;
10425 
10426 	/* n_dma. */
10427 	n_dma = 1 + (instr->type - INSTR_DMA_HT);
10428 
10429 	/* instr. */
10430 	fprintf(f,
10431 		"\t{\n"
10432 		"\t\t.type = %s,\n",
10433 		instr_type_to_name(instr));
10434 
10435 	/* instr.dma. */
10436 	fprintf(f,
10437 		"\t\t.dma = {\n");
10438 
10439 	/* instr.dma.dst. */
10440 	fprintf(f,
10441 		"\t\t\t.dst = {\n");
10442 
10443 	/* instr.dma.dst.header_id. */
10444 	fprintf(f,
10445 		"\t\t\t\t.header_id = {");
10446 
10447 	for (i = 0; i < n_dma; i++)
10448 		fprintf(f,
10449 			"%u, ",
10450 			instr->dma.dst.header_id[i]);
10451 
10452 	fprintf(f,
10453 		"},\n");
10454 
10455 	/* instr.dma.dst.struct_id. */
10456 	fprintf(f,
10457 		"\t\t\t\t.struct_id = {");
10458 
10459 	for (i = 0; i < n_dma; i++)
10460 		fprintf(f,
10461 			"%u, ",
10462 			instr->dma.dst.struct_id[i]);
10463 
10464 	fprintf(f,
10465 		"},\n");
10466 
10467 	/* instr.dma.dst - closing curly brace. */
10468 	fprintf(f,
10469 		"\t\t\t},\n");
10470 
10471 	/* instr.dma.src. */
10472 	fprintf(f,
10473 		"\t\t\t.src = {\n");
10474 
10475 	/* instr.dma.src.offset. */
10476 	fprintf(f,
10477 		"\t\t\t\t.offset = {");
10478 
10479 	for (i = 0; i < n_dma; i++)
10480 		fprintf(f,
10481 			"%u, ",
10482 			instr->dma.src.offset[i]);
10483 
10484 	fprintf(f,
10485 		"},\n");
10486 
10487 	/* instr.dma.src - closing curly brace. */
10488 	fprintf(f,
10489 		"\t\t\t},\n");
10490 
10491 	/* instr.dma.n_bytes. */
10492 	fprintf(f,
10493 		"\t\t\t.n_bytes = {");
10494 
10495 	for (i = 0; i < n_dma; i++)
10496 		fprintf(f,
10497 			"%u, ",
10498 			instr->dma.n_bytes[i]);
10499 
10500 	fprintf(f,
10501 		"},\n");
10502 
10503 	/* instr.dma - closing curly brace. */
10504 	fprintf(f,
10505 		"\t\t},\n");
10506 
10507 	/* instr - closing curly brace. */
10508 	fprintf(f,
10509 		"\t},\n");
10510 }
10511 
10512 static void
10513 instr_alu_export(struct instruction *instr, FILE *f)
10514 {
10515 	int imm = 0;
10516 
10517 	if (instr->type == INSTR_ALU_ADD_MI ||
10518 	    instr->type == INSTR_ALU_ADD_HI ||
10519 	    instr->type == INSTR_ALU_SUB_MI ||
10520 	    instr->type == INSTR_ALU_SUB_HI ||
10521 	    instr->type == INSTR_ALU_SHL_MI ||
10522 	    instr->type == INSTR_ALU_SHL_HI ||
10523 	    instr->type == INSTR_ALU_SHR_MI ||
10524 	    instr->type == INSTR_ALU_SHR_HI ||
10525 	    instr->type == INSTR_ALU_AND_I ||
10526 	    instr->type == INSTR_ALU_OR_I ||
10527 	    instr->type == INSTR_ALU_XOR_I)
10528 		imm = 1;
10529 
10530 	if (!imm)
10531 		fprintf(f,
10532 			"\t{\n"
10533 			"\t\t.type = %s,\n"
10534 			"\t\t.alu = {\n"
10535 			"\t\t\t.dst = {\n"
10536 			"\t\t\t\t.struct_id = %u,\n"
10537 			"\t\t\t\t.n_bits = %u,\n"
10538 			"\t\t\t\t.offset = %u,\n"
10539 			"\t\t\t},\n"
10540 			"\t\t\t.src = {\n"
10541 			"\t\t\t\t.struct_id = %u,\n"
10542 			"\t\t\t\t.n_bits = %u,\n"
10543 			"\t\t\t\t.offset = %u,\n"
10544 			"\t\t\t},\n"
10545 			"\t\t},\n"
10546 			"\t},\n",
10547 			instr_type_to_name(instr),
10548 			instr->alu.dst.struct_id,
10549 			instr->alu.dst.n_bits,
10550 			instr->alu.dst.offset,
10551 			instr->alu.src.struct_id,
10552 			instr->alu.src.n_bits,
10553 			instr->alu.src.offset);
10554 	else
10555 		fprintf(f,
10556 			"\t{\n"
10557 			"\t\t.type = %s,\n"
10558 			"\t\t.alu = {\n"
10559 			"\t\t\t.dst = {\n"
10560 			"\t\t\t\t.struct_id = %u,\n"
10561 			"\t\t\t\t.n_bits = %u,\n"
10562 			"\t\t\t\t.offset = %u,\n"
10563 			"\t\t\t}\n,"
10564 			"\t\t\t.src_val = %" PRIu64 ",\n"
10565 			"\t\t},\n"
10566 			"\t},\n",
10567 			instr_type_to_name(instr),
10568 			instr->alu.dst.struct_id,
10569 			instr->alu.dst.n_bits,
10570 			instr->alu.dst.offset,
10571 			instr->alu.src_val);
10572 }
10573 
10574 static void
10575 instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused)
10576 {
10577 	int prefetch  = 0, idx_imm = 0, src_imm = 0;
10578 
10579 	if (instr->type == INSTR_REGPREFETCH_RH ||
10580 	    instr->type == INSTR_REGPREFETCH_RM ||
10581 	    instr->type == INSTR_REGPREFETCH_RI)
10582 		prefetch = 1;
10583 
10584 	/* index is the 3rd operand for the regrd instruction and the 2nd
10585 	 * operand for the regwr and regadd instructions.
10586 	 */
10587 	if (instr->type == INSTR_REGPREFETCH_RI ||
10588 	    instr->type == INSTR_REGRD_HRI ||
10589 	    instr->type == INSTR_REGRD_MRI ||
10590 	    instr->type == INSTR_REGWR_RIH ||
10591 	    instr->type == INSTR_REGWR_RIM ||
10592 	    instr->type == INSTR_REGWR_RII ||
10593 	    instr->type == INSTR_REGADD_RIH ||
10594 	    instr->type == INSTR_REGADD_RIM ||
10595 	    instr->type == INSTR_REGADD_RII)
10596 		idx_imm = 1;
10597 
10598 	/* src is the 3rd operand for the regwr and regadd instructions. */
10599 	if (instr->type == INSTR_REGWR_RHI ||
10600 	    instr->type == INSTR_REGWR_RMI ||
10601 	    instr->type == INSTR_REGWR_RII ||
10602 	    instr->type == INSTR_REGADD_RHI ||
10603 	    instr->type == INSTR_REGADD_RMI ||
10604 	    instr->type == INSTR_REGADD_RII)
10605 		src_imm = 1;
10606 
10607 	/* instr.regarray.regarray_id. */
10608 	fprintf(f,
10609 		"\t{\n"
10610 		"\t\t.type = %s,\n"
10611 		"\t\t.regarray = {\n"
10612 		"\t\t\t.regarray_id = %u,\n",
10613 		instr_type_to_name(instr),
10614 		instr->regarray.regarray_id);
10615 
10616 	/* instr.regarray.idx / instr.regarray.idx_val. */
10617 	if (!idx_imm)
10618 		fprintf(f,
10619 			"\t\t\t\t.idx = {\n"
10620 			"\t\t\t\t\t.struct_id = %u,\n"
10621 			"\t\t\t\t\t.n_bits = %u,\n"
10622 			"\t\t\t\t\t.offset = %u,\n"
10623 			"\t\t\t\t},\n",
10624 			instr->regarray.idx.struct_id,
10625 			instr->regarray.idx.n_bits,
10626 			instr->regarray.idx.offset);
10627 	else
10628 		fprintf(f,
10629 			"\t\t\t\t.idx_val = %u,\n",
10630 			instr->regarray.idx_val);
10631 
10632 	/* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */
10633 	if (!prefetch) {
10634 		if (!src_imm)
10635 			fprintf(f,
10636 				"\t\t\t\t.dstsrc = {\n"
10637 				"\t\t\t\t\t.struct_id = %u,\n"
10638 				"\t\t\t\t\t.n_bits = %u,\n"
10639 				"\t\t\t\t\t.offset = %u,\n"
10640 				"\t\t\t\t},\n",
10641 				instr->regarray.dstsrc.struct_id,
10642 				instr->regarray.dstsrc.n_bits,
10643 				instr->regarray.dstsrc.offset);
10644 		else
10645 			fprintf(f,
10646 				"\t\t\t\t.dstsrc_val = %" PRIu64 ",\n",
10647 				instr->regarray.dstsrc_val);
10648 	}
10649 
10650 	/* instr.regarray and instr - closing curly braces. */
10651 	fprintf(f,
10652 		"\t\t},\n"
10653 		"\t},\n");
10654 }
10655 
10656 static void
10657 instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused)
10658 {
10659 	int prefetch  = 0, idx_imm = 0, color_in_imm = 0;
10660 
10661 	if (instr->type == INSTR_METPREFETCH_H ||
10662 	    instr->type == INSTR_METPREFETCH_M ||
10663 	    instr->type == INSTR_METPREFETCH_I)
10664 		prefetch = 1;
10665 
10666 	/* idx_imm. */
10667 	if (instr->type == INSTR_METPREFETCH_I ||
10668 	    instr->type == INSTR_METER_IHM ||
10669 	    instr->type == INSTR_METER_IHI ||
10670 	    instr->type == INSTR_METER_IMM ||
10671 	    instr->type == INSTR_METER_IMI)
10672 		idx_imm = 1;
10673 
10674 	/* color_in_imm. */
10675 	if (instr->type == INSTR_METER_HHI ||
10676 	    instr->type == INSTR_METER_HMI ||
10677 	    instr->type == INSTR_METER_MHI ||
10678 	    instr->type == INSTR_METER_MMI ||
10679 	    instr->type == INSTR_METER_IHI ||
10680 	    instr->type == INSTR_METER_IMI)
10681 		color_in_imm = 1;
10682 
10683 	/* instr.meter.metarray_id. */
10684 	fprintf(f,
10685 		"\t{\n"
10686 		"\t\t.type = %s,\n"
10687 		"\t\t.meter = {\n"
10688 		"\t\t\t.metarray_id = %u,\n",
10689 		instr_type_to_name(instr),
10690 		instr->meter.metarray_id);
10691 
10692 	/* instr.meter.idx / instr.meter.idx_val. */
10693 	if (!idx_imm)
10694 		fprintf(f,
10695 			"\t\t\t.idx = {\n"
10696 			"\t\t\t\t.struct_id = %u,\n"
10697 			"\t\t\t\t.n_bits = %u,\n"
10698 			"\t\t\t\t.offset = %u,\n"
10699 			"\t\t\t},\n",
10700 			instr->meter.idx.struct_id,
10701 			instr->meter.idx.n_bits,
10702 			instr->meter.idx.offset);
10703 	else
10704 		fprintf(f,
10705 			"\t\t\t.idx_val = %u,\n",
10706 			instr->meter.idx_val);
10707 
10708 	if (!prefetch) {
10709 		/* instr.meter.length. */
10710 		fprintf(f,
10711 			"\t\t\t.length = {\n"
10712 			"\t\t\t\t.struct_id = %u,\n"
10713 			"\t\t\t\t.n_bits = %u,\n"
10714 			"\t\t\t\t.offset = %u,\n"
10715 			"\t\t\t},\n",
10716 			instr->meter.length.struct_id,
10717 			instr->meter.length.n_bits,
10718 			instr->meter.length.offset);
10719 
10720 		/* instr.meter.color_in / instr.meter.color_in_val. */
10721 		if (!color_in_imm)
10722 			fprintf(f,
10723 				"\t\t\t.color_in = {\n"
10724 				"\t\t\t\t.struct_id = %u,\n"
10725 				"\t\t\t\t.n_bits = %u,\n"
10726 				"\t\t\t\t.offset = %u,\n"
10727 				"\t\t\t},\n",
10728 				instr->meter.color_in.struct_id,
10729 				instr->meter.color_in.n_bits,
10730 				instr->meter.color_in.offset);
10731 		else
10732 			fprintf(f,
10733 				"\t\t\t.color_in_val = %u,\n",
10734 				(uint32_t)instr->meter.color_in_val);
10735 
10736 		/* instr.meter.color_out. */
10737 		fprintf(f,
10738 			"\t\t\t.color_out = {\n"
10739 			"\t\t\t\t.struct_id = %u,\n"
10740 			"\t\t\t\t.n_bits = %u,\n"
10741 			"\t\t\t\t.offset = %u,\n"
10742 			"\t\t\t},\n",
10743 			instr->meter.color_out.struct_id,
10744 			instr->meter.color_out.n_bits,
10745 			instr->meter.color_out.offset);
10746 	}
10747 
10748 	/* instr.meter and instr - closing curly braces. */
10749 	fprintf(f,
10750 		"\t\t},\n"
10751 		"\t},\n");
10752 }
10753 
10754 static void
10755 instr_table_export(struct instruction *instr,
10756 		FILE *f)
10757 {
10758 	fprintf(f,
10759 		"\t{\n"
10760 		"\t\t.type = %s,\n"
10761 		"\t\t.table = {\n"
10762 		"\t\t\t.table_id = %u,\n"
10763 		"\t\t},\n"
10764 		"\t},\n",
10765 		instr_type_to_name(instr),
10766 		instr->table.table_id);
10767 }
10768 
10769 static void
10770 instr_learn_export(struct instruction *instr, FILE *f)
10771 {
10772 	fprintf(f,
10773 		"\t{\n"
10774 		"\t\t.type = %s,\n"
10775 		"\t\t.learn = {\n"
10776 		"\t\t\t\t.action_id = %u,\n"
10777 		"\t\t},\n"
10778 		"\t},\n",
10779 		instr_type_to_name(instr),
10780 		instr->learn.action_id);
10781 }
10782 
10783 static void
10784 instr_forget_export(struct instruction *instr, FILE *f)
10785 {
10786 	fprintf(f,
10787 		"\t{\n"
10788 		"\t\t.type = %s,\n"
10789 		"\t},\n",
10790 		instr_type_to_name(instr));
10791 }
10792 
10793 static void
10794 instr_extern_export(struct instruction *instr, FILE *f)
10795 {
10796 	if (instr->type == INSTR_EXTERN_OBJ)
10797 		fprintf(f,
10798 			"\t{\n"
10799 			"\t\t.type = %s,\n"
10800 			"\t\t.ext_obj = {\n"
10801 			"\t\t\t.ext_obj_id = %u,\n"
10802 			"\t\t\t.func_id = %u,\n"
10803 			"\t\t},\n"
10804 			"\t},\n",
10805 			instr_type_to_name(instr),
10806 			instr->ext_obj.ext_obj_id,
10807 			instr->ext_obj.func_id);
10808 	else
10809 		fprintf(f,
10810 			"\t{\n"
10811 			"\t\t.type = %s,\n"
10812 			"\t\t.ext_func = {\n"
10813 			"\t\t\t.ext_func_id = %u,\n"
10814 			"\t\t},\n"
10815 			"\t},\n",
10816 			instr_type_to_name(instr),
10817 			instr->ext_func.ext_func_id);
10818 }
10819 
10820 static void
10821 instr_jmp_export(struct instruction *instr, FILE *f __rte_unused)
10822 {
10823 	fprintf(f,
10824 		"\t{\n"
10825 		"\t\t.type = %s,\n"
10826 		"\t\t.jmp = {\n"
10827 		"\t\t\t.ip = NULL,\n",
10828 		instr_type_to_name(instr));
10829 
10830 	switch (instr->type) {
10831 	case INSTR_JMP_VALID:
10832 	case INSTR_JMP_INVALID:
10833 		fprintf(f,
10834 			"\t\t\t.header_id = %u,\n",
10835 			instr->jmp.header_id);
10836 		break;
10837 
10838 	case INSTR_JMP_ACTION_HIT:
10839 	case INSTR_JMP_ACTION_MISS:
10840 		fprintf(f,
10841 			"\t\t\t.action_id = %u,\n",
10842 			instr->jmp.action_id);
10843 		break;
10844 
10845 	case INSTR_JMP_EQ:
10846 	case INSTR_JMP_EQ_MH:
10847 	case INSTR_JMP_EQ_HM:
10848 	case INSTR_JMP_EQ_HH:
10849 	case INSTR_JMP_NEQ:
10850 	case INSTR_JMP_NEQ_MH:
10851 	case INSTR_JMP_NEQ_HM:
10852 	case INSTR_JMP_NEQ_HH:
10853 	case INSTR_JMP_LT:
10854 	case INSTR_JMP_LT_MH:
10855 	case INSTR_JMP_LT_HM:
10856 	case INSTR_JMP_LT_HH:
10857 	case INSTR_JMP_GT:
10858 	case INSTR_JMP_GT_MH:
10859 	case INSTR_JMP_GT_HM:
10860 	case INSTR_JMP_GT_HH:
10861 		fprintf(f,
10862 			"\t\t\t.a = {\n"
10863 			"\t\t\t\t.struct_id = %u,\n"
10864 			"\t\t\t\t.n_bits = %u,\n"
10865 			"\t\t\t\t.offset = %u,\n"
10866 			"\t\t\t},\n"
10867 			"\t\t\t.b = {\n"
10868 			"\t\t\t\t.struct_id = %u,\n"
10869 			"\t\t\t\t.n_bits = %u,\n"
10870 			"\t\t\t\t.offset = %u,\n"
10871 			"\t\t\t},\n",
10872 			instr->jmp.a.struct_id,
10873 			instr->jmp.a.n_bits,
10874 			instr->jmp.a.offset,
10875 			instr->jmp.b.struct_id,
10876 			instr->jmp.b.n_bits,
10877 			instr->jmp.b.offset);
10878 		break;
10879 
10880 	case INSTR_JMP_EQ_I:
10881 	case INSTR_JMP_NEQ_I:
10882 	case INSTR_JMP_LT_MI:
10883 	case INSTR_JMP_LT_HI:
10884 	case INSTR_JMP_GT_MI:
10885 	case INSTR_JMP_GT_HI:
10886 		fprintf(f,
10887 			"\t\t\t.a = {\n"
10888 			"\t\t\t\t.struct_id = %u,\n"
10889 			"\t\t\t\t.n_bits = %u,\n"
10890 			"\t\t\t\t.offset = %u,\n"
10891 			"\t\t\t}\n,"
10892 			"\t\t\t.b_val = %" PRIu64 ",\n",
10893 			instr->jmp.a.struct_id,
10894 			instr->jmp.a.n_bits,
10895 			instr->jmp.a.offset,
10896 			instr->jmp.b_val);
10897 		break;
10898 
10899 	default:
10900 		break;
10901 	}
10902 
10903 	fprintf(f,
10904 		"\t\t},\n"
10905 		"\t},\n");
10906 }
10907 
10908 static void
10909 instr_return_export(struct instruction *instr,
10910 		FILE *f)
10911 {
10912 	fprintf(f,
10913 		"\t{\n"
10914 		"\t\t.type = %s,\n",
10915 		instr_type_to_name(instr));
10916 
10917 	fprintf(f,
10918 		"\t},\n");
10919 }
10920 
10921 static instruction_export_t export_table[] = {
10922 	[INSTR_RX] = instr_io_export,
10923 
10924 	[INSTR_TX] = instr_io_export,
10925 	[INSTR_TX_I] = instr_io_export,
10926 	[INSTR_DROP] = instr_io_export,
10927 
10928 	[INSTR_HDR_EXTRACT] = instr_io_export,
10929 	[INSTR_HDR_EXTRACT2] = instr_io_export,
10930 	[INSTR_HDR_EXTRACT3] = instr_io_export,
10931 	[INSTR_HDR_EXTRACT4] = instr_io_export,
10932 	[INSTR_HDR_EXTRACT5] = instr_io_export,
10933 	[INSTR_HDR_EXTRACT6] = instr_io_export,
10934 	[INSTR_HDR_EXTRACT7] = instr_io_export,
10935 	[INSTR_HDR_EXTRACT8] = instr_io_export,
10936 
10937 	[INSTR_HDR_EXTRACT_M] = instr_io_export,
10938 
10939 	[INSTR_HDR_LOOKAHEAD] = instr_io_export,
10940 
10941 	[INSTR_HDR_EMIT] = instr_io_export,
10942 	[INSTR_HDR_EMIT_TX] = instr_io_export,
10943 	[INSTR_HDR_EMIT2_TX] = instr_io_export,
10944 	[INSTR_HDR_EMIT3_TX] = instr_io_export,
10945 	[INSTR_HDR_EMIT4_TX] = instr_io_export,
10946 	[INSTR_HDR_EMIT5_TX] = instr_io_export,
10947 	[INSTR_HDR_EMIT6_TX] = instr_io_export,
10948 	[INSTR_HDR_EMIT7_TX] = instr_io_export,
10949 	[INSTR_HDR_EMIT8_TX] = instr_io_export,
10950 
10951 	[INSTR_HDR_VALIDATE] = instr_hdr_validate_export,
10952 	[INSTR_HDR_INVALIDATE] = instr_hdr_validate_export,
10953 
10954 	[INSTR_MOV] = instr_mov_export,
10955 	[INSTR_MOV_MH] = instr_mov_export,
10956 	[INSTR_MOV_HM] = instr_mov_export,
10957 	[INSTR_MOV_HH] = instr_mov_export,
10958 	[INSTR_MOV_I] = instr_mov_export,
10959 
10960 	[INSTR_DMA_HT]  = instr_dma_ht_export,
10961 	[INSTR_DMA_HT2] = instr_dma_ht_export,
10962 	[INSTR_DMA_HT3] = instr_dma_ht_export,
10963 	[INSTR_DMA_HT4] = instr_dma_ht_export,
10964 	[INSTR_DMA_HT5] = instr_dma_ht_export,
10965 	[INSTR_DMA_HT6] = instr_dma_ht_export,
10966 	[INSTR_DMA_HT7] = instr_dma_ht_export,
10967 	[INSTR_DMA_HT8] = instr_dma_ht_export,
10968 
10969 	[INSTR_ALU_ADD] = instr_alu_export,
10970 	[INSTR_ALU_ADD_MH] = instr_alu_export,
10971 	[INSTR_ALU_ADD_HM] = instr_alu_export,
10972 	[INSTR_ALU_ADD_HH] = instr_alu_export,
10973 	[INSTR_ALU_ADD_MI] = instr_alu_export,
10974 	[INSTR_ALU_ADD_HI] = instr_alu_export,
10975 
10976 	[INSTR_ALU_SUB] = instr_alu_export,
10977 	[INSTR_ALU_SUB_MH] = instr_alu_export,
10978 	[INSTR_ALU_SUB_HM] = instr_alu_export,
10979 	[INSTR_ALU_SUB_HH] = instr_alu_export,
10980 	[INSTR_ALU_SUB_MI] = instr_alu_export,
10981 	[INSTR_ALU_SUB_HI] = instr_alu_export,
10982 
10983 	[INSTR_ALU_CKADD_FIELD] = instr_alu_export,
10984 	[INSTR_ALU_CKADD_STRUCT] = instr_alu_export,
10985 	[INSTR_ALU_CKADD_STRUCT20] = instr_alu_export,
10986 	[INSTR_ALU_CKSUB_FIELD] = instr_alu_export,
10987 
10988 	[INSTR_ALU_AND] = instr_alu_export,
10989 	[INSTR_ALU_AND_MH] = instr_alu_export,
10990 	[INSTR_ALU_AND_HM] = instr_alu_export,
10991 	[INSTR_ALU_AND_HH] = instr_alu_export,
10992 	[INSTR_ALU_AND_I] = instr_alu_export,
10993 
10994 	[INSTR_ALU_OR] = instr_alu_export,
10995 	[INSTR_ALU_OR_MH] = instr_alu_export,
10996 	[INSTR_ALU_OR_HM] = instr_alu_export,
10997 	[INSTR_ALU_OR_HH] = instr_alu_export,
10998 	[INSTR_ALU_OR_I] = instr_alu_export,
10999 
11000 	[INSTR_ALU_XOR] = instr_alu_export,
11001 	[INSTR_ALU_XOR_MH] = instr_alu_export,
11002 	[INSTR_ALU_XOR_HM] = instr_alu_export,
11003 	[INSTR_ALU_XOR_HH] = instr_alu_export,
11004 	[INSTR_ALU_XOR_I] = instr_alu_export,
11005 
11006 	[INSTR_ALU_SHL] = instr_alu_export,
11007 	[INSTR_ALU_SHL_MH] = instr_alu_export,
11008 	[INSTR_ALU_SHL_HM] = instr_alu_export,
11009 	[INSTR_ALU_SHL_HH] = instr_alu_export,
11010 	[INSTR_ALU_SHL_MI] = instr_alu_export,
11011 	[INSTR_ALU_SHL_HI] = instr_alu_export,
11012 
11013 	[INSTR_ALU_SHR] = instr_alu_export,
11014 	[INSTR_ALU_SHR_MH] = instr_alu_export,
11015 	[INSTR_ALU_SHR_HM] = instr_alu_export,
11016 	[INSTR_ALU_SHR_HH] = instr_alu_export,
11017 	[INSTR_ALU_SHR_MI] = instr_alu_export,
11018 	[INSTR_ALU_SHR_HI] = instr_alu_export,
11019 
11020 	[INSTR_REGPREFETCH_RH] = instr_reg_export,
11021 	[INSTR_REGPREFETCH_RM] = instr_reg_export,
11022 	[INSTR_REGPREFETCH_RI] = instr_reg_export,
11023 
11024 	[INSTR_REGRD_HRH] = instr_reg_export,
11025 	[INSTR_REGRD_HRM] = instr_reg_export,
11026 	[INSTR_REGRD_MRH] = instr_reg_export,
11027 	[INSTR_REGRD_MRM] = instr_reg_export,
11028 	[INSTR_REGRD_HRI] = instr_reg_export,
11029 	[INSTR_REGRD_MRI] = instr_reg_export,
11030 
11031 	[INSTR_REGWR_RHH] = instr_reg_export,
11032 	[INSTR_REGWR_RHM] = instr_reg_export,
11033 	[INSTR_REGWR_RMH] = instr_reg_export,
11034 	[INSTR_REGWR_RMM] = instr_reg_export,
11035 	[INSTR_REGWR_RHI] = instr_reg_export,
11036 	[INSTR_REGWR_RMI] = instr_reg_export,
11037 	[INSTR_REGWR_RIH] = instr_reg_export,
11038 	[INSTR_REGWR_RIM] = instr_reg_export,
11039 	[INSTR_REGWR_RII] = instr_reg_export,
11040 
11041 	[INSTR_REGADD_RHH] = instr_reg_export,
11042 	[INSTR_REGADD_RHM] = instr_reg_export,
11043 	[INSTR_REGADD_RMH] = instr_reg_export,
11044 	[INSTR_REGADD_RMM] = instr_reg_export,
11045 	[INSTR_REGADD_RHI] = instr_reg_export,
11046 	[INSTR_REGADD_RMI] = instr_reg_export,
11047 	[INSTR_REGADD_RIH] = instr_reg_export,
11048 	[INSTR_REGADD_RIM] = instr_reg_export,
11049 	[INSTR_REGADD_RII] = instr_reg_export,
11050 
11051 	[INSTR_METPREFETCH_H] = instr_meter_export,
11052 	[INSTR_METPREFETCH_M] = instr_meter_export,
11053 	[INSTR_METPREFETCH_I] = instr_meter_export,
11054 
11055 	[INSTR_METER_HHM] = instr_meter_export,
11056 	[INSTR_METER_HHI] = instr_meter_export,
11057 	[INSTR_METER_HMM] = instr_meter_export,
11058 	[INSTR_METER_HMI] = instr_meter_export,
11059 	[INSTR_METER_MHM] = instr_meter_export,
11060 	[INSTR_METER_MHI] = instr_meter_export,
11061 	[INSTR_METER_MMM] = instr_meter_export,
11062 	[INSTR_METER_MMI] = instr_meter_export,
11063 	[INSTR_METER_IHM] = instr_meter_export,
11064 	[INSTR_METER_IHI] = instr_meter_export,
11065 	[INSTR_METER_IMM] = instr_meter_export,
11066 	[INSTR_METER_IMI] = instr_meter_export,
11067 
11068 	[INSTR_TABLE] = instr_table_export,
11069 	[INSTR_TABLE_AF] = instr_table_export,
11070 	[INSTR_SELECTOR] = instr_table_export,
11071 	[INSTR_LEARNER] = instr_table_export,
11072 	[INSTR_LEARNER_AF] = instr_table_export,
11073 
11074 	[INSTR_LEARNER_LEARN] = instr_learn_export,
11075 	[INSTR_LEARNER_FORGET] = instr_forget_export,
11076 
11077 	[INSTR_EXTERN_OBJ] = instr_extern_export,
11078 	[INSTR_EXTERN_FUNC] = instr_extern_export,
11079 
11080 	[INSTR_JMP] = instr_jmp_export,
11081 	[INSTR_JMP_VALID] = instr_jmp_export,
11082 	[INSTR_JMP_INVALID] = instr_jmp_export,
11083 	[INSTR_JMP_HIT] = instr_jmp_export,
11084 	[INSTR_JMP_MISS] = instr_jmp_export,
11085 	[INSTR_JMP_ACTION_HIT] = instr_jmp_export,
11086 	[INSTR_JMP_ACTION_MISS] = instr_jmp_export,
11087 
11088 	[INSTR_JMP_EQ] = instr_jmp_export,
11089 	[INSTR_JMP_EQ_MH] = instr_jmp_export,
11090 	[INSTR_JMP_EQ_HM] = instr_jmp_export,
11091 	[INSTR_JMP_EQ_HH] = instr_jmp_export,
11092 	[INSTR_JMP_EQ_I] = instr_jmp_export,
11093 
11094 	[INSTR_JMP_NEQ] = instr_jmp_export,
11095 	[INSTR_JMP_NEQ_MH] = instr_jmp_export,
11096 	[INSTR_JMP_NEQ_HM] = instr_jmp_export,
11097 	[INSTR_JMP_NEQ_HH] = instr_jmp_export,
11098 	[INSTR_JMP_NEQ_I] = instr_jmp_export,
11099 
11100 	[INSTR_JMP_LT] = instr_jmp_export,
11101 	[INSTR_JMP_LT_MH] = instr_jmp_export,
11102 	[INSTR_JMP_LT_HM] = instr_jmp_export,
11103 	[INSTR_JMP_LT_HH] = instr_jmp_export,
11104 	[INSTR_JMP_LT_MI] = instr_jmp_export,
11105 	[INSTR_JMP_LT_HI] = instr_jmp_export,
11106 
11107 	[INSTR_JMP_GT] = instr_jmp_export,
11108 	[INSTR_JMP_GT_MH] = instr_jmp_export,
11109 	[INSTR_JMP_GT_HM] = instr_jmp_export,
11110 	[INSTR_JMP_GT_HH] = instr_jmp_export,
11111 	[INSTR_JMP_GT_MI] = instr_jmp_export,
11112 	[INSTR_JMP_GT_HI] = instr_jmp_export,
11113 
11114 	[INSTR_RETURN] = instr_return_export,
11115 };
11116 
11117 static void
11118 action_data_codegen(struct action *a, FILE *f)
11119 {
11120 	uint32_t i;
11121 
11122 	fprintf(f,
11123 		"static const struct instruction action_%s_instructions[] = {\n",
11124 		a->name);
11125 
11126 	for (i = 0; i < a->n_instructions; i++) {
11127 		struct instruction *instr = &a->instructions[i];
11128 		instruction_export_t func = export_table[instr->type];
11129 
11130 		func(instr, f);
11131 	}
11132 
11133 	fprintf(f, "};\n");
11134 }
11135 
11136 static const char *
11137 instr_type_to_func(struct instruction *instr)
11138 {
11139 	switch (instr->type) {
11140 	case INSTR_RX: return NULL;
11141 
11142 	case INSTR_TX: return "__instr_tx_exec";
11143 	case INSTR_TX_I: return "__instr_tx_i_exec";
11144 	case INSTR_DROP: return "__instr_drop_exec";
11145 
11146 	case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec";
11147 	case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec";
11148 	case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec";
11149 	case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec";
11150 	case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec";
11151 	case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec";
11152 	case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec";
11153 	case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec";
11154 
11155 	case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec";
11156 
11157 	case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec";
11158 
11159 	case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec";
11160 	case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec";
11161 	case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec";
11162 	case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec";
11163 	case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec";
11164 	case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec";
11165 	case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec";
11166 	case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec";
11167 	case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec";
11168 
11169 	case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec";
11170 	case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec";
11171 
11172 	case INSTR_MOV: return "__instr_mov_exec";
11173 	case INSTR_MOV_MH: return "__instr_mov_mh_exec";
11174 	case INSTR_MOV_HM: return "__instr_mov_hm_exec";
11175 	case INSTR_MOV_HH: return "__instr_mov_hh_exec";
11176 	case INSTR_MOV_I: return "__instr_mov_i_exec";
11177 
11178 	case INSTR_DMA_HT: return "__instr_dma_ht_exec";
11179 	case INSTR_DMA_HT2: return "__instr_dma_ht2_exec";
11180 	case INSTR_DMA_HT3: return "__instr_dma_ht3_exec";
11181 	case INSTR_DMA_HT4: return "__instr_dma_ht4_exec";
11182 	case INSTR_DMA_HT5: return "__instr_dma_ht5_exec";
11183 	case INSTR_DMA_HT6: return "__instr_dma_ht6_exec";
11184 	case INSTR_DMA_HT7: return "__instr_dma_ht7_exec";
11185 	case INSTR_DMA_HT8: return "__instr_dma_ht8_exec";
11186 
11187 	case INSTR_ALU_ADD: return "__instr_alu_add_exec";
11188 	case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec";
11189 	case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec";
11190 	case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec";
11191 	case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec";
11192 	case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec";
11193 
11194 	case INSTR_ALU_SUB: return "__instr_alu_sub_exec";
11195 	case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec";
11196 	case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec";
11197 	case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec";
11198 	case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec";
11199 	case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec";
11200 
11201 	case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec";
11202 	case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec";
11203 	case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec";
11204 	case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec";
11205 
11206 	case INSTR_ALU_AND: return "__instr_alu_and_exec";
11207 	case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec";
11208 	case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec";
11209 	case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec";
11210 	case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec";
11211 
11212 	case INSTR_ALU_OR: return "__instr_alu_or_exec";
11213 	case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec";
11214 	case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec";
11215 	case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec";
11216 	case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec";
11217 
11218 	case INSTR_ALU_XOR: return "__instr_alu_xor_exec";
11219 	case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec";
11220 	case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec";
11221 	case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec";
11222 	case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec";
11223 
11224 	case INSTR_ALU_SHL: return "__instr_alu_shl_exec";
11225 	case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec";
11226 	case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec";
11227 	case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec";
11228 	case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec";
11229 	case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec";
11230 
11231 	case INSTR_ALU_SHR: return "__instr_alu_shr_exec";
11232 	case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec";
11233 	case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec";
11234 	case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec";
11235 	case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec";
11236 	case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec";
11237 
11238 	case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec";
11239 	case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec";
11240 	case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec";
11241 
11242 	case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec";
11243 	case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec";
11244 	case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec";
11245 	case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec";
11246 	case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec";
11247 	case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec";
11248 
11249 	case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec";
11250 	case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec";
11251 	case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec";
11252 	case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec";
11253 	case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec";
11254 	case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec";
11255 	case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec";
11256 	case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec";
11257 	case INSTR_REGWR_RII: return "__instr_regwr_rii_exec";
11258 
11259 	case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec";
11260 	case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec";
11261 	case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec";
11262 	case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec";
11263 	case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec";
11264 	case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec";
11265 	case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec";
11266 	case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec";
11267 	case INSTR_REGADD_RII: return "__instr_regadd_rii_exec";
11268 
11269 	case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec";
11270 	case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec";
11271 	case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec";
11272 
11273 	case INSTR_METER_HHM: return "__instr_meter_hhm_exec";
11274 	case INSTR_METER_HHI: return "__instr_meter_hhi_exec";
11275 	case INSTR_METER_HMM: return "__instr_meter_hmm_exec";
11276 	case INSTR_METER_HMI: return "__instr_meter_hmi_exec";
11277 	case INSTR_METER_MHM: return "__instr_meter_mhm_exec";
11278 	case INSTR_METER_MHI: return "__instr_meter_mhi_exec";
11279 	case INSTR_METER_MMM: return "__instr_meter_mmm_exec";
11280 	case INSTR_METER_MMI: return "__instr_meter_mmi_exec";
11281 	case INSTR_METER_IHM: return "__instr_meter_ihm_exec";
11282 	case INSTR_METER_IHI: return "__instr_meter_ihi_exec";
11283 	case INSTR_METER_IMM: return "__instr_meter_imm_exec";
11284 	case INSTR_METER_IMI: return "__instr_meter_imi_exec";
11285 
11286 	case INSTR_TABLE: return NULL;
11287 	case INSTR_TABLE_AF: return NULL;
11288 	case INSTR_SELECTOR: return NULL;
11289 	case INSTR_LEARNER: return NULL;
11290 	case INSTR_LEARNER_AF: return NULL;
11291 
11292 	case INSTR_LEARNER_LEARN: return "__instr_learn_exec";
11293 	case INSTR_LEARNER_FORGET: return "__instr_forget_exec";
11294 
11295 	case INSTR_EXTERN_OBJ: return NULL;
11296 	case INSTR_EXTERN_FUNC: return NULL;
11297 
11298 	case INSTR_JMP: return NULL;
11299 	case INSTR_JMP_VALID: return NULL;
11300 	case INSTR_JMP_INVALID: return NULL;
11301 	case INSTR_JMP_HIT: return NULL;
11302 	case INSTR_JMP_MISS: return NULL;
11303 	case INSTR_JMP_ACTION_HIT: return NULL;
11304 	case INSTR_JMP_ACTION_MISS: return NULL;
11305 	case INSTR_JMP_EQ: return NULL;
11306 	case INSTR_JMP_EQ_MH: return NULL;
11307 	case INSTR_JMP_EQ_HM: return NULL;
11308 	case INSTR_JMP_EQ_HH: return NULL;
11309 	case INSTR_JMP_EQ_I: return NULL;
11310 	case INSTR_JMP_NEQ: return NULL;
11311 	case INSTR_JMP_NEQ_MH: return NULL;
11312 	case INSTR_JMP_NEQ_HM: return NULL;
11313 	case INSTR_JMP_NEQ_HH: return NULL;
11314 	case INSTR_JMP_NEQ_I: return NULL;
11315 	case INSTR_JMP_LT: return NULL;
11316 	case INSTR_JMP_LT_MH: return NULL;
11317 	case INSTR_JMP_LT_HM: return NULL;
11318 	case INSTR_JMP_LT_HH: return NULL;
11319 	case INSTR_JMP_LT_MI: return NULL;
11320 	case INSTR_JMP_LT_HI: return NULL;
11321 	case INSTR_JMP_GT: return NULL;
11322 	case INSTR_JMP_GT_MH: return NULL;
11323 	case INSTR_JMP_GT_HM: return NULL;
11324 	case INSTR_JMP_GT_HH: return NULL;
11325 	case INSTR_JMP_GT_MI: return NULL;
11326 	case INSTR_JMP_GT_HI: return NULL;
11327 
11328 	case INSTR_RETURN: return NULL;
11329 
11330 	default: return NULL;
11331 	}
11332 }
11333 
11334 static void
11335 action_instr_does_tx_codegen(struct action *a,
11336 			uint32_t instr_pos,
11337 			struct instruction *instr,
11338 			FILE *f)
11339 {
11340 	fprintf(f,
11341 		"%s(p, t, &action_%s_instructions[%u]);\n"
11342 		"\tthread_ip_reset(p, t);\n"
11343 		"\tinstr_rx_exec(p);\n"
11344 		"\treturn;\n",
11345 		instr_type_to_func(instr),
11346 		a->name,
11347 		instr_pos);
11348 }
11349 
11350 static void
11351 action_instr_extern_obj_codegen(struct action *a,
11352 				uint32_t instr_pos,
11353 				FILE *f)
11354 {
11355 	fprintf(f,
11356 		"while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n",
11357 		a->name,
11358 		instr_pos);
11359 }
11360 
11361 static void
11362 action_instr_extern_func_codegen(struct action *a,
11363 				 uint32_t instr_pos,
11364 				 FILE *f)
11365 {
11366 	fprintf(f,
11367 		"while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n",
11368 		a->name,
11369 		instr_pos);
11370 }
11371 
11372 static void
11373 action_instr_jmp_codegen(struct action *a,
11374 			 uint32_t instr_pos,
11375 			 struct instruction *instr,
11376 			 struct instruction_data *data,
11377 			 FILE *f)
11378 {
11379 	switch (instr->type) {
11380 	case INSTR_JMP:
11381 		fprintf(f,
11382 			"goto %s;\n",
11383 			data->jmp_label);
11384 		return;
11385 
11386 	case INSTR_JMP_VALID:
11387 		fprintf(f,
11388 			"if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n"
11389 			"\t\tgoto %s;\n",
11390 			a->name,
11391 			instr_pos,
11392 			data->jmp_label);
11393 		return;
11394 
11395 	case INSTR_JMP_INVALID:
11396 		fprintf(f,
11397 			"if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n"
11398 			"\t\tgoto %s;\n",
11399 			a->name,
11400 			instr_pos,
11401 			data->jmp_label);
11402 		return;
11403 
11404 	case INSTR_JMP_HIT:
11405 		fprintf(f,
11406 			"if (t->hit)\n"
11407 			"\t\tgoto %s;\n",
11408 			data->jmp_label);
11409 		return;
11410 
11411 	case INSTR_JMP_MISS:
11412 		fprintf(f,
11413 			"if (!t->hit)\n"
11414 			"\t\tgoto %s;\n",
11415 			data->jmp_label);
11416 		return;
11417 
11418 	case INSTR_JMP_ACTION_HIT:
11419 		fprintf(f,
11420 			"if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n"
11421 			"\t\tgoto %s;\n",
11422 			a->name,
11423 			instr_pos,
11424 			data->jmp_label);
11425 		return;
11426 
11427 	case INSTR_JMP_ACTION_MISS:
11428 		fprintf(f,
11429 			"if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n"
11430 			"\t\tgoto %s;\n",
11431 			a->name,
11432 			instr_pos,
11433 			data->jmp_label);
11434 		return;
11435 
11436 	case INSTR_JMP_EQ:
11437 		fprintf(f,
11438 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == "
11439 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11440 			"\t\tgoto %s;\n",
11441 			a->name,
11442 			instr_pos,
11443 			a->name,
11444 			instr_pos,
11445 			data->jmp_label);
11446 		return;
11447 
11448 	case INSTR_JMP_EQ_MH:
11449 		fprintf(f,
11450 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == "
11451 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11452 			"\t\tgoto %s;\n",
11453 			a->name,
11454 			instr_pos,
11455 			a->name,
11456 			instr_pos,
11457 			data->jmp_label);
11458 		return;
11459 
11460 	case INSTR_JMP_EQ_HM:
11461 		fprintf(f,
11462 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == "
11463 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11464 			"\t\tgoto %s;\n",
11465 			a->name,
11466 			instr_pos,
11467 			a->name,
11468 			instr_pos,
11469 			data->jmp_label);
11470 		return;
11471 
11472 	case INSTR_JMP_EQ_HH:
11473 		fprintf(f,
11474 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == "
11475 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11476 			"\t\tgoto %s;\n",
11477 			a->name,
11478 			instr_pos,
11479 			a->name,
11480 			instr_pos,
11481 			data->jmp_label);
11482 		return;
11483 
11484 	case INSTR_JMP_EQ_I:
11485 		fprintf(f,
11486 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == "
11487 			"action_%s_instructions[%u].jmp.b_val)\n"
11488 			"\t\tgoto %s;\n",
11489 			a->name,
11490 			instr_pos,
11491 			a->name,
11492 			instr_pos,
11493 			data->jmp_label);
11494 		return;
11495 
11496 	case INSTR_JMP_NEQ:
11497 		fprintf(f,
11498 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != "
11499 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11500 			"\t\tgoto %s;\n",
11501 			a->name,
11502 			instr_pos,
11503 			a->name,
11504 			instr_pos,
11505 			data->jmp_label);
11506 		return;
11507 
11508 	case INSTR_JMP_NEQ_MH:
11509 		fprintf(f,
11510 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != "
11511 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11512 			"\t\tgoto %s;\n",
11513 			a->name,
11514 			instr_pos,
11515 			a->name,
11516 			instr_pos,
11517 			data->jmp_label);
11518 		return;
11519 
11520 	case INSTR_JMP_NEQ_HM:
11521 		fprintf(f,
11522 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != "
11523 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11524 			"\t\tgoto %s;\n",
11525 			a->name,
11526 			instr_pos,
11527 			a->name,
11528 			instr_pos,
11529 			data->jmp_label);
11530 		return;
11531 
11532 	case INSTR_JMP_NEQ_HH:
11533 		fprintf(f,
11534 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != "
11535 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11536 			"\t\tgoto %s;\n",
11537 			a->name,
11538 			instr_pos,
11539 			a->name,
11540 			instr_pos,
11541 			data->jmp_label);
11542 		return;
11543 
11544 	case INSTR_JMP_NEQ_I:
11545 		fprintf(f,
11546 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != "
11547 			"action_%s_instructions[%u].jmp.b_val)\n"
11548 			"\t\tgoto %s;\n",
11549 			a->name,
11550 			instr_pos,
11551 			a->name,
11552 			instr_pos,
11553 			data->jmp_label);
11554 		return;
11555 
11556 	case INSTR_JMP_LT:
11557 		fprintf(f,
11558 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < "
11559 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11560 			"\t\tgoto %s;\n",
11561 			a->name,
11562 			instr_pos,
11563 			a->name,
11564 			instr_pos,
11565 			data->jmp_label);
11566 		return;
11567 
11568 	case INSTR_JMP_LT_MH:
11569 		fprintf(f,
11570 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < "
11571 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11572 			"\t\tgoto %s;\n",
11573 			a->name,
11574 			instr_pos,
11575 			a->name,
11576 			instr_pos,
11577 			data->jmp_label);
11578 		return;
11579 
11580 	case INSTR_JMP_LT_HM:
11581 		fprintf(f,
11582 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < "
11583 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11584 			"\t\tgoto %s;\n",
11585 			a->name,
11586 			instr_pos,
11587 			a->name,
11588 			instr_pos,
11589 			data->jmp_label);
11590 		return;
11591 
11592 	case INSTR_JMP_LT_HH:
11593 		fprintf(f,
11594 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < "
11595 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11596 			"\t\tgoto %s;\n",
11597 			a->name,
11598 			instr_pos,
11599 			a->name,
11600 			instr_pos,
11601 			data->jmp_label);
11602 		return;
11603 
11604 	case INSTR_JMP_LT_MI:
11605 		fprintf(f,
11606 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < "
11607 			"action_%s_instructions[%u].jmp.b_val)\n"
11608 			"\t\tgoto %s;\n",
11609 			a->name,
11610 			instr_pos,
11611 			a->name,
11612 			instr_pos,
11613 			data->jmp_label);
11614 		return;
11615 
11616 	case INSTR_JMP_LT_HI:
11617 		fprintf(f,
11618 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < "
11619 			"action_%s_instructions[%u].jmp.b_val)\n"
11620 			"\t\tgoto %s;\n",
11621 			a->name,
11622 			instr_pos,
11623 			a->name,
11624 			instr_pos,
11625 			data->jmp_label);
11626 		return;
11627 
11628 	case INSTR_JMP_GT:
11629 		fprintf(f,
11630 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > "
11631 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11632 			"\t\tgoto %s;\n",
11633 			a->name,
11634 			instr_pos,
11635 			a->name,
11636 			instr_pos,
11637 			data->jmp_label);
11638 		return;
11639 
11640 	case INSTR_JMP_GT_MH:
11641 		fprintf(f,
11642 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > "
11643 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11644 			"\t\tgoto %s;\n",
11645 			a->name,
11646 			instr_pos,
11647 			a->name,
11648 			instr_pos,
11649 			data->jmp_label);
11650 		return;
11651 
11652 	case INSTR_JMP_GT_HM:
11653 		fprintf(f,
11654 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > "
11655 			"instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n"
11656 			"\t\tgoto %s;\n",
11657 			a->name,
11658 			instr_pos,
11659 			a->name,
11660 			instr_pos,
11661 			data->jmp_label);
11662 		return;
11663 
11664 	case INSTR_JMP_GT_HH:
11665 		fprintf(f,
11666 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > "
11667 			"instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n"
11668 			"\t\tgoto %s;\n",
11669 			a->name,
11670 			instr_pos,
11671 			a->name,
11672 			instr_pos,
11673 			data->jmp_label);
11674 		return;
11675 
11676 	case INSTR_JMP_GT_MI:
11677 		fprintf(f,
11678 			"if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > "
11679 			"action_%s_instructions[%u].jmp.b_val)\n"
11680 			"\t\tgoto %s;\n",
11681 			a->name,
11682 			instr_pos,
11683 			a->name,
11684 			instr_pos,
11685 			data->jmp_label);
11686 		return;
11687 
11688 	case INSTR_JMP_GT_HI:
11689 		fprintf(f,
11690 			"if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > "
11691 			"action_%s_instructions[%u].jmp.b_val)\n"
11692 			"\t\tgoto %s;\n",
11693 			a->name,
11694 			instr_pos,
11695 			a->name,
11696 			instr_pos,
11697 			data->jmp_label);
11698 		return;
11699 
11700 	default:
11701 		return;
11702 	}
11703 }
11704 
11705 static void
11706 action_instr_return_codegen(FILE *f)
11707 {
11708 	fprintf(f,
11709 		"return;\n");
11710 }
11711 
11712 static void
11713 action_instr_codegen(struct action *a, FILE *f)
11714 {
11715 	uint32_t i;
11716 
11717 	fprintf(f,
11718 		"void\n"
11719 		"action_%s_run(struct rte_swx_pipeline *p)\n"
11720 		"{\n"
11721 		"\tstruct thread *t = &p->threads[p->thread_id];\n"
11722 		"\n",
11723 		a->name);
11724 
11725 	for (i = 0; i < a->n_instructions; i++) {
11726 		struct instruction *instr = &a->instructions[i];
11727 		struct instruction_data *data = &a->instruction_data[i];
11728 
11729 		/* Label, if present. */
11730 		if (data->label[0])
11731 			fprintf(f, "\n%s : ", data->label);
11732 		else
11733 			fprintf(f, "\n\t");
11734 
11735 		/* TX instruction type. */
11736 		if (instruction_does_tx(instr)) {
11737 			action_instr_does_tx_codegen(a, i, instr, f);
11738 			continue;
11739 		}
11740 
11741 		/* Extern object/function instruction type. */
11742 		if (instr->type == INSTR_EXTERN_OBJ) {
11743 			action_instr_extern_obj_codegen(a, i, f);
11744 			continue;
11745 		}
11746 
11747 		if (instr->type == INSTR_EXTERN_FUNC) {
11748 			action_instr_extern_func_codegen(a, i, f);
11749 			continue;
11750 		}
11751 
11752 		/* Jump instruction type. */
11753 		if (instruction_is_jmp(instr)) {
11754 			action_instr_jmp_codegen(a, i, instr, data, f);
11755 			continue;
11756 		}
11757 
11758 		/* Return instruction type. */
11759 		if (instr->type == INSTR_RETURN) {
11760 			action_instr_return_codegen(f);
11761 			continue;
11762 		}
11763 
11764 		/* Any other instruction type. */
11765 		fprintf(f,
11766 			"%s(p, t, &action_%s_instructions[%u]);\n",
11767 			instr_type_to_func(instr),
11768 			a->name,
11769 			i);
11770 	}
11771 
11772 	fprintf(f, "}\n\n");
11773 }
11774 
11775 struct instruction_group {
11776 	TAILQ_ENTRY(instruction_group) node;
11777 
11778 	uint32_t group_id;
11779 
11780 	uint32_t first_instr_id;
11781 
11782 	uint32_t last_instr_id;
11783 
11784 	instr_exec_t func;
11785 };
11786 
11787 TAILQ_HEAD(instruction_group_list, instruction_group);
11788 
11789 static struct instruction_group *
11790 instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id)
11791 {
11792 	struct instruction_group *g;
11793 
11794 	TAILQ_FOREACH(g, igl, node)
11795 		if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id))
11796 			return g;
11797 
11798 	return NULL;
11799 }
11800 
11801 static void
11802 instruction_group_list_free(struct instruction_group_list *igl)
11803 {
11804 	if (!igl)
11805 		return;
11806 
11807 	for ( ; ; ) {
11808 		struct instruction_group *g;
11809 
11810 		g = TAILQ_FIRST(igl);
11811 		if (!g)
11812 			break;
11813 
11814 		TAILQ_REMOVE(igl, g, node);
11815 		free(g);
11816 	}
11817 
11818 	free(igl);
11819 }
11820 
11821 static struct instruction_group_list *
11822 instruction_group_list_create(struct rte_swx_pipeline *p)
11823 {
11824 	struct instruction_group_list *igl = NULL;
11825 	struct instruction_group *g = NULL;
11826 	uint32_t n_groups = 0, i;
11827 
11828 	if (!p || !p->instructions || !p->instruction_data || !p->n_instructions)
11829 		goto error;
11830 
11831 	/* List init. */
11832 	igl = calloc(1, sizeof(struct instruction_group_list));
11833 	if (!igl)
11834 		goto error;
11835 
11836 	TAILQ_INIT(igl);
11837 
11838 	/* Allocate the first group. */
11839 	g = calloc(1, sizeof(struct instruction_group));
11840 	if (!g)
11841 		goto error;
11842 
11843 	/* Iteration 1: Separate the instructions into groups based on the thread yield
11844 	 * instructions. Do not worry about the jump instructions at this point.
11845 	 */
11846 	for (i = 0; i < p->n_instructions; i++) {
11847 		struct instruction *instr = &p->instructions[i];
11848 
11849 		/* Check for thread yield instructions. */
11850 		if (!instruction_does_thread_yield(instr))
11851 			continue;
11852 
11853 		/* If the current group contains at least one instruction, then finalize it (with
11854 		 * the previous instruction), add it to the list and allocate a new group (that
11855 		 * starts with the current instruction).
11856 		 */
11857 		if (i - g->first_instr_id) {
11858 			/* Finalize the group. */
11859 			g->last_instr_id = i - 1;
11860 
11861 			/* Add the group to the list. Advance the number of groups. */
11862 			TAILQ_INSERT_TAIL(igl, g, node);
11863 			n_groups++;
11864 
11865 			/* Allocate a new group. */
11866 			g = calloc(1, sizeof(struct instruction_group));
11867 			if (!g)
11868 				goto error;
11869 
11870 			/* Initialize the new group. */
11871 			g->group_id = n_groups;
11872 			g->first_instr_id = i;
11873 		}
11874 
11875 		/* Finalize the current group (with the current instruction, therefore this group
11876 		 * contains just the current thread yield instruction), add it to the list and
11877 		 * allocate a new group (that starts with the next instruction).
11878 		 */
11879 
11880 		/* Finalize the group. */
11881 		g->last_instr_id = i;
11882 
11883 		/* Add the group to the list. Advance the number of groups. */
11884 		TAILQ_INSERT_TAIL(igl, g, node);
11885 		n_groups++;
11886 
11887 		/* Allocate a new group. */
11888 		g = calloc(1, sizeof(struct instruction_group));
11889 		if (!g)
11890 			goto error;
11891 
11892 		/* Initialize the new group. */
11893 		g->group_id = n_groups;
11894 		g->first_instr_id = i + 1;
11895 	}
11896 
11897 	/* Handle the last group. */
11898 	if (i - g->first_instr_id) {
11899 		/* Finalize the group. */
11900 		g->last_instr_id = i - 1;
11901 
11902 		/* Add the group to the list. Advance the number of groups. */
11903 		TAILQ_INSERT_TAIL(igl, g, node);
11904 		n_groups++;
11905 	} else
11906 		free(g);
11907 
11908 	g = NULL;
11909 
11910 	/* Iteration 2: Handle jumps. If the current group contains an instruction which represents
11911 	 * the destination of a jump instruction located in a different group ("far jump"), then the
11912 	 * current group has to be split, so that the instruction representing the far jump
11913 	 * destination is at the start of its group.
11914 	 */
11915 	for ( ; ; ) {
11916 		int is_modified = 0;
11917 
11918 		for (i = 0; i < p->n_instructions; i++) {
11919 			struct instruction_data *data = &p->instruction_data[i];
11920 			struct instruction_group *g;
11921 			uint32_t j;
11922 
11923 			/* Continue when the current instruction is not a jump destination. */
11924 			if (!data->n_users)
11925 				continue;
11926 
11927 			g = instruction_group_list_group_find(igl, i);
11928 			if (!g)
11929 				goto error;
11930 
11931 			/* Find out all the jump instructions with this destination. */
11932 			for (j = 0; j < p->n_instructions; j++) {
11933 				struct instruction *jmp_instr = &p->instructions[j];
11934 				struct instruction_data *jmp_data = &p->instruction_data[j];
11935 				struct instruction_group *jmp_g, *new_g;
11936 
11937 				/* Continue when not a jump instruction. Even when jump instruction,
11938 				 * continue when the jump destination is not this instruction.
11939 				 */
11940 				if (!instruction_is_jmp(jmp_instr) ||
11941 				    strcmp(jmp_data->jmp_label, data->label))
11942 					continue;
11943 
11944 				jmp_g = instruction_group_list_group_find(igl, j);
11945 				if (!jmp_g)
11946 					goto error;
11947 
11948 				/* Continue when both the jump instruction and the jump destination
11949 				 * instruction are in the same group. Even when in different groups,
11950 				 * still continue if the jump destination instruction is already the
11951 				 * first instruction of its group.
11952 				 */
11953 				if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i))
11954 					continue;
11955 
11956 				/* Split the group of the current jump destination instruction to
11957 				 * make this instruction the first instruction of a new group.
11958 				 */
11959 				new_g = calloc(1, sizeof(struct instruction_group));
11960 				if (!new_g)
11961 					goto error;
11962 
11963 				new_g->group_id = n_groups;
11964 				new_g->first_instr_id = i;
11965 				new_g->last_instr_id = g->last_instr_id;
11966 
11967 				g->last_instr_id = i - 1;
11968 
11969 				TAILQ_INSERT_AFTER(igl, g, new_g, node);
11970 				n_groups++;
11971 				is_modified = 1;
11972 
11973 				/* The decision to split this group (to make the current instruction
11974 				 * the first instruction of a new group) is already taken and fully
11975 				 * implemented, so no need to search for more reasons to do it.
11976 				 */
11977 				break;
11978 			}
11979 		}
11980 
11981 		/* Re-evaluate everything, as at least one group got split, so some jumps that were
11982 		 * previously considered local (i.e. the jump destination is in the same group as
11983 		 * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a
11984 		 * different group than the jump instruction). Wost case scenario: each instruction
11985 		 * that is a jump destination ends up as the first instruction of its group.
11986 		 */
11987 		if (!is_modified)
11988 			break;
11989 	}
11990 
11991 	/* Re-assign the group IDs to be in incremental order. */
11992 	i = 0;
11993 	TAILQ_FOREACH(g, igl, node) {
11994 		g->group_id = i;
11995 
11996 		i++;
11997 	}
11998 
11999 	return igl;
12000 
12001 error:
12002 	instruction_group_list_free(igl);
12003 
12004 	free(g);
12005 
12006 	return NULL;
12007 }
12008 
12009 static void
12010 pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused,
12011 			       uint32_t instr_pos,
12012 			       struct instruction *instr,
12013 			       FILE *f)
12014 {
12015 	fprintf(f,
12016 		"%s(p, t, &pipeline_instructions[%u]);\n"
12017 		"\tthread_ip_reset(p, t);\n"
12018 		"\tinstr_rx_exec(p);\n"
12019 		"\treturn;\n",
12020 		instr_type_to_func(instr),
12021 		instr_pos);
12022 }
12023 
12024 static int
12025 pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p,
12026 			   struct instruction_group_list *igl,
12027 			   uint32_t jmp_instr_id,
12028 			   struct instruction *jmp_instr,
12029 			   struct instruction_data *jmp_data,
12030 			   FILE *f)
12031 {
12032 	struct instruction_group *jmp_g, *g;
12033 	struct instruction_data *data;
12034 	uint32_t instr_id;
12035 
12036 	switch (jmp_instr->type) {
12037 	case INSTR_JMP:
12038 		break;
12039 
12040 	case INSTR_JMP_VALID:
12041 		fprintf(f,
12042 			"if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))",
12043 			jmp_instr_id);
12044 		break;
12045 
12046 	case INSTR_JMP_INVALID:
12047 		fprintf(f,
12048 			"if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))",
12049 			jmp_instr_id);
12050 		break;
12051 
12052 	case INSTR_JMP_HIT:
12053 		fprintf(f,
12054 			"if (t->hit)\n");
12055 		break;
12056 
12057 	case INSTR_JMP_MISS:
12058 		fprintf(f,
12059 			"if (!t->hit)\n");
12060 		break;
12061 
12062 	case INSTR_JMP_ACTION_HIT:
12063 		fprintf(f,
12064 			"if (t->action_id == pipeline_instructions[%u].jmp.action_id)",
12065 			jmp_instr_id);
12066 		break;
12067 
12068 	case INSTR_JMP_ACTION_MISS:
12069 		fprintf(f,
12070 			"if (t->action_id != pipeline_instructions[%u].jmp.action_id)",
12071 			jmp_instr_id);
12072 		break;
12073 
12074 	case INSTR_JMP_EQ:
12075 		fprintf(f,
12076 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == "
12077 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12078 			jmp_instr_id,
12079 			jmp_instr_id);
12080 		break;
12081 
12082 	case INSTR_JMP_EQ_MH:
12083 		fprintf(f,
12084 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == "
12085 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12086 			jmp_instr_id,
12087 			jmp_instr_id);
12088 		break;
12089 
12090 	case INSTR_JMP_EQ_HM:
12091 		fprintf(f,
12092 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == "
12093 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12094 			jmp_instr_id,
12095 			jmp_instr_id);
12096 		break;
12097 
12098 	case INSTR_JMP_EQ_HH:
12099 		fprintf(f,
12100 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == "
12101 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12102 			jmp_instr_id,
12103 			jmp_instr_id);
12104 		break;
12105 
12106 	case INSTR_JMP_EQ_I:
12107 		fprintf(f,
12108 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == "
12109 			"pipeline_instructions[%u].jmp.b_val)",
12110 			jmp_instr_id,
12111 			jmp_instr_id);
12112 		break;
12113 
12114 	case INSTR_JMP_NEQ:
12115 		fprintf(f,
12116 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != "
12117 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12118 			jmp_instr_id,
12119 			jmp_instr_id);
12120 		break;
12121 
12122 	case INSTR_JMP_NEQ_MH:
12123 		fprintf(f,
12124 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != "
12125 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12126 			jmp_instr_id,
12127 			jmp_instr_id);
12128 		break;
12129 
12130 	case INSTR_JMP_NEQ_HM:
12131 		fprintf(f,
12132 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != "
12133 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12134 			jmp_instr_id,
12135 			jmp_instr_id);
12136 		break;
12137 
12138 	case INSTR_JMP_NEQ_HH:
12139 		fprintf(f,
12140 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != "
12141 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12142 			jmp_instr_id,
12143 			jmp_instr_id);
12144 		break;
12145 
12146 	case INSTR_JMP_NEQ_I:
12147 		fprintf(f,
12148 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != "
12149 			"pipeline_instructions[%u].jmp.b_val)",
12150 			jmp_instr_id,
12151 			jmp_instr_id);
12152 		break;
12153 
12154 	case INSTR_JMP_LT:
12155 		fprintf(f,
12156 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < "
12157 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12158 			jmp_instr_id,
12159 			jmp_instr_id);
12160 		break;
12161 
12162 	case INSTR_JMP_LT_MH:
12163 		fprintf(f,
12164 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < "
12165 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12166 			jmp_instr_id,
12167 			jmp_instr_id);
12168 		break;
12169 
12170 	case INSTR_JMP_LT_HM:
12171 		fprintf(f,
12172 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < "
12173 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12174 			jmp_instr_id,
12175 			jmp_instr_id);
12176 		break;
12177 
12178 	case INSTR_JMP_LT_HH:
12179 		fprintf(f,
12180 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < "
12181 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12182 			jmp_instr_id,
12183 			jmp_instr_id);
12184 		break;
12185 
12186 	case INSTR_JMP_LT_MI:
12187 		fprintf(f,
12188 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < "
12189 			"pipeline_instructions[%u].jmp.b_val)",
12190 			jmp_instr_id,
12191 			jmp_instr_id);
12192 		break;
12193 
12194 	case INSTR_JMP_LT_HI:
12195 		fprintf(f,
12196 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < "
12197 			"pipeline_instructions[%u].jmp.b_val)",
12198 			jmp_instr_id,
12199 			jmp_instr_id);
12200 		break;
12201 
12202 	case INSTR_JMP_GT:
12203 		fprintf(f,
12204 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > "
12205 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12206 			jmp_instr_id,
12207 			jmp_instr_id);
12208 		break;
12209 
12210 	case INSTR_JMP_GT_MH:
12211 		fprintf(f,
12212 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > "
12213 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12214 			jmp_instr_id,
12215 			jmp_instr_id);
12216 		break;
12217 
12218 	case INSTR_JMP_GT_HM:
12219 		fprintf(f,
12220 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > "
12221 			"instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))",
12222 			jmp_instr_id,
12223 			jmp_instr_id);
12224 		break;
12225 
12226 	case INSTR_JMP_GT_HH:
12227 		fprintf(f,
12228 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > "
12229 			"instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))",
12230 			jmp_instr_id,
12231 			jmp_instr_id);
12232 		break;
12233 
12234 	case INSTR_JMP_GT_MI:
12235 		fprintf(f,
12236 			"if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > "
12237 			"pipeline_instructions[%u].jmp.b_val)",
12238 			jmp_instr_id,
12239 			jmp_instr_id);
12240 		break;
12241 
12242 	case INSTR_JMP_GT_HI:
12243 		fprintf(f,
12244 			"if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > "
12245 			"pipeline_instructions[%u].jmp.b_val)",
12246 			jmp_instr_id,
12247 			jmp_instr_id);
12248 		break;
12249 
12250 	default:
12251 		break;
12252 	}
12253 
12254 	/* Find the instruction group of the jump instruction. */
12255 	jmp_g = instruction_group_list_group_find(igl, jmp_instr_id);
12256 	if (!jmp_g)
12257 		return -EINVAL;
12258 
12259 	/* Find the instruction group of the jump destination instruction. */
12260 	data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label);
12261 	if (!data)
12262 		return -EINVAL;
12263 
12264 	instr_id = data - p->instruction_data;
12265 
12266 	g = instruction_group_list_group_find(igl, instr_id);
12267 	if (!g)
12268 		return -EINVAL;
12269 
12270 	/* Code generation for "near" jump (same instruction group) or "far" jump (different
12271 	 * instruction group).
12272 	 */
12273 	if (g->group_id == jmp_g->group_id)
12274 		fprintf(f,
12275 			"\n\t\tgoto %s;\n",
12276 			jmp_data->jmp_label);
12277 	else
12278 		fprintf(f,
12279 			" {\n"
12280 			"\t\tthread_ip_set(t, &p->instructions[%u]);\n"
12281 			"\t\treturn;\n"
12282 			"\t}\n\n",
12283 			g->group_id);
12284 
12285 	return 0;
12286 }
12287 
12288 static void
12289 instruction_group_list_codegen(struct instruction_group_list *igl,
12290 			       struct rte_swx_pipeline *p,
12291 			       FILE *f)
12292 {
12293 	struct instruction_group *g;
12294 	uint32_t i;
12295 	int is_required = 0;
12296 
12297 	/* Check if code generation is required. */
12298 	TAILQ_FOREACH(g, igl, node)
12299 		if (g->first_instr_id < g->last_instr_id)
12300 			is_required = 1;
12301 
12302 	if (!is_required)
12303 		return;
12304 
12305 	/* Generate the code for the pipeline instruction array. */
12306 	fprintf(f,
12307 		"static const struct instruction pipeline_instructions[] = {\n");
12308 
12309 	for (i = 0; i < p->n_instructions; i++) {
12310 		struct instruction *instr = &p->instructions[i];
12311 		instruction_export_t func = export_table[instr->type];
12312 
12313 		func(instr, f);
12314 	}
12315 
12316 	fprintf(f, "};\n\n");
12317 
12318 	/* Generate the code for the pipeline functions: one function for each instruction group
12319 	 * that contains more than one instruction.
12320 	 */
12321 	TAILQ_FOREACH(g, igl, node) {
12322 		struct instruction *last_instr;
12323 		uint32_t j;
12324 
12325 		/* Skip if group contains a single instruction. */
12326 		if (g->last_instr_id == g->first_instr_id)
12327 			continue;
12328 
12329 		/* Generate new pipeline function. */
12330 		fprintf(f,
12331 			"void\n"
12332 			"pipeline_func_%u(struct rte_swx_pipeline *p)\n"
12333 			"{\n"
12334 			"\tstruct thread *t = &p->threads[p->thread_id];\n"
12335 			"\n",
12336 			g->group_id);
12337 
12338 		/* Generate the code for each pipeline instruction. */
12339 		for (j = g->first_instr_id; j <= g->last_instr_id; j++) {
12340 			struct instruction *instr = &p->instructions[j];
12341 			struct instruction_data *data = &p->instruction_data[j];
12342 
12343 			/* Label, if present. */
12344 			if (data->label[0])
12345 				fprintf(f, "\n%s : ", data->label);
12346 			else
12347 				fprintf(f, "\n\t");
12348 
12349 			/* TX instruction type. */
12350 			if (instruction_does_tx(instr)) {
12351 				pipeline_instr_does_tx_codegen(p, j, instr, f);
12352 				continue;
12353 			}
12354 
12355 			/* Jump instruction type. */
12356 			if (instruction_is_jmp(instr)) {
12357 				pipeline_instr_jmp_codegen(p, igl, j, instr, data, f);
12358 				continue;
12359 			}
12360 
12361 			/* Any other instruction type. */
12362 			fprintf(f,
12363 				"%s(p, t, &pipeline_instructions[%u]);\n",
12364 				instr_type_to_func(instr),
12365 				j);
12366 		}
12367 
12368 		/* Finalize the generated pipeline function. For some instructions such as TX,
12369 		 * emit-many-and-TX and unconditional jump, the next instruction has been already
12370 		 * decided unconditionally and the instruction pointer of the current thread set
12371 		 * accordingly; for all the other instructions, the instruction pointer must be
12372 		 * incremented now.
12373 		 */
12374 		last_instr = &p->instructions[g->last_instr_id];
12375 
12376 		if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP))
12377 			fprintf(f,
12378 				"thread_ip_inc(p);\n");
12379 
12380 		fprintf(f,
12381 			"}\n"
12382 			"\n");
12383 	}
12384 }
12385 
12386 static uint32_t
12387 instruction_group_list_custom_instructions_count(struct instruction_group_list *igl)
12388 {
12389 	struct instruction_group *g;
12390 	uint32_t n_custom_instr = 0;
12391 
12392 	/* Groups with a single instruction: no function is generated for this group, the group
12393 	 * keeps its current instruction. Groups with more than two instructions: one function and
12394 	 * the associated custom instruction get generated for each such group.
12395 	 */
12396 	TAILQ_FOREACH(g, igl, node) {
12397 		if (g->first_instr_id == g->last_instr_id)
12398 			continue;
12399 
12400 		n_custom_instr++;
12401 	}
12402 
12403 	return n_custom_instr;
12404 }
12405 
12406 static int
12407 pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
12408 {
12409 	struct action *a;
12410 	FILE *f = NULL;
12411 
12412 	/* Create the .c file. */
12413 	f = fopen("/tmp/pipeline.c", "w");
12414 	if (!f)
12415 		return -EIO;
12416 
12417 	/* Include the .h file. */
12418 	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
12419 
12420 	/* Add the code for each action. */
12421 	TAILQ_FOREACH(a, &p->actions, node) {
12422 		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
12423 
12424 		action_data_codegen(a, f);
12425 
12426 		fprintf(f, "\n");
12427 
12428 		action_instr_codegen(a, f);
12429 
12430 		fprintf(f, "\n");
12431 	}
12432 
12433 	/* Add the pipeline code. */
12434 	instruction_group_list_codegen(igl, p, f);
12435 
12436 	/* Close the .c file. */
12437 	fclose(f);
12438 
12439 	return 0;
12440 }
12441 
12442 #ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
12443 #define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
12444 #endif
12445 
12446 static int
12447 pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
12448 {
12449 	struct action *a;
12450 	struct instruction_group *g;
12451 	char *dir_in, *buffer = NULL;
12452 	const char *dir_out;
12453 	int status = 0;
12454 
12455 	/* Get the environment variables. */
12456 	dir_in = getenv("RTE_INSTALL_DIR");
12457 	if (!dir_in) {
12458 		status = -EINVAL;
12459 		goto free;
12460 	}
12461 
12462 	dir_out = "/tmp";
12463 
12464 	/* Memory allocation for the command buffer. */
12465 	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
12466 	if (!buffer) {
12467 		status = -ENOMEM;
12468 		goto free;
12469 	}
12470 
12471 	snprintf(buffer,
12472 		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
12473 		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
12474 		 "-I %s/lib/pipeline "
12475 		 "-I %s/lib/eal/include "
12476 		 "-I %s/lib/eal/x86/include "
12477 		 "-I %s/lib/eal/include/generic "
12478 		 "-I %s/lib/meter "
12479 		 "-I %s/lib/port "
12480 		 "-I %s/lib/table "
12481 		 "-I %s/lib/pipeline "
12482 		 "-I %s/config "
12483 		 "-I %s/build "
12484 		 "-I %s/lib/eal/linux/include "
12485 		 ">%s/pipeline.log 2>&1 "
12486 		 "&& "
12487 		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
12488 		 ">>%s/pipeline.log 2>&1",
12489 		 dir_out,
12490 		 dir_out,
12491 		 dir_in,
12492 		 dir_in,
12493 		 dir_in,
12494 		 dir_in,
12495 		 dir_in,
12496 		 dir_in,
12497 		 dir_in,
12498 		 dir_in,
12499 		 dir_in,
12500 		 dir_in,
12501 		 dir_in,
12502 		 dir_out,
12503 		 dir_out,
12504 		 dir_out,
12505 		 dir_out);
12506 
12507 	/* Build the shared object library. */
12508 	status = system(buffer);
12509 	if (status)
12510 		goto free;
12511 
12512 	/* Open library. */
12513 	snprintf(buffer,
12514 		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
12515 		 "%s/libpipeline.so",
12516 		 dir_out);
12517 
12518 	p->lib = dlopen(buffer, RTLD_LAZY);
12519 	if (!p->lib) {
12520 		status = -EIO;
12521 		goto free;
12522 	}
12523 
12524 	/* Get the action function symbols. */
12525 	TAILQ_FOREACH(a, &p->actions, node) {
12526 		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
12527 
12528 		p->action_funcs[a->id] = dlsym(p->lib, buffer);
12529 		if (!p->action_funcs[a->id]) {
12530 			status = -EINVAL;
12531 			goto free;
12532 		}
12533 	}
12534 
12535 	/* Get the pipeline function symbols. */
12536 	TAILQ_FOREACH(g, igl, node) {
12537 		if (g->first_instr_id == g->last_instr_id)
12538 			continue;
12539 
12540 		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
12541 
12542 		g->func = dlsym(p->lib, buffer);
12543 		if (!g->func) {
12544 			status = -EINVAL;
12545 			goto free;
12546 		}
12547 	}
12548 
12549 free:
12550 	if (status && p->lib) {
12551 		dlclose(p->lib);
12552 		p->lib = NULL;
12553 	}
12554 
12555 	free(buffer);
12556 
12557 	return status;
12558 }
12559 
12560 static int
12561 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
12562 		      struct instruction_group_list *igl)
12563 {
12564 	uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl);
12565 
12566 	/* Check that enough space is available within the pipeline instruction table to store all
12567 	 * the custom instructions.
12568 	 */
12569 	if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX)
12570 		return -ENOSPC;
12571 
12572 	return 0;
12573 }
12574 
12575 static void
12576 pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
12577 {
12578 	struct instruction_group *g;
12579 	uint32_t i;
12580 
12581 	/* Pipeline table instructions. */
12582 	for (i = 0; i < p->n_instructions; i++) {
12583 		struct instruction *instr = &p->instructions[i];
12584 
12585 		if (instr->type == INSTR_TABLE)
12586 			instr->type = INSTR_TABLE_AF;
12587 
12588 		if (instr->type == INSTR_LEARNER)
12589 			instr->type = INSTR_LEARNER_AF;
12590 	}
12591 
12592 	/* Pipeline custom instructions. */
12593 	i = 0;
12594 	TAILQ_FOREACH(g, igl, node) {
12595 		struct instruction *instr = &p->instructions[g->first_instr_id];
12596 		uint32_t j;
12597 
12598 		if (g->first_instr_id == g->last_instr_id)
12599 			continue;
12600 
12601 		/* Install a new custom instruction. */
12602 		p->instruction_table[INSTR_CUSTOM_0 + i] = g->func;
12603 
12604 		/* First instruction of the group: change its type to the new custom instruction. */
12605 		instr->type = INSTR_CUSTOM_0 + i;
12606 
12607 		/* All the subsequent instructions of the group: invalidate. */
12608 		for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) {
12609 			struct instruction_data *data = &p->instruction_data[j];
12610 
12611 			data->invalid = 1;
12612 		}
12613 
12614 		i++;
12615 	}
12616 
12617 	/* Remove the invalidated instructions. */
12618 	p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions);
12619 
12620 	/* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump
12621 	 * instructions that are the only instruction within their group, so they were left
12622 	 * unmodified).
12623 	 */
12624 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
12625 }
12626 
12627 static int
12628 pipeline_compile(struct rte_swx_pipeline *p)
12629 {
12630 	struct instruction_group_list *igl = NULL;
12631 	int status = 0;
12632 
12633 	igl = instruction_group_list_create(p);
12634 	if (!igl) {
12635 		status = -ENOMEM;
12636 		goto free;
12637 	}
12638 
12639 	/* Code generation. */
12640 	status = pipeline_codegen(p, igl);
12641 	if (status)
12642 		goto free;
12643 
12644 	/* Build and load the shared object library. */
12645 	status = pipeline_libload(p, igl);
12646 	if (status)
12647 		goto free;
12648 
12649 	/* Adjust instructions. */
12650 	status = pipeline_adjust_check(p, igl);
12651 	if (status)
12652 		goto free;
12653 
12654 	pipeline_adjust(p, igl);
12655 
12656 free:
12657 	instruction_group_list_free(igl);
12658 
12659 	return status;
12660 }
12661