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