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