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