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