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