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