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