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