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