[V3,01/24] pipeline: move data structures to internal header file

Message ID 20210913164443.16875-1-cristian.dumitrescu@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Thomas Monjalon
Headers
Series [V3,01/24] pipeline: move data structures to internal header file |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-testing warning apply patch failure

Commit Message

Cristian Dumitrescu Sept. 13, 2021, 4:44 p.m. UTC
  Start to consolidate the data structures and inline functions required
by the pipeline instructions into an internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
Depends-on: series-18297 ("[V4,1/4] table: add support learner tables")

V3:
-fixed meson.build

 lib/pipeline/rte_swx_pipeline.c          | 1373 +--------------------
 lib/pipeline/rte_swx_pipeline_internal.h | 1383 ++++++++++++++++++++++
 2 files changed, 1384 insertions(+), 1372 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_internal.h
  

Comments

Stephen Hemminger Sept. 13, 2021, 4:51 p.m. UTC | #1
On Mon, 13 Sep 2021 17:44:20 +0100
Cristian Dumitrescu <cristian.dumitrescu@intel.com> wrote:

> Start to consolidate the data structures and inline functions required
> by the pipeline instructions into an internal header file.
> 
> Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> ---
> Depends-on: series-18297 ("[V4,1/4] table: add support learner tables")

Won't this change will make future changes to API/ABI harder because more
of the pipeline internals are exposed to application?
  
Cristian Dumitrescu Sept. 13, 2021, 6:42 p.m. UTC | #2
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Monday, September 13, 2021 5:51 PM
> To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH V3 01/24] pipeline: move data structures to
> internal header file
> 
> On Mon, 13 Sep 2021 17:44:20 +0100
> Cristian Dumitrescu <cristian.dumitrescu@intel.com> wrote:
> 
> > Start to consolidate the data structures and inline functions required
> > by the pipeline instructions into an internal header file.
> >
> > Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> > ---
> > Depends-on: series-18297 ("[V4,1/4] table: add support learner tables")
> 
> Won't this change will make future changes to API/ABI harder because more
> of the pipeline internals are exposed to application?

Not at all, this header file is internal to the library and not accessible to the application.
  
Stephen Hemminger Sept. 13, 2021, 7:02 p.m. UTC | #3
On Mon, 13 Sep 2021 18:42:39 +0000
"Dumitrescu, Cristian" <cristian.dumitrescu@intel.com> wrote:

> > -----Original Message-----
> > From: Stephen Hemminger <stephen@networkplumber.org>
> > Sent: Monday, September 13, 2021 5:51 PM
> > To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH V3 01/24] pipeline: move data structures to
> > internal header file
> > 
> > On Mon, 13 Sep 2021 17:44:20 +0100
> > Cristian Dumitrescu <cristian.dumitrescu@intel.com> wrote:
> >   
> > > Start to consolidate the data structures and inline functions required
> > > by the pipeline instructions into an internal header file.
> > >
> > > Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> > > ---
> > > Depends-on: series-18297 ("[V4,1/4] table: add support learner tables")  
> > 
> > Won't this change will make future changes to API/ABI harder because more
> > of the pipeline internals are exposed to application?  
> 
> Not at all, this header file is internal to the library and not accessible to the application.

Good
  
Cristian Dumitrescu Sept. 20, 2021, 3:24 p.m. UTC | #4
> Depends-on: series-18297 ("[V4,1/4] table: add support learner tables")

Just sent an updated version for the learner table series, which does not result in any code changes for this patch set. Therefore, the updated dependency list of this patch set is:

Depends-on: series-19048 ("[V5,1/4] table: add support learner tables")

Thanks,
Cristian
  
Thomas Monjalon Sept. 27, 2021, 10:11 a.m. UTC | #5
13/09/2021 18:44, Cristian Dumitrescu:
> Start to consolidate the data structures and inline functions required
> by the pipeline instructions into an internal header file.
> 
> Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Series applied, thanks.
  

Patch

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index f89a134a52..ae9b2056db 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -2,24 +2,11 @@ 
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdlib.h>
-#include <string.h>
 #include <stdio.h>
 #include <errno.h>
-#include <inttypes.h>
-#include <sys/queue.h>
 #include <arpa/inet.h>
 
-#include <rte_common.h>
-#include <rte_prefetch.h>
-#include <rte_byteorder.h>
-#include <rte_cycles.h>
-#include <rte_meter.h>
-
-#include <rte_swx_table_selector.h>
-#include <rte_swx_table_learner.h>
-
-#include "rte_swx_pipeline.h"
-#include "rte_swx_ctl.h"
+#include "rte_swx_pipeline_internal.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -40,22 +27,9 @@  do {                                                                           \
 	       RTE_SWX_INSTRUCTION_SIZE),                                      \
 	      err_code)
 
-#ifndef TRACE_LEVEL
-#define TRACE_LEVEL 0
-#endif
-
-#if TRACE_LEVEL
-#define TRACE(...) printf(__VA_ARGS__)
-#else
-#define TRACE(...)
-#endif
-
 /*
  * Environment.
  */
-#define ntoh64(x) rte_be_to_cpu_64(x)
-#define hton64(x) rte_cpu_to_be_64(x)
-
 #ifndef RTE_SWX_PIPELINE_HUGE_PAGES_DISABLE
 
 #include <rte_malloc.h>
@@ -103,1351 +77,6 @@  env_free(void *start, size_t size)
 
 #endif
 
-/*
- * Struct.
- */
-struct field {
-	char name[RTE_SWX_NAME_SIZE];
-	uint32_t n_bits;
-	uint32_t offset;
-	int var_size;
-};
-
-struct struct_type {
-	TAILQ_ENTRY(struct_type) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct field *fields;
-	uint32_t n_fields;
-	uint32_t n_bits;
-	uint32_t n_bits_min;
-	int var_size;
-};
-
-TAILQ_HEAD(struct_type_tailq, struct_type);
-
-/*
- * Input port.
- */
-struct port_in_type {
-	TAILQ_ENTRY(port_in_type) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct rte_swx_port_in_ops ops;
-};
-
-TAILQ_HEAD(port_in_type_tailq, port_in_type);
-
-struct port_in {
-	TAILQ_ENTRY(port_in) node;
-	struct port_in_type *type;
-	void *obj;
-	uint32_t id;
-};
-
-TAILQ_HEAD(port_in_tailq, port_in);
-
-struct port_in_runtime {
-	rte_swx_port_in_pkt_rx_t pkt_rx;
-	void *obj;
-};
-
-/*
- * Output port.
- */
-struct port_out_type {
-	TAILQ_ENTRY(port_out_type) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct rte_swx_port_out_ops ops;
-};
-
-TAILQ_HEAD(port_out_type_tailq, port_out_type);
-
-struct port_out {
-	TAILQ_ENTRY(port_out) node;
-	struct port_out_type *type;
-	void *obj;
-	uint32_t id;
-};
-
-TAILQ_HEAD(port_out_tailq, port_out);
-
-struct port_out_runtime {
-	rte_swx_port_out_pkt_tx_t pkt_tx;
-	rte_swx_port_out_flush_t flush;
-	void *obj;
-};
-
-/*
- * Extern object.
- */
-struct extern_type_member_func {
-	TAILQ_ENTRY(extern_type_member_func) node;
-	char name[RTE_SWX_NAME_SIZE];
-	rte_swx_extern_type_member_func_t func;
-	uint32_t id;
-};
-
-TAILQ_HEAD(extern_type_member_func_tailq, extern_type_member_func);
-
-struct extern_type {
-	TAILQ_ENTRY(extern_type) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct struct_type *mailbox_struct_type;
-	rte_swx_extern_type_constructor_t constructor;
-	rte_swx_extern_type_destructor_t destructor;
-	struct extern_type_member_func_tailq funcs;
-	uint32_t n_funcs;
-};
-
-TAILQ_HEAD(extern_type_tailq, extern_type);
-
-struct extern_obj {
-	TAILQ_ENTRY(extern_obj) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct extern_type *type;
-	void *obj;
-	uint32_t struct_id;
-	uint32_t id;
-};
-
-TAILQ_HEAD(extern_obj_tailq, extern_obj);
-
-#ifndef RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX
-#define RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX 8
-#endif
-
-struct extern_obj_runtime {
-	void *obj;
-	uint8_t *mailbox;
-	rte_swx_extern_type_member_func_t funcs[RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX];
-};
-
-/*
- * Extern function.
- */
-struct extern_func {
-	TAILQ_ENTRY(extern_func) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct struct_type *mailbox_struct_type;
-	rte_swx_extern_func_t func;
-	uint32_t struct_id;
-	uint32_t id;
-};
-
-TAILQ_HEAD(extern_func_tailq, extern_func);
-
-struct extern_func_runtime {
-	uint8_t *mailbox;
-	rte_swx_extern_func_t func;
-};
-
-/*
- * Header.
- */
-struct header {
-	TAILQ_ENTRY(header) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct struct_type *st;
-	uint32_t struct_id;
-	uint32_t id;
-};
-
-TAILQ_HEAD(header_tailq, header);
-
-struct header_runtime {
-	uint8_t *ptr0;
-	uint32_t n_bytes;
-};
-
-struct header_out_runtime {
-	uint8_t *ptr0;
-	uint8_t *ptr;
-	uint32_t n_bytes;
-};
-
-/*
- * Instruction.
- */
-
-/* Packet headers are always in Network Byte Order (NBO), i.e. big endian.
- * Packet meta-data fields are always assumed to be in Host Byte Order (HBO).
- * Table entry fields can be in either NBO or HBO; they are assumed to be in HBO
- * when transferred to packet meta-data and in NBO when transferred to packet
- * headers.
- */
-
-/* Notation conventions:
- *    -Header field: H = h.header.field (dst/src)
- *    -Meta-data field: M = m.field (dst/src)
- *    -Extern object mailbox field: E = e.field (dst/src)
- *    -Extern function mailbox field: F = f.field (dst/src)
- *    -Table action data field: T = t.field (src only)
- *    -Immediate value: I = 32-bit unsigned value (src only)
- */
-
-enum instruction_type {
-	/* rx m.port_in */
-	INSTR_RX,
-
-	/* tx port_out
-	 * port_out = MI
-	 */
-	INSTR_TX,   /* port_out = M */
-	INSTR_TX_I, /* port_out = I */
-
-	/* extract h.header */
-	INSTR_HDR_EXTRACT,
-	INSTR_HDR_EXTRACT2,
-	INSTR_HDR_EXTRACT3,
-	INSTR_HDR_EXTRACT4,
-	INSTR_HDR_EXTRACT5,
-	INSTR_HDR_EXTRACT6,
-	INSTR_HDR_EXTRACT7,
-	INSTR_HDR_EXTRACT8,
-
-	/* extract h.header m.last_field_size */
-	INSTR_HDR_EXTRACT_M,
-
-	/* lookahead h.header */
-	INSTR_HDR_LOOKAHEAD,
-
-	/* emit h.header */
-	INSTR_HDR_EMIT,
-	INSTR_HDR_EMIT_TX,
-	INSTR_HDR_EMIT2_TX,
-	INSTR_HDR_EMIT3_TX,
-	INSTR_HDR_EMIT4_TX,
-	INSTR_HDR_EMIT5_TX,
-	INSTR_HDR_EMIT6_TX,
-	INSTR_HDR_EMIT7_TX,
-	INSTR_HDR_EMIT8_TX,
-
-	/* validate h.header */
-	INSTR_HDR_VALIDATE,
-
-	/* invalidate h.header */
-	INSTR_HDR_INVALIDATE,
-
-	/* mov dst src
-	 * dst = src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_MOV,    /* dst = MEF, src = MEFT */
-	INSTR_MOV_MH, /* dst = MEF, src = H */
-	INSTR_MOV_HM, /* dst = H, src = MEFT */
-	INSTR_MOV_HH, /* dst = H, src = H */
-	INSTR_MOV_I,  /* dst = HMEF, src = I */
-
-	/* dma h.header t.field
-	 * memcpy(h.header, t.field, sizeof(h.header))
-	 */
-	INSTR_DMA_HT,
-	INSTR_DMA_HT2,
-	INSTR_DMA_HT3,
-	INSTR_DMA_HT4,
-	INSTR_DMA_HT5,
-	INSTR_DMA_HT6,
-	INSTR_DMA_HT7,
-	INSTR_DMA_HT8,
-
-	/* add dst src
-	 * dst += src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_ADD,    /* dst = MEF, src = MEF */
-	INSTR_ALU_ADD_MH, /* dst = MEF, src = H */
-	INSTR_ALU_ADD_HM, /* dst = H, src = MEF */
-	INSTR_ALU_ADD_HH, /* dst = H, src = H */
-	INSTR_ALU_ADD_MI, /* dst = MEF, src = I */
-	INSTR_ALU_ADD_HI, /* dst = H, src = I */
-
-	/* sub dst src
-	 * dst -= src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_SUB,    /* dst = MEF, src = MEF */
-	INSTR_ALU_SUB_MH, /* dst = MEF, src = H */
-	INSTR_ALU_SUB_HM, /* dst = H, src = MEF */
-	INSTR_ALU_SUB_HH, /* dst = H, src = H */
-	INSTR_ALU_SUB_MI, /* dst = MEF, src = I */
-	INSTR_ALU_SUB_HI, /* dst = H, src = I */
-
-	/* ckadd dst src
-	 * dst = dst '+ src[0:1] '+ src[2:3] + ...
-	 * dst = H, src = {H, h.header}
-	 */
-	INSTR_ALU_CKADD_FIELD,    /* src = H */
-	INSTR_ALU_CKADD_STRUCT20, /* src = h.header, with sizeof(header) = 20 */
-	INSTR_ALU_CKADD_STRUCT,   /* src = h.hdeader, with any sizeof(header) */
-
-	/* cksub dst src
-	 * dst = dst '- src
-	 * dst = H, src = H
-	 */
-	INSTR_ALU_CKSUB_FIELD,
-
-	/* and dst src
-	 * dst &= src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_AND,    /* dst = MEF, src = MEFT */
-	INSTR_ALU_AND_MH, /* dst = MEF, src = H */
-	INSTR_ALU_AND_HM, /* dst = H, src = MEFT */
-	INSTR_ALU_AND_HH, /* dst = H, src = H */
-	INSTR_ALU_AND_I,  /* dst = HMEF, src = I */
-
-	/* or dst src
-	 * dst |= src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_OR,    /* dst = MEF, src = MEFT */
-	INSTR_ALU_OR_MH, /* dst = MEF, src = H */
-	INSTR_ALU_OR_HM, /* dst = H, src = MEFT */
-	INSTR_ALU_OR_HH, /* dst = H, src = H */
-	INSTR_ALU_OR_I,  /* dst = HMEF, src = I */
-
-	/* xor dst src
-	 * dst ^= src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_XOR,    /* dst = MEF, src = MEFT */
-	INSTR_ALU_XOR_MH, /* dst = MEF, src = H */
-	INSTR_ALU_XOR_HM, /* dst = H, src = MEFT */
-	INSTR_ALU_XOR_HH, /* dst = H, src = H */
-	INSTR_ALU_XOR_I,  /* dst = HMEF, src = I */
-
-	/* shl dst src
-	 * dst <<= src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_SHL,    /* dst = MEF, src = MEF */
-	INSTR_ALU_SHL_MH, /* dst = MEF, src = H */
-	INSTR_ALU_SHL_HM, /* dst = H, src = MEF */
-	INSTR_ALU_SHL_HH, /* dst = H, src = H */
-	INSTR_ALU_SHL_MI, /* dst = MEF, src = I */
-	INSTR_ALU_SHL_HI, /* dst = H, src = I */
-
-	/* shr dst src
-	 * dst >>= src
-	 * dst = HMEF, src = HMEFTI
-	 */
-	INSTR_ALU_SHR,    /* dst = MEF, src = MEF */
-	INSTR_ALU_SHR_MH, /* dst = MEF, src = H */
-	INSTR_ALU_SHR_HM, /* dst = H, src = MEF */
-	INSTR_ALU_SHR_HH, /* dst = H, src = H */
-	INSTR_ALU_SHR_MI, /* dst = MEF, src = I */
-	INSTR_ALU_SHR_HI, /* dst = H, src = I */
-
-	/* regprefetch REGARRAY index
-	 * prefetch REGARRAY[index]
-	 * index = HMEFTI
-	 */
-	INSTR_REGPREFETCH_RH, /* index = H */
-	INSTR_REGPREFETCH_RM, /* index = MEFT */
-	INSTR_REGPREFETCH_RI, /* index = I */
-
-	/* regrd dst REGARRAY index
-	 * dst = REGARRAY[index]
-	 * dst = HMEF, index = HMEFTI
-	 */
-	INSTR_REGRD_HRH, /* dst = H, index = H */
-	INSTR_REGRD_HRM, /* dst = H, index = MEFT */
-	INSTR_REGRD_HRI, /* dst = H, index = I */
-	INSTR_REGRD_MRH, /* dst = MEF, index = H */
-	INSTR_REGRD_MRM, /* dst = MEF, index = MEFT */
-	INSTR_REGRD_MRI, /* dst = MEF, index = I */
-
-	/* regwr REGARRAY index src
-	 * REGARRAY[index] = src
-	 * index = HMEFTI, src = HMEFTI
-	 */
-	INSTR_REGWR_RHH, /* index = H, src = H */
-	INSTR_REGWR_RHM, /* index = H, src = MEFT */
-	INSTR_REGWR_RHI, /* index = H, src = I */
-	INSTR_REGWR_RMH, /* index = MEFT, src = H */
-	INSTR_REGWR_RMM, /* index = MEFT, src = MEFT */
-	INSTR_REGWR_RMI, /* index = MEFT, src = I */
-	INSTR_REGWR_RIH, /* index = I, src = H */
-	INSTR_REGWR_RIM, /* index = I, src = MEFT */
-	INSTR_REGWR_RII, /* index = I, src = I */
-
-	/* regadd REGARRAY index src
-	 * REGARRAY[index] += src
-	 * index = HMEFTI, src = HMEFTI
-	 */
-	INSTR_REGADD_RHH, /* index = H, src = H */
-	INSTR_REGADD_RHM, /* index = H, src = MEFT */
-	INSTR_REGADD_RHI, /* index = H, src = I */
-	INSTR_REGADD_RMH, /* index = MEFT, src = H */
-	INSTR_REGADD_RMM, /* index = MEFT, src = MEFT */
-	INSTR_REGADD_RMI, /* index = MEFT, src = I */
-	INSTR_REGADD_RIH, /* index = I, src = H */
-	INSTR_REGADD_RIM, /* index = I, src = MEFT */
-	INSTR_REGADD_RII, /* index = I, src = I */
-
-	/* metprefetch METARRAY index
-	 * prefetch METARRAY[index]
-	 * index = HMEFTI
-	 */
-	INSTR_METPREFETCH_H, /* index = H */
-	INSTR_METPREFETCH_M, /* index = MEFT */
-	INSTR_METPREFETCH_I, /* index = I */
-
-	/* meter METARRAY index length color_in color_out
-	 * color_out = meter(METARRAY[index], length, color_in)
-	 * index = HMEFTI, length = HMEFT, color_in = MEFTI, color_out = MEF
-	 */
-	INSTR_METER_HHM, /* index = H, length = H, color_in = MEFT */
-	INSTR_METER_HHI, /* index = H, length = H, color_in = I */
-	INSTR_METER_HMM, /* index = H, length = MEFT, color_in = MEFT */
-	INSTR_METER_HMI, /* index = H, length = MEFT, color_in = I */
-	INSTR_METER_MHM, /* index = MEFT, length = H, color_in = MEFT */
-	INSTR_METER_MHI, /* index = MEFT, length = H, color_in = I */
-	INSTR_METER_MMM, /* index = MEFT, length = MEFT, color_in = MEFT */
-	INSTR_METER_MMI, /* index = MEFT, length = MEFT, color_in = I */
-	INSTR_METER_IHM, /* index = I, length = H, color_in = MEFT */
-	INSTR_METER_IHI, /* index = I, length = H, color_in = I */
-	INSTR_METER_IMM, /* index = I, length = MEFT, color_in = MEFT */
-	INSTR_METER_IMI, /* index = I, length = MEFT, color_in = I */
-
-	/* table TABLE */
-	INSTR_TABLE,
-	INSTR_SELECTOR,
-	INSTR_LEARNER,
-
-	/* learn LEARNER ACTION_NAME */
-	INSTR_LEARNER_LEARN,
-
-	/* forget */
-	INSTR_LEARNER_FORGET,
-
-	/* extern e.obj.func */
-	INSTR_EXTERN_OBJ,
-
-	/* extern f.func */
-	INSTR_EXTERN_FUNC,
-
-	/* jmp LABEL
-	 * Unconditional jump
-	 */
-	INSTR_JMP,
-
-	/* jmpv LABEL h.header
-	 * Jump if header is valid
-	 */
-	INSTR_JMP_VALID,
-
-	/* jmpnv LABEL h.header
-	 * Jump if header is invalid
-	 */
-	INSTR_JMP_INVALID,
-
-	/* jmph LABEL
-	 * Jump if table lookup hit
-	 */
-	INSTR_JMP_HIT,
-
-	/* jmpnh LABEL
-	 * Jump if table lookup miss
-	 */
-	INSTR_JMP_MISS,
-
-	/* jmpa LABEL ACTION
-	 * Jump if action run
-	 */
-	INSTR_JMP_ACTION_HIT,
-
-	/* jmpna LABEL ACTION
-	 * Jump if action not run
-	 */
-	INSTR_JMP_ACTION_MISS,
-
-	/* jmpeq LABEL a b
-	 * Jump if a is equal to b
-	 * a = HMEFT, b = HMEFTI
-	 */
-	INSTR_JMP_EQ,    /* a = MEFT, b = MEFT */
-	INSTR_JMP_EQ_MH, /* a = MEFT, b = H */
-	INSTR_JMP_EQ_HM, /* a = H, b = MEFT */
-	INSTR_JMP_EQ_HH, /* a = H, b = H */
-	INSTR_JMP_EQ_I,  /* (a, b) = (MEFT, I) or (a, b) = (H, I) */
-
-	/* jmpneq LABEL a b
-	 * Jump if a is not equal to b
-	 * a = HMEFT, b = HMEFTI
-	 */
-	INSTR_JMP_NEQ,    /* a = MEFT, b = MEFT */
-	INSTR_JMP_NEQ_MH, /* a = MEFT, b = H */
-	INSTR_JMP_NEQ_HM, /* a = H, b = MEFT */
-	INSTR_JMP_NEQ_HH, /* a = H, b = H */
-	INSTR_JMP_NEQ_I,  /* (a, b) = (MEFT, I) or (a, b) = (H, I) */
-
-	/* jmplt LABEL a b
-	 * Jump if a is less than b
-	 * a = HMEFT, b = HMEFTI
-	 */
-	INSTR_JMP_LT,    /* a = MEFT, b = MEFT */
-	INSTR_JMP_LT_MH, /* a = MEFT, b = H */
-	INSTR_JMP_LT_HM, /* a = H, b = MEFT */
-	INSTR_JMP_LT_HH, /* a = H, b = H */
-	INSTR_JMP_LT_MI, /* a = MEFT, b = I */
-	INSTR_JMP_LT_HI, /* a = H, b = I */
-
-	/* jmpgt LABEL a b
-	 * Jump if a is greater than b
-	 * a = HMEFT, b = HMEFTI
-	 */
-	INSTR_JMP_GT,    /* a = MEFT, b = MEFT */
-	INSTR_JMP_GT_MH, /* a = MEFT, b = H */
-	INSTR_JMP_GT_HM, /* a = H, b = MEFT */
-	INSTR_JMP_GT_HH, /* a = H, b = H */
-	INSTR_JMP_GT_MI, /* a = MEFT, b = I */
-	INSTR_JMP_GT_HI, /* a = H, b = I */
-
-	/* return
-	 * Return from action
-	 */
-	INSTR_RETURN,
-};
-
-struct instr_operand {
-	uint8_t struct_id;
-	uint8_t n_bits;
-	uint8_t offset;
-	uint8_t pad;
-};
-
-struct instr_io {
-	struct {
-		union {
-			struct {
-				uint8_t offset;
-				uint8_t n_bits;
-				uint8_t pad[2];
-			};
-
-			uint32_t val;
-		};
-	} io;
-
-	struct {
-		uint8_t header_id[8];
-		uint8_t struct_id[8];
-		uint8_t n_bytes[8];
-	} hdr;
-};
-
-struct instr_hdr_validity {
-	uint8_t header_id;
-};
-
-struct instr_table {
-	uint8_t table_id;
-};
-
-struct instr_learn {
-	uint8_t action_id;
-};
-
-struct instr_extern_obj {
-	uint8_t ext_obj_id;
-	uint8_t func_id;
-};
-
-struct instr_extern_func {
-	uint8_t ext_func_id;
-};
-
-struct instr_dst_src {
-	struct instr_operand dst;
-	union {
-		struct instr_operand src;
-		uint64_t src_val;
-	};
-};
-
-struct instr_regarray {
-	uint8_t regarray_id;
-	uint8_t pad[3];
-
-	union {
-		struct instr_operand idx;
-		uint32_t idx_val;
-	};
-
-	union {
-		struct instr_operand dstsrc;
-		uint64_t dstsrc_val;
-	};
-};
-
-struct instr_meter {
-	uint8_t metarray_id;
-	uint8_t pad[3];
-
-	union {
-		struct instr_operand idx;
-		uint32_t idx_val;
-	};
-
-	struct instr_operand length;
-
-	union {
-		struct instr_operand color_in;
-		uint32_t color_in_val;
-	};
-
-	struct instr_operand color_out;
-};
-
-struct instr_dma {
-	struct {
-		uint8_t header_id[8];
-		uint8_t struct_id[8];
-	} dst;
-
-	struct {
-		uint8_t offset[8];
-	} src;
-
-	uint16_t n_bytes[8];
-};
-
-struct instr_jmp {
-	struct instruction *ip;
-
-	union {
-		struct instr_operand a;
-		uint8_t header_id;
-		uint8_t action_id;
-	};
-
-	union {
-		struct instr_operand b;
-		uint64_t b_val;
-	};
-};
-
-struct instruction {
-	enum instruction_type type;
-	union {
-		struct instr_io io;
-		struct instr_hdr_validity valid;
-		struct instr_dst_src mov;
-		struct instr_regarray regarray;
-		struct instr_meter meter;
-		struct instr_dma dma;
-		struct instr_dst_src alu;
-		struct instr_table table;
-		struct instr_learn learn;
-		struct instr_extern_obj ext_obj;
-		struct instr_extern_func ext_func;
-		struct instr_jmp jmp;
-	};
-};
-
-struct instruction_data {
-	char label[RTE_SWX_NAME_SIZE];
-	char jmp_label[RTE_SWX_NAME_SIZE];
-	uint32_t n_users; /* user = jmp instruction to this instruction. */
-	int invalid;
-};
-
-/*
- * Action.
- */
-struct action {
-	TAILQ_ENTRY(action) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct struct_type *st;
-	int *args_endianness; /* 0 = Host Byte Order (HBO); 1 = Network Byte Order (NBO). */
-	struct instruction *instructions;
-	uint32_t n_instructions;
-	uint32_t id;
-};
-
-TAILQ_HEAD(action_tailq, action);
-
-/*
- * Table.
- */
-struct table_type {
-	TAILQ_ENTRY(table_type) node;
-	char name[RTE_SWX_NAME_SIZE];
-	enum rte_swx_table_match_type match_type;
-	struct rte_swx_table_ops ops;
-};
-
-TAILQ_HEAD(table_type_tailq, table_type);
-
-struct match_field {
-	enum rte_swx_table_match_type match_type;
-	struct field *field;
-};
-
-struct table {
-	TAILQ_ENTRY(table) node;
-	char name[RTE_SWX_NAME_SIZE];
-	char args[RTE_SWX_NAME_SIZE];
-	struct table_type *type; /* NULL when n_fields == 0. */
-
-	/* Match. */
-	struct match_field *fields;
-	uint32_t n_fields;
-	struct header *header; /* Only valid when n_fields > 0. */
-
-	/* Action. */
-	struct action **actions;
-	struct action *default_action;
-	uint8_t *default_action_data;
-	uint32_t n_actions;
-	int default_action_is_const;
-	uint32_t action_data_size_max;
-
-	uint32_t size;
-	uint32_t id;
-};
-
-TAILQ_HEAD(table_tailq, table);
-
-struct table_runtime {
-	rte_swx_table_lookup_t func;
-	void *mailbox;
-	uint8_t **key;
-};
-
-struct table_statistics {
-	uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */
-	uint64_t *n_pkts_action;
-};
-
-/*
- * Selector.
- */
-struct selector {
-	TAILQ_ENTRY(selector) node;
-	char name[RTE_SWX_NAME_SIZE];
-
-	struct field *group_id_field;
-	struct field **selector_fields;
-	uint32_t n_selector_fields;
-	struct header *selector_header;
-	struct field *member_id_field;
-
-	uint32_t n_groups_max;
-	uint32_t n_members_per_group_max;
-
-	uint32_t id;
-};
-
-TAILQ_HEAD(selector_tailq, selector);
-
-struct selector_runtime {
-	void *mailbox;
-	uint8_t **group_id_buffer;
-	uint8_t **selector_buffer;
-	uint8_t **member_id_buffer;
-};
-
-struct selector_statistics {
-	uint64_t n_pkts;
-};
-
-/*
- * Learner table.
- */
-struct learner {
-	TAILQ_ENTRY(learner) node;
-	char name[RTE_SWX_NAME_SIZE];
-
-	/* Match. */
-	struct field **fields;
-	uint32_t n_fields;
-	struct header *header;
-
-	/* Action. */
-	struct action **actions;
-	struct field **action_arg;
-	struct action *default_action;
-	uint8_t *default_action_data;
-	uint32_t n_actions;
-	int default_action_is_const;
-	uint32_t action_data_size_max;
-
-	uint32_t size;
-	uint32_t timeout;
-	uint32_t id;
-};
-
-TAILQ_HEAD(learner_tailq, learner);
-
-struct learner_runtime {
-	void *mailbox;
-	uint8_t **key;
-	uint8_t **action_data;
-};
-
-struct learner_statistics {
-	uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */
-	uint64_t n_pkts_learn[2]; /* 0 = Learn OK, 1 = Learn error. */
-	uint64_t n_pkts_forget;
-	uint64_t *n_pkts_action;
-};
-
-/*
- * Register array.
- */
-struct regarray {
-	TAILQ_ENTRY(regarray) node;
-	char name[RTE_SWX_NAME_SIZE];
-	uint64_t init_val;
-	uint32_t size;
-	uint32_t id;
-};
-
-TAILQ_HEAD(regarray_tailq, regarray);
-
-struct regarray_runtime {
-	uint64_t *regarray;
-	uint32_t size_mask;
-};
-
-/*
- * Meter array.
- */
-struct meter_profile {
-	TAILQ_ENTRY(meter_profile) node;
-	char name[RTE_SWX_NAME_SIZE];
-	struct rte_meter_trtcm_params params;
-	struct rte_meter_trtcm_profile profile;
-	uint32_t n_users;
-};
-
-TAILQ_HEAD(meter_profile_tailq, meter_profile);
-
-struct metarray {
-	TAILQ_ENTRY(metarray) node;
-	char name[RTE_SWX_NAME_SIZE];
-	uint32_t size;
-	uint32_t id;
-};
-
-TAILQ_HEAD(metarray_tailq, metarray);
-
-struct meter {
-	struct rte_meter_trtcm m;
-	struct meter_profile *profile;
-	enum rte_color color_mask;
-	uint8_t pad[20];
-
-	uint64_t n_pkts[RTE_COLORS];
-	uint64_t n_bytes[RTE_COLORS];
-};
-
-struct metarray_runtime {
-	struct meter *metarray;
-	uint32_t size_mask;
-};
-
-/*
- * Pipeline.
- */
-struct thread {
-	/* Packet. */
-	struct rte_swx_pkt pkt;
-	uint8_t *ptr;
-
-	/* Structures. */
-	uint8_t **structs;
-
-	/* Packet headers. */
-	struct header_runtime *headers; /* Extracted or generated headers. */
-	struct header_out_runtime *headers_out; /* Emitted headers. */
-	uint8_t *header_storage;
-	uint8_t *header_out_storage;
-	uint64_t valid_headers;
-	uint32_t n_headers_out;
-
-	/* Packet meta-data. */
-	uint8_t *metadata;
-
-	/* Tables. */
-	struct table_runtime *tables;
-	struct selector_runtime *selectors;
-	struct learner_runtime *learners;
-	struct rte_swx_table_state *table_state;
-	uint64_t action_id;
-	int hit; /* 0 = Miss, 1 = Hit. */
-	uint32_t learner_id;
-	uint64_t time;
-
-	/* Extern objects and functions. */
-	struct extern_obj_runtime *extern_objs;
-	struct extern_func_runtime *extern_funcs;
-
-	/* Instructions. */
-	struct instruction *ip;
-	struct instruction *ret;
-};
-
-#define MASK64_BIT_GET(mask, pos) ((mask) & (1LLU << (pos)))
-#define MASK64_BIT_SET(mask, pos) ((mask) | (1LLU << (pos)))
-#define MASK64_BIT_CLR(mask, pos) ((mask) & ~(1LLU << (pos)))
-
-#define HEADER_VALID(thread, header_id) \
-	MASK64_BIT_GET((thread)->valid_headers, header_id)
-
-#define ALU(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
-	uint64_t dst = dst64 & dst64_mask;                                     \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits);       \
-	uint64_t src = src64 & src64_mask;                                     \
-									       \
-	uint64_t result = dst operator src;                                    \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask);            \
-}
-
-#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
-
-#define ALU_MH(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
-	uint64_t dst = dst64 & dst64_mask;                                     \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src = ntoh64(src64) >> (64 - (ip)->alu.src.n_bits);           \
-									       \
-	uint64_t result = dst operator src;                                    \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask);            \
-}
-
-#define ALU_HM(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
-	uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits);           \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits);       \
-	uint64_t src = src64 & src64_mask;                                     \
-									       \
-	uint64_t result = dst operator src;                                    \
-	result = hton64(result << (64 - (ip)->alu.dst.n_bits));                \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | result;                           \
-}
-
-#define ALU_HM_FAST(thread, ip, operator)  \
-{                                                                                 \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];         \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];      \
-	uint64_t dst64 = *dst64_ptr;                                              \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);          \
-	uint64_t dst = dst64 & dst64_mask;                                        \
-										  \
-	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];         \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];      \
-	uint64_t src64 = *src64_ptr;                                              \
-	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits);          \
-	uint64_t src = hton64(src64 & src64_mask) >> (64 - (ip)->alu.dst.n_bits); \
-										  \
-	uint64_t result = dst operator src;                                       \
-										  \
-	*dst64_ptr = (dst64 & ~dst64_mask) | result;                              \
-}
-
-#define ALU_HH(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
-	uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits);           \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src = ntoh64(src64) >> (64 - (ip)->alu.src.n_bits);           \
-									       \
-	uint64_t result = dst operator src;                                    \
-	result = hton64(result << (64 - (ip)->alu.dst.n_bits));                \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | result;                           \
-}
-
-#define ALU_HH_FAST(thread, ip, operator)  \
-{                                                                                             \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];                     \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];                  \
-	uint64_t dst64 = *dst64_ptr;                                                          \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);                      \
-	uint64_t dst = dst64 & dst64_mask;                                                    \
-											      \
-	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];                     \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];                  \
-	uint64_t src64 = *src64_ptr;                                                          \
-	uint64_t src = (src64 << (64 - (ip)->alu.src.n_bits)) >> (64 - (ip)->alu.dst.n_bits); \
-											      \
-	uint64_t result = dst operator src;                                                   \
-											      \
-	*dst64_ptr = (dst64 & ~dst64_mask) | result;                                          \
-}
-
-#else
-
-#define ALU_MH ALU
-#define ALU_HM ALU
-#define ALU_HM_FAST ALU
-#define ALU_HH ALU
-#define ALU_HH_FAST ALU
-
-#endif
-
-#define ALU_I(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
-	uint64_t dst = dst64 & dst64_mask;                                     \
-									       \
-	uint64_t src = (ip)->alu.src_val;                                      \
-									       \
-	uint64_t result = dst operator src;                                    \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask);            \
-}
-
-#define ALU_MI ALU_I
-
-#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
-
-#define ALU_HI(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
-	uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits);           \
-									       \
-	uint64_t src = (ip)->alu.src_val;                                      \
-									       \
-	uint64_t result = dst operator src;                                    \
-	result = hton64(result << (64 - (ip)->alu.dst.n_bits));                \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | result;                           \
-}
-
-#else
-
-#define ALU_HI ALU_I
-
-#endif
-
-#define MOV(thread, ip)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->mov.src.n_bits);       \
-	uint64_t src = src64 & src64_mask;                                     \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \
-}
-
-#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
-
-#define MOV_MH(thread, ip)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src = ntoh64(src64) >> (64 - (ip)->mov.src.n_bits);           \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \
-}
-
-#define MOV_HM(thread, ip)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->mov.src.n_bits);       \
-	uint64_t src = src64 & src64_mask;                                     \
-									       \
-	src = hton64(src) >> (64 - (ip)->mov.dst.n_bits);                      \
-	*dst64_ptr = (dst64 & ~dst64_mask) | src;                              \
-}
-
-#define MOV_HH(thread, ip)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
-									       \
-	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
-	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
-	uint64_t src64 = *src64_ptr;                                           \
-									       \
-	uint64_t src = src64 << (64 - (ip)->mov.src.n_bits);                   \
-	src = src >> (64 - (ip)->mov.dst.n_bits);                              \
-	*dst64_ptr = (dst64 & ~dst64_mask) | src;                              \
-}
-
-#else
-
-#define MOV_MH MOV
-#define MOV_HM MOV
-#define MOV_HH MOV
-
-#endif
-
-#define MOV_I(thread, ip)  \
-{                                                                              \
-	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
-	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
-	uint64_t dst64 = *dst64_ptr;                                           \
-	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
-									       \
-	uint64_t src = (ip)->mov.src_val;                                      \
-									       \
-	*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \
-}
-
-#define JMP_CMP(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \
-	uint64_t a = a64 & a64_mask;                                           \
-									       \
-	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
-	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
-	uint64_t b64 = *b64_ptr;                                               \
-	uint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits);           \
-	uint64_t b = b64 & b64_mask;                                           \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
-
-#define JMP_CMP_MH(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \
-	uint64_t a = a64 & a64_mask;                                           \
-									       \
-	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
-	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
-	uint64_t b64 = *b64_ptr;                                               \
-	uint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits);                 \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#define JMP_CMP_HM(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \
-									       \
-	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
-	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
-	uint64_t b64 = *b64_ptr;                                               \
-	uint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits);           \
-	uint64_t b = b64 & b64_mask;                                           \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#define JMP_CMP_HH(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \
-									       \
-	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
-	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
-	uint64_t b64 = *b64_ptr;                                               \
-	uint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits);                 \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#define JMP_CMP_HH_FAST(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a = a64 << (64 - (ip)->jmp.a.n_bits);                         \
-									       \
-	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
-	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
-	uint64_t b64 = *b64_ptr;                                               \
-	uint64_t b = b64 << (64 - (ip)->jmp.b.n_bits);                         \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#else
-
-#define JMP_CMP_MH JMP_CMP
-#define JMP_CMP_HM JMP_CMP
-#define JMP_CMP_HH JMP_CMP
-#define JMP_CMP_HH_FAST JMP_CMP
-
-#endif
-
-#define JMP_CMP_I(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \
-	uint64_t a = a64 & a64_mask;                                           \
-									       \
-	uint64_t b = (ip)->jmp.b_val;                                          \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#define JMP_CMP_MI JMP_CMP_I
-
-#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
-
-#define JMP_CMP_HI(thread, ip, operator)  \
-{                                                                              \
-	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
-	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
-	uint64_t a64 = *a64_ptr;                                               \
-	uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \
-									       \
-	uint64_t b = (ip)->jmp.b_val;                                          \
-									       \
-	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
-}
-
-#else
-
-#define JMP_CMP_HI JMP_CMP_I
-
-#endif
-
-#define METADATA_READ(thread, offset, n_bits)                                  \
-({                                                                             \
-	uint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset];           \
-	uint64_t m64 = *m64_ptr;                                               \
-	uint64_t m64_mask = UINT64_MAX >> (64 - (n_bits));                     \
-	(m64 & m64_mask);                                                      \
-})
-
-#define METADATA_WRITE(thread, offset, n_bits, value)                          \
-{                                                                              \
-	uint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset];           \
-	uint64_t m64 = *m64_ptr;                                               \
-	uint64_t m64_mask = UINT64_MAX >> (64 - (n_bits));                     \
-									       \
-	uint64_t m_new = value;                                                \
-									       \
-	*m64_ptr = (m64 & ~m64_mask) | (m_new & m64_mask);                     \
-}
-
-#ifndef RTE_SWX_PIPELINE_THREADS_MAX
-#define RTE_SWX_PIPELINE_THREADS_MAX 16
-#endif
-
-struct rte_swx_pipeline {
-	struct struct_type_tailq struct_types;
-	struct port_in_type_tailq port_in_types;
-	struct port_in_tailq ports_in;
-	struct port_out_type_tailq port_out_types;
-	struct port_out_tailq ports_out;
-	struct extern_type_tailq extern_types;
-	struct extern_obj_tailq extern_objs;
-	struct extern_func_tailq extern_funcs;
-	struct header_tailq headers;
-	struct struct_type *metadata_st;
-	uint32_t metadata_struct_id;
-	struct action_tailq actions;
-	struct table_type_tailq table_types;
-	struct table_tailq tables;
-	struct selector_tailq selectors;
-	struct learner_tailq learners;
-	struct regarray_tailq regarrays;
-	struct meter_profile_tailq meter_profiles;
-	struct metarray_tailq metarrays;
-
-	struct port_in_runtime *in;
-	struct port_out_runtime *out;
-	struct instruction **action_instructions;
-	struct rte_swx_table_state *table_state;
-	struct table_statistics *table_stats;
-	struct selector_statistics *selector_stats;
-	struct learner_statistics *learner_stats;
-	struct regarray_runtime *regarray_runtime;
-	struct metarray_runtime *metarray_runtime;
-	struct instruction *instructions;
-	struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
-
-	uint32_t n_structs;
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	uint32_t n_extern_objs;
-	uint32_t n_extern_funcs;
-	uint32_t n_actions;
-	uint32_t n_tables;
-	uint32_t n_selectors;
-	uint32_t n_learners;
-	uint32_t n_regarrays;
-	uint32_t n_metarrays;
-	uint32_t n_headers;
-	uint32_t thread_id;
-	uint32_t port_id;
-	uint32_t n_instructions;
-	int build_done;
-	int numa_node;
-};
-
 /*
  * Struct.
  */
diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h
new file mode 100644
index 0000000000..5d80dd8451
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_internal.h
@@ -0,0 +1,1383 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Intel Corporation
+ */
+#ifndef __INCLUDE_RTE_SWX_PIPELINE_INTERNAL_H__
+#define __INCLUDE_RTE_SWX_PIPELINE_INTERNAL_H__
+
+#include <inttypes.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_meter.h>
+
+#include <rte_swx_table_selector.h>
+#include <rte_swx_table_learner.h>
+#include <rte_swx_pipeline.h>
+#include <rte_swx_ctl.h>
+
+#ifndef TRACE_LEVEL
+#define TRACE_LEVEL 0
+#endif
+
+#if TRACE_LEVEL
+#define TRACE(...) printf(__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+/*
+ * Environment.
+ */
+#define ntoh64(x) rte_be_to_cpu_64(x)
+#define hton64(x) rte_cpu_to_be_64(x)
+
+/*
+ * Struct.
+ */
+struct field {
+	char name[RTE_SWX_NAME_SIZE];
+	uint32_t n_bits;
+	uint32_t offset;
+	int var_size;
+};
+
+struct struct_type {
+	TAILQ_ENTRY(struct_type) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct field *fields;
+	uint32_t n_fields;
+	uint32_t n_bits;
+	uint32_t n_bits_min;
+	int var_size;
+};
+
+TAILQ_HEAD(struct_type_tailq, struct_type);
+
+/*
+ * Input port.
+ */
+struct port_in_type {
+	TAILQ_ENTRY(port_in_type) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct rte_swx_port_in_ops ops;
+};
+
+TAILQ_HEAD(port_in_type_tailq, port_in_type);
+
+struct port_in {
+	TAILQ_ENTRY(port_in) node;
+	struct port_in_type *type;
+	void *obj;
+	uint32_t id;
+};
+
+TAILQ_HEAD(port_in_tailq, port_in);
+
+struct port_in_runtime {
+	rte_swx_port_in_pkt_rx_t pkt_rx;
+	void *obj;
+};
+
+/*
+ * Output port.
+ */
+struct port_out_type {
+	TAILQ_ENTRY(port_out_type) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct rte_swx_port_out_ops ops;
+};
+
+TAILQ_HEAD(port_out_type_tailq, port_out_type);
+
+struct port_out {
+	TAILQ_ENTRY(port_out) node;
+	struct port_out_type *type;
+	void *obj;
+	uint32_t id;
+};
+
+TAILQ_HEAD(port_out_tailq, port_out);
+
+struct port_out_runtime {
+	rte_swx_port_out_pkt_tx_t pkt_tx;
+	rte_swx_port_out_flush_t flush;
+	void *obj;
+};
+
+/*
+ * Extern object.
+ */
+struct extern_type_member_func {
+	TAILQ_ENTRY(extern_type_member_func) node;
+	char name[RTE_SWX_NAME_SIZE];
+	rte_swx_extern_type_member_func_t func;
+	uint32_t id;
+};
+
+TAILQ_HEAD(extern_type_member_func_tailq, extern_type_member_func);
+
+struct extern_type {
+	TAILQ_ENTRY(extern_type) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct struct_type *mailbox_struct_type;
+	rte_swx_extern_type_constructor_t constructor;
+	rte_swx_extern_type_destructor_t destructor;
+	struct extern_type_member_func_tailq funcs;
+	uint32_t n_funcs;
+};
+
+TAILQ_HEAD(extern_type_tailq, extern_type);
+
+struct extern_obj {
+	TAILQ_ENTRY(extern_obj) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct extern_type *type;
+	void *obj;
+	uint32_t struct_id;
+	uint32_t id;
+};
+
+TAILQ_HEAD(extern_obj_tailq, extern_obj);
+
+#ifndef RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX
+#define RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX 8
+#endif
+
+struct extern_obj_runtime {
+	void *obj;
+	uint8_t *mailbox;
+	rte_swx_extern_type_member_func_t funcs[RTE_SWX_EXTERN_TYPE_MEMBER_FUNCS_MAX];
+};
+
+/*
+ * Extern function.
+ */
+struct extern_func {
+	TAILQ_ENTRY(extern_func) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct struct_type *mailbox_struct_type;
+	rte_swx_extern_func_t func;
+	uint32_t struct_id;
+	uint32_t id;
+};
+
+TAILQ_HEAD(extern_func_tailq, extern_func);
+
+struct extern_func_runtime {
+	uint8_t *mailbox;
+	rte_swx_extern_func_t func;
+};
+
+/*
+ * Header.
+ */
+struct header {
+	TAILQ_ENTRY(header) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct struct_type *st;
+	uint32_t struct_id;
+	uint32_t id;
+};
+
+TAILQ_HEAD(header_tailq, header);
+
+struct header_runtime {
+	uint8_t *ptr0;
+	uint32_t n_bytes;
+};
+
+struct header_out_runtime {
+	uint8_t *ptr0;
+	uint8_t *ptr;
+	uint32_t n_bytes;
+};
+
+/*
+ * Instruction.
+ */
+
+/* Packet headers are always in Network Byte Order (NBO), i.e. big endian.
+ * Packet meta-data fields are always assumed to be in Host Byte Order (HBO).
+ * Table entry fields can be in either NBO or HBO; they are assumed to be in HBO
+ * when transferred to packet meta-data and in NBO when transferred to packet
+ * headers.
+ */
+
+/* Notation conventions:
+ *    -Header field: H = h.header.field (dst/src)
+ *    -Meta-data field: M = m.field (dst/src)
+ *    -Extern object mailbox field: E = e.field (dst/src)
+ *    -Extern function mailbox field: F = f.field (dst/src)
+ *    -Table action data field: T = t.field (src only)
+ *    -Immediate value: I = 32-bit unsigned value (src only)
+ */
+
+enum instruction_type {
+	/* rx m.port_in */
+	INSTR_RX,
+
+	/* tx port_out
+	 * port_out = MI
+	 */
+	INSTR_TX,   /* port_out = M */
+	INSTR_TX_I, /* port_out = I */
+
+	/* extract h.header */
+	INSTR_HDR_EXTRACT,
+	INSTR_HDR_EXTRACT2,
+	INSTR_HDR_EXTRACT3,
+	INSTR_HDR_EXTRACT4,
+	INSTR_HDR_EXTRACT5,
+	INSTR_HDR_EXTRACT6,
+	INSTR_HDR_EXTRACT7,
+	INSTR_HDR_EXTRACT8,
+
+	/* extract h.header m.last_field_size */
+	INSTR_HDR_EXTRACT_M,
+
+	/* lookahead h.header */
+	INSTR_HDR_LOOKAHEAD,
+
+	/* emit h.header */
+	INSTR_HDR_EMIT,
+	INSTR_HDR_EMIT_TX,
+	INSTR_HDR_EMIT2_TX,
+	INSTR_HDR_EMIT3_TX,
+	INSTR_HDR_EMIT4_TX,
+	INSTR_HDR_EMIT5_TX,
+	INSTR_HDR_EMIT6_TX,
+	INSTR_HDR_EMIT7_TX,
+	INSTR_HDR_EMIT8_TX,
+
+	/* validate h.header */
+	INSTR_HDR_VALIDATE,
+
+	/* invalidate h.header */
+	INSTR_HDR_INVALIDATE,
+
+	/* mov dst src
+	 * dst = src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_MOV,    /* dst = MEF, src = MEFT */
+	INSTR_MOV_MH, /* dst = MEF, src = H */
+	INSTR_MOV_HM, /* dst = H, src = MEFT */
+	INSTR_MOV_HH, /* dst = H, src = H */
+	INSTR_MOV_I,  /* dst = HMEF, src = I */
+
+	/* dma h.header t.field
+	 * memcpy(h.header, t.field, sizeof(h.header))
+	 */
+	INSTR_DMA_HT,
+	INSTR_DMA_HT2,
+	INSTR_DMA_HT3,
+	INSTR_DMA_HT4,
+	INSTR_DMA_HT5,
+	INSTR_DMA_HT6,
+	INSTR_DMA_HT7,
+	INSTR_DMA_HT8,
+
+	/* add dst src
+	 * dst += src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_ADD,    /* dst = MEF, src = MEF */
+	INSTR_ALU_ADD_MH, /* dst = MEF, src = H */
+	INSTR_ALU_ADD_HM, /* dst = H, src = MEF */
+	INSTR_ALU_ADD_HH, /* dst = H, src = H */
+	INSTR_ALU_ADD_MI, /* dst = MEF, src = I */
+	INSTR_ALU_ADD_HI, /* dst = H, src = I */
+
+	/* sub dst src
+	 * dst -= src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_SUB,    /* dst = MEF, src = MEF */
+	INSTR_ALU_SUB_MH, /* dst = MEF, src = H */
+	INSTR_ALU_SUB_HM, /* dst = H, src = MEF */
+	INSTR_ALU_SUB_HH, /* dst = H, src = H */
+	INSTR_ALU_SUB_MI, /* dst = MEF, src = I */
+	INSTR_ALU_SUB_HI, /* dst = H, src = I */
+
+	/* ckadd dst src
+	 * dst = dst '+ src[0:1] '+ src[2:3] + ...
+	 * dst = H, src = {H, h.header}
+	 */
+	INSTR_ALU_CKADD_FIELD,    /* src = H */
+	INSTR_ALU_CKADD_STRUCT20, /* src = h.header, with sizeof(header) = 20 */
+	INSTR_ALU_CKADD_STRUCT,   /* src = h.hdeader, with any sizeof(header) */
+
+	/* cksub dst src
+	 * dst = dst '- src
+	 * dst = H, src = H
+	 */
+	INSTR_ALU_CKSUB_FIELD,
+
+	/* and dst src
+	 * dst &= src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_AND,    /* dst = MEF, src = MEFT */
+	INSTR_ALU_AND_MH, /* dst = MEF, src = H */
+	INSTR_ALU_AND_HM, /* dst = H, src = MEFT */
+	INSTR_ALU_AND_HH, /* dst = H, src = H */
+	INSTR_ALU_AND_I,  /* dst = HMEF, src = I */
+
+	/* or dst src
+	 * dst |= src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_OR,    /* dst = MEF, src = MEFT */
+	INSTR_ALU_OR_MH, /* dst = MEF, src = H */
+	INSTR_ALU_OR_HM, /* dst = H, src = MEFT */
+	INSTR_ALU_OR_HH, /* dst = H, src = H */
+	INSTR_ALU_OR_I,  /* dst = HMEF, src = I */
+
+	/* xor dst src
+	 * dst ^= src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_XOR,    /* dst = MEF, src = MEFT */
+	INSTR_ALU_XOR_MH, /* dst = MEF, src = H */
+	INSTR_ALU_XOR_HM, /* dst = H, src = MEFT */
+	INSTR_ALU_XOR_HH, /* dst = H, src = H */
+	INSTR_ALU_XOR_I,  /* dst = HMEF, src = I */
+
+	/* shl dst src
+	 * dst <<= src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_SHL,    /* dst = MEF, src = MEF */
+	INSTR_ALU_SHL_MH, /* dst = MEF, src = H */
+	INSTR_ALU_SHL_HM, /* dst = H, src = MEF */
+	INSTR_ALU_SHL_HH, /* dst = H, src = H */
+	INSTR_ALU_SHL_MI, /* dst = MEF, src = I */
+	INSTR_ALU_SHL_HI, /* dst = H, src = I */
+
+	/* shr dst src
+	 * dst >>= src
+	 * dst = HMEF, src = HMEFTI
+	 */
+	INSTR_ALU_SHR,    /* dst = MEF, src = MEF */
+	INSTR_ALU_SHR_MH, /* dst = MEF, src = H */
+	INSTR_ALU_SHR_HM, /* dst = H, src = MEF */
+	INSTR_ALU_SHR_HH, /* dst = H, src = H */
+	INSTR_ALU_SHR_MI, /* dst = MEF, src = I */
+	INSTR_ALU_SHR_HI, /* dst = H, src = I */
+
+	/* regprefetch REGARRAY index
+	 * prefetch REGARRAY[index]
+	 * index = HMEFTI
+	 */
+	INSTR_REGPREFETCH_RH, /* index = H */
+	INSTR_REGPREFETCH_RM, /* index = MEFT */
+	INSTR_REGPREFETCH_RI, /* index = I */
+
+	/* regrd dst REGARRAY index
+	 * dst = REGARRAY[index]
+	 * dst = HMEF, index = HMEFTI
+	 */
+	INSTR_REGRD_HRH, /* dst = H, index = H */
+	INSTR_REGRD_HRM, /* dst = H, index = MEFT */
+	INSTR_REGRD_HRI, /* dst = H, index = I */
+	INSTR_REGRD_MRH, /* dst = MEF, index = H */
+	INSTR_REGRD_MRM, /* dst = MEF, index = MEFT */
+	INSTR_REGRD_MRI, /* dst = MEF, index = I */
+
+	/* regwr REGARRAY index src
+	 * REGARRAY[index] = src
+	 * index = HMEFTI, src = HMEFTI
+	 */
+	INSTR_REGWR_RHH, /* index = H, src = H */
+	INSTR_REGWR_RHM, /* index = H, src = MEFT */
+	INSTR_REGWR_RHI, /* index = H, src = I */
+	INSTR_REGWR_RMH, /* index = MEFT, src = H */
+	INSTR_REGWR_RMM, /* index = MEFT, src = MEFT */
+	INSTR_REGWR_RMI, /* index = MEFT, src = I */
+	INSTR_REGWR_RIH, /* index = I, src = H */
+	INSTR_REGWR_RIM, /* index = I, src = MEFT */
+	INSTR_REGWR_RII, /* index = I, src = I */
+
+	/* regadd REGARRAY index src
+	 * REGARRAY[index] += src
+	 * index = HMEFTI, src = HMEFTI
+	 */
+	INSTR_REGADD_RHH, /* index = H, src = H */
+	INSTR_REGADD_RHM, /* index = H, src = MEFT */
+	INSTR_REGADD_RHI, /* index = H, src = I */
+	INSTR_REGADD_RMH, /* index = MEFT, src = H */
+	INSTR_REGADD_RMM, /* index = MEFT, src = MEFT */
+	INSTR_REGADD_RMI, /* index = MEFT, src = I */
+	INSTR_REGADD_RIH, /* index = I, src = H */
+	INSTR_REGADD_RIM, /* index = I, src = MEFT */
+	INSTR_REGADD_RII, /* index = I, src = I */
+
+	/* metprefetch METARRAY index
+	 * prefetch METARRAY[index]
+	 * index = HMEFTI
+	 */
+	INSTR_METPREFETCH_H, /* index = H */
+	INSTR_METPREFETCH_M, /* index = MEFT */
+	INSTR_METPREFETCH_I, /* index = I */
+
+	/* meter METARRAY index length color_in color_out
+	 * color_out = meter(METARRAY[index], length, color_in)
+	 * index = HMEFTI, length = HMEFT, color_in = MEFTI, color_out = MEF
+	 */
+	INSTR_METER_HHM, /* index = H, length = H, color_in = MEFT */
+	INSTR_METER_HHI, /* index = H, length = H, color_in = I */
+	INSTR_METER_HMM, /* index = H, length = MEFT, color_in = MEFT */
+	INSTR_METER_HMI, /* index = H, length = MEFT, color_in = I */
+	INSTR_METER_MHM, /* index = MEFT, length = H, color_in = MEFT */
+	INSTR_METER_MHI, /* index = MEFT, length = H, color_in = I */
+	INSTR_METER_MMM, /* index = MEFT, length = MEFT, color_in = MEFT */
+	INSTR_METER_MMI, /* index = MEFT, length = MEFT, color_in = I */
+	INSTR_METER_IHM, /* index = I, length = H, color_in = MEFT */
+	INSTR_METER_IHI, /* index = I, length = H, color_in = I */
+	INSTR_METER_IMM, /* index = I, length = MEFT, color_in = MEFT */
+	INSTR_METER_IMI, /* index = I, length = MEFT, color_in = I */
+
+	/* table TABLE */
+	INSTR_TABLE,
+	INSTR_SELECTOR,
+	INSTR_LEARNER,
+
+	/* learn LEARNER ACTION_NAME */
+	INSTR_LEARNER_LEARN,
+
+	/* forget */
+	INSTR_LEARNER_FORGET,
+
+	/* extern e.obj.func */
+	INSTR_EXTERN_OBJ,
+
+	/* extern f.func */
+	INSTR_EXTERN_FUNC,
+
+	/* jmp LABEL
+	 * Unconditional jump
+	 */
+	INSTR_JMP,
+
+	/* jmpv LABEL h.header
+	 * Jump if header is valid
+	 */
+	INSTR_JMP_VALID,
+
+	/* jmpnv LABEL h.header
+	 * Jump if header is invalid
+	 */
+	INSTR_JMP_INVALID,
+
+	/* jmph LABEL
+	 * Jump if table lookup hit
+	 */
+	INSTR_JMP_HIT,
+
+	/* jmpnh LABEL
+	 * Jump if table lookup miss
+	 */
+	INSTR_JMP_MISS,
+
+	/* jmpa LABEL ACTION
+	 * Jump if action run
+	 */
+	INSTR_JMP_ACTION_HIT,
+
+	/* jmpna LABEL ACTION
+	 * Jump if action not run
+	 */
+	INSTR_JMP_ACTION_MISS,
+
+	/* jmpeq LABEL a b
+	 * Jump if a is equal to b
+	 * a = HMEFT, b = HMEFTI
+	 */
+	INSTR_JMP_EQ,    /* a = MEFT, b = MEFT */
+	INSTR_JMP_EQ_MH, /* a = MEFT, b = H */
+	INSTR_JMP_EQ_HM, /* a = H, b = MEFT */
+	INSTR_JMP_EQ_HH, /* a = H, b = H */
+	INSTR_JMP_EQ_I,  /* (a, b) = (MEFT, I) or (a, b) = (H, I) */
+
+	/* jmpneq LABEL a b
+	 * Jump if a is not equal to b
+	 * a = HMEFT, b = HMEFTI
+	 */
+	INSTR_JMP_NEQ,    /* a = MEFT, b = MEFT */
+	INSTR_JMP_NEQ_MH, /* a = MEFT, b = H */
+	INSTR_JMP_NEQ_HM, /* a = H, b = MEFT */
+	INSTR_JMP_NEQ_HH, /* a = H, b = H */
+	INSTR_JMP_NEQ_I,  /* (a, b) = (MEFT, I) or (a, b) = (H, I) */
+
+	/* jmplt LABEL a b
+	 * Jump if a is less than b
+	 * a = HMEFT, b = HMEFTI
+	 */
+	INSTR_JMP_LT,    /* a = MEFT, b = MEFT */
+	INSTR_JMP_LT_MH, /* a = MEFT, b = H */
+	INSTR_JMP_LT_HM, /* a = H, b = MEFT */
+	INSTR_JMP_LT_HH, /* a = H, b = H */
+	INSTR_JMP_LT_MI, /* a = MEFT, b = I */
+	INSTR_JMP_LT_HI, /* a = H, b = I */
+
+	/* jmpgt LABEL a b
+	 * Jump if a is greater than b
+	 * a = HMEFT, b = HMEFTI
+	 */
+	INSTR_JMP_GT,    /* a = MEFT, b = MEFT */
+	INSTR_JMP_GT_MH, /* a = MEFT, b = H */
+	INSTR_JMP_GT_HM, /* a = H, b = MEFT */
+	INSTR_JMP_GT_HH, /* a = H, b = H */
+	INSTR_JMP_GT_MI, /* a = MEFT, b = I */
+	INSTR_JMP_GT_HI, /* a = H, b = I */
+
+	/* return
+	 * Return from action
+	 */
+	INSTR_RETURN,
+};
+
+struct instr_operand {
+	uint8_t struct_id;
+	uint8_t n_bits;
+	uint8_t offset;
+	uint8_t pad;
+};
+
+struct instr_io {
+	struct {
+		union {
+			struct {
+				uint8_t offset;
+				uint8_t n_bits;
+				uint8_t pad[2];
+			};
+
+			uint32_t val;
+		};
+	} io;
+
+	struct {
+		uint8_t header_id[8];
+		uint8_t struct_id[8];
+		uint8_t n_bytes[8];
+	} hdr;
+};
+
+struct instr_hdr_validity {
+	uint8_t header_id;
+};
+
+struct instr_table {
+	uint8_t table_id;
+};
+
+struct instr_learn {
+	uint8_t action_id;
+};
+
+struct instr_extern_obj {
+	uint8_t ext_obj_id;
+	uint8_t func_id;
+};
+
+struct instr_extern_func {
+	uint8_t ext_func_id;
+};
+
+struct instr_dst_src {
+	struct instr_operand dst;
+	union {
+		struct instr_operand src;
+		uint64_t src_val;
+	};
+};
+
+struct instr_regarray {
+	uint8_t regarray_id;
+	uint8_t pad[3];
+
+	union {
+		struct instr_operand idx;
+		uint32_t idx_val;
+	};
+
+	union {
+		struct instr_operand dstsrc;
+		uint64_t dstsrc_val;
+	};
+};
+
+struct instr_meter {
+	uint8_t metarray_id;
+	uint8_t pad[3];
+
+	union {
+		struct instr_operand idx;
+		uint32_t idx_val;
+	};
+
+	struct instr_operand length;
+
+	union {
+		struct instr_operand color_in;
+		uint32_t color_in_val;
+	};
+
+	struct instr_operand color_out;
+};
+
+struct instr_dma {
+	struct {
+		uint8_t header_id[8];
+		uint8_t struct_id[8];
+	} dst;
+
+	struct {
+		uint8_t offset[8];
+	} src;
+
+	uint16_t n_bytes[8];
+};
+
+struct instr_jmp {
+	struct instruction *ip;
+
+	union {
+		struct instr_operand a;
+		uint8_t header_id;
+		uint8_t action_id;
+	};
+
+	union {
+		struct instr_operand b;
+		uint64_t b_val;
+	};
+};
+
+struct instruction {
+	enum instruction_type type;
+	union {
+		struct instr_io io;
+		struct instr_hdr_validity valid;
+		struct instr_dst_src mov;
+		struct instr_regarray regarray;
+		struct instr_meter meter;
+		struct instr_dma dma;
+		struct instr_dst_src alu;
+		struct instr_table table;
+		struct instr_learn learn;
+		struct instr_extern_obj ext_obj;
+		struct instr_extern_func ext_func;
+		struct instr_jmp jmp;
+	};
+};
+
+struct instruction_data {
+	char label[RTE_SWX_NAME_SIZE];
+	char jmp_label[RTE_SWX_NAME_SIZE];
+	uint32_t n_users; /* user = jmp instruction to this instruction. */
+	int invalid;
+};
+
+/*
+ * Action.
+ */
+struct action {
+	TAILQ_ENTRY(action) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct struct_type *st;
+	int *args_endianness; /* 0 = Host Byte Order (HBO); 1 = Network Byte Order (NBO). */
+	struct instruction *instructions;
+	uint32_t n_instructions;
+	uint32_t id;
+};
+
+TAILQ_HEAD(action_tailq, action);
+
+/*
+ * Table.
+ */
+struct table_type {
+	TAILQ_ENTRY(table_type) node;
+	char name[RTE_SWX_NAME_SIZE];
+	enum rte_swx_table_match_type match_type;
+	struct rte_swx_table_ops ops;
+};
+
+TAILQ_HEAD(table_type_tailq, table_type);
+
+struct match_field {
+	enum rte_swx_table_match_type match_type;
+	struct field *field;
+};
+
+struct table {
+	TAILQ_ENTRY(table) node;
+	char name[RTE_SWX_NAME_SIZE];
+	char args[RTE_SWX_NAME_SIZE];
+	struct table_type *type; /* NULL when n_fields == 0. */
+
+	/* Match. */
+	struct match_field *fields;
+	uint32_t n_fields;
+	struct header *header; /* Only valid when n_fields > 0. */
+
+	/* Action. */
+	struct action **actions;
+	struct action *default_action;
+	uint8_t *default_action_data;
+	uint32_t n_actions;
+	int default_action_is_const;
+	uint32_t action_data_size_max;
+
+	uint32_t size;
+	uint32_t id;
+};
+
+TAILQ_HEAD(table_tailq, table);
+
+struct table_runtime {
+	rte_swx_table_lookup_t func;
+	void *mailbox;
+	uint8_t **key;
+};
+
+struct table_statistics {
+	uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */
+	uint64_t *n_pkts_action;
+};
+
+/*
+ * Selector.
+ */
+struct selector {
+	TAILQ_ENTRY(selector) node;
+	char name[RTE_SWX_NAME_SIZE];
+
+	struct field *group_id_field;
+	struct field **selector_fields;
+	uint32_t n_selector_fields;
+	struct header *selector_header;
+	struct field *member_id_field;
+
+	uint32_t n_groups_max;
+	uint32_t n_members_per_group_max;
+
+	uint32_t id;
+};
+
+TAILQ_HEAD(selector_tailq, selector);
+
+struct selector_runtime {
+	void *mailbox;
+	uint8_t **group_id_buffer;
+	uint8_t **selector_buffer;
+	uint8_t **member_id_buffer;
+};
+
+struct selector_statistics {
+	uint64_t n_pkts;
+};
+
+/*
+ * Learner table.
+ */
+struct learner {
+	TAILQ_ENTRY(learner) node;
+	char name[RTE_SWX_NAME_SIZE];
+
+	/* Match. */
+	struct field **fields;
+	uint32_t n_fields;
+	struct header *header;
+
+	/* Action. */
+	struct action **actions;
+	struct field **action_arg;
+	struct action *default_action;
+	uint8_t *default_action_data;
+	uint32_t n_actions;
+	int default_action_is_const;
+	uint32_t action_data_size_max;
+
+	uint32_t size;
+	uint32_t timeout;
+	uint32_t id;
+};
+
+TAILQ_HEAD(learner_tailq, learner);
+
+struct learner_runtime {
+	void *mailbox;
+	uint8_t **key;
+	uint8_t **action_data;
+};
+
+struct learner_statistics {
+	uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */
+	uint64_t n_pkts_learn[2]; /* 0 = Learn OK, 1 = Learn error. */
+	uint64_t n_pkts_forget;
+	uint64_t *n_pkts_action;
+};
+
+/*
+ * Register array.
+ */
+struct regarray {
+	TAILQ_ENTRY(regarray) node;
+	char name[RTE_SWX_NAME_SIZE];
+	uint64_t init_val;
+	uint32_t size;
+	uint32_t id;
+};
+
+TAILQ_HEAD(regarray_tailq, regarray);
+
+struct regarray_runtime {
+	uint64_t *regarray;
+	uint32_t size_mask;
+};
+
+/*
+ * Meter array.
+ */
+struct meter_profile {
+	TAILQ_ENTRY(meter_profile) node;
+	char name[RTE_SWX_NAME_SIZE];
+	struct rte_meter_trtcm_params params;
+	struct rte_meter_trtcm_profile profile;
+	uint32_t n_users;
+};
+
+TAILQ_HEAD(meter_profile_tailq, meter_profile);
+
+struct metarray {
+	TAILQ_ENTRY(metarray) node;
+	char name[RTE_SWX_NAME_SIZE];
+	uint32_t size;
+	uint32_t id;
+};
+
+TAILQ_HEAD(metarray_tailq, metarray);
+
+struct meter {
+	struct rte_meter_trtcm m;
+	struct meter_profile *profile;
+	enum rte_color color_mask;
+	uint8_t pad[20];
+
+	uint64_t n_pkts[RTE_COLORS];
+	uint64_t n_bytes[RTE_COLORS];
+};
+
+struct metarray_runtime {
+	struct meter *metarray;
+	uint32_t size_mask;
+};
+
+/*
+ * Pipeline.
+ */
+struct thread {
+	/* Packet. */
+	struct rte_swx_pkt pkt;
+	uint8_t *ptr;
+
+	/* Structures. */
+	uint8_t **structs;
+
+	/* Packet headers. */
+	struct header_runtime *headers; /* Extracted or generated headers. */
+	struct header_out_runtime *headers_out; /* Emitted headers. */
+	uint8_t *header_storage;
+	uint8_t *header_out_storage;
+	uint64_t valid_headers;
+	uint32_t n_headers_out;
+
+	/* Packet meta-data. */
+	uint8_t *metadata;
+
+	/* Tables. */
+	struct table_runtime *tables;
+	struct selector_runtime *selectors;
+	struct learner_runtime *learners;
+	struct rte_swx_table_state *table_state;
+	uint64_t action_id;
+	int hit; /* 0 = Miss, 1 = Hit. */
+	uint32_t learner_id;
+	uint64_t time;
+
+	/* Extern objects and functions. */
+	struct extern_obj_runtime *extern_objs;
+	struct extern_func_runtime *extern_funcs;
+
+	/* Instructions. */
+	struct instruction *ip;
+	struct instruction *ret;
+};
+
+#define MASK64_BIT_GET(mask, pos) ((mask) & (1LLU << (pos)))
+#define MASK64_BIT_SET(mask, pos) ((mask) | (1LLU << (pos)))
+#define MASK64_BIT_CLR(mask, pos) ((mask) & ~(1LLU << (pos)))
+
+#define HEADER_VALID(thread, header_id) \
+	MASK64_BIT_GET((thread)->valid_headers, header_id)
+
+#define ALU(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
+	uint64_t dst = dst64 & dst64_mask;                                     \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits);       \
+	uint64_t src = src64 & src64_mask;                                     \
+									       \
+	uint64_t result = dst operator src;                                    \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask);            \
+}
+
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+
+#define ALU_MH(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
+	uint64_t dst = dst64 & dst64_mask;                                     \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src = ntoh64(src64) >> (64 - (ip)->alu.src.n_bits);           \
+									       \
+	uint64_t result = dst operator src;                                    \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask);            \
+}
+
+#define ALU_HM(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
+	uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits);           \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits);       \
+	uint64_t src = src64 & src64_mask;                                     \
+									       \
+	uint64_t result = dst operator src;                                    \
+	result = hton64(result << (64 - (ip)->alu.dst.n_bits));                \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | result;                           \
+}
+
+#define ALU_HM_FAST(thread, ip, operator)  \
+{                                                                                 \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];         \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];      \
+	uint64_t dst64 = *dst64_ptr;                                              \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);          \
+	uint64_t dst = dst64 & dst64_mask;                                        \
+										  \
+	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];         \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];      \
+	uint64_t src64 = *src64_ptr;                                              \
+	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->alu.src.n_bits);          \
+	uint64_t src = hton64(src64 & src64_mask) >> (64 - (ip)->alu.dst.n_bits); \
+										  \
+	uint64_t result = dst operator src;                                       \
+										  \
+	*dst64_ptr = (dst64 & ~dst64_mask) | result;                              \
+}
+
+#define ALU_HH(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
+	uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits);           \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src = ntoh64(src64) >> (64 - (ip)->alu.src.n_bits);           \
+									       \
+	uint64_t result = dst operator src;                                    \
+	result = hton64(result << (64 - (ip)->alu.dst.n_bits));                \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | result;                           \
+}
+
+#define ALU_HH_FAST(thread, ip, operator)  \
+{                                                                                             \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];                     \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];                  \
+	uint64_t dst64 = *dst64_ptr;                                                          \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);                      \
+	uint64_t dst = dst64 & dst64_mask;                                                    \
+											      \
+	uint8_t *src_struct = (thread)->structs[(ip)->alu.src.struct_id];                     \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->alu.src.offset];                  \
+	uint64_t src64 = *src64_ptr;                                                          \
+	uint64_t src = (src64 << (64 - (ip)->alu.src.n_bits)) >> (64 - (ip)->alu.dst.n_bits); \
+											      \
+	uint64_t result = dst operator src;                                                   \
+											      \
+	*dst64_ptr = (dst64 & ~dst64_mask) | result;                                          \
+}
+
+#else
+
+#define ALU_MH ALU
+#define ALU_HM ALU
+#define ALU_HM_FAST ALU
+#define ALU_HH ALU
+#define ALU_HH_FAST ALU
+
+#endif
+
+#define ALU_I(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
+	uint64_t dst = dst64 & dst64_mask;                                     \
+									       \
+	uint64_t src = (ip)->alu.src_val;                                      \
+									       \
+	uint64_t result = dst operator src;                                    \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | (result & dst64_mask);            \
+}
+
+#define ALU_MI ALU_I
+
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+
+#define ALU_HI(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->alu.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->alu.dst.n_bits);       \
+	uint64_t dst = ntoh64(dst64) >> (64 - (ip)->alu.dst.n_bits);           \
+									       \
+	uint64_t src = (ip)->alu.src_val;                                      \
+									       \
+	uint64_t result = dst operator src;                                    \
+	result = hton64(result << (64 - (ip)->alu.dst.n_bits));                \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | result;                           \
+}
+
+#else
+
+#define ALU_HI ALU_I
+
+#endif
+
+#define MOV(thread, ip)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->mov.src.n_bits);       \
+	uint64_t src = src64 & src64_mask;                                     \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \
+}
+
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+
+#define MOV_MH(thread, ip)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src = ntoh64(src64) >> (64 - (ip)->mov.src.n_bits);           \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \
+}
+
+#define MOV_HM(thread, ip)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+	uint64_t src64_mask = UINT64_MAX >> (64 - (ip)->mov.src.n_bits);       \
+	uint64_t src = src64 & src64_mask;                                     \
+									       \
+	src = hton64(src) >> (64 - (ip)->mov.dst.n_bits);                      \
+	*dst64_ptr = (dst64 & ~dst64_mask) | src;                              \
+}
+
+#define MOV_HH(thread, ip)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
+									       \
+	uint8_t *src_struct = (thread)->structs[(ip)->mov.src.struct_id];      \
+	uint64_t *src64_ptr = (uint64_t *)&src_struct[(ip)->mov.src.offset];   \
+	uint64_t src64 = *src64_ptr;                                           \
+									       \
+	uint64_t src = src64 << (64 - (ip)->mov.src.n_bits);                   \
+	src = src >> (64 - (ip)->mov.dst.n_bits);                              \
+	*dst64_ptr = (dst64 & ~dst64_mask) | src;                              \
+}
+
+#else
+
+#define MOV_MH MOV
+#define MOV_HM MOV
+#define MOV_HH MOV
+
+#endif
+
+#define MOV_I(thread, ip)  \
+{                                                                              \
+	uint8_t *dst_struct = (thread)->structs[(ip)->mov.dst.struct_id];      \
+	uint64_t *dst64_ptr = (uint64_t *)&dst_struct[(ip)->mov.dst.offset];   \
+	uint64_t dst64 = *dst64_ptr;                                           \
+	uint64_t dst64_mask = UINT64_MAX >> (64 - (ip)->mov.dst.n_bits);       \
+									       \
+	uint64_t src = (ip)->mov.src_val;                                      \
+									       \
+	*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \
+}
+
+#define JMP_CMP(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \
+	uint64_t a = a64 & a64_mask;                                           \
+									       \
+	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
+	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
+	uint64_t b64 = *b64_ptr;                                               \
+	uint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits);           \
+	uint64_t b = b64 & b64_mask;                                           \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+
+#define JMP_CMP_MH(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \
+	uint64_t a = a64 & a64_mask;                                           \
+									       \
+	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
+	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
+	uint64_t b64 = *b64_ptr;                                               \
+	uint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits);                 \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#define JMP_CMP_HM(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \
+									       \
+	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
+	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
+	uint64_t b64 = *b64_ptr;                                               \
+	uint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits);           \
+	uint64_t b = b64 & b64_mask;                                           \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#define JMP_CMP_HH(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \
+									       \
+	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
+	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
+	uint64_t b64 = *b64_ptr;                                               \
+	uint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits);                 \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#define JMP_CMP_HH_FAST(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a = a64 << (64 - (ip)->jmp.a.n_bits);                         \
+									       \
+	uint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \
+	uint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \
+	uint64_t b64 = *b64_ptr;                                               \
+	uint64_t b = b64 << (64 - (ip)->jmp.b.n_bits);                         \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#else
+
+#define JMP_CMP_MH JMP_CMP
+#define JMP_CMP_HM JMP_CMP
+#define JMP_CMP_HH JMP_CMP
+#define JMP_CMP_HH_FAST JMP_CMP
+
+#endif
+
+#define JMP_CMP_I(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \
+	uint64_t a = a64 & a64_mask;                                           \
+									       \
+	uint64_t b = (ip)->jmp.b_val;                                          \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#define JMP_CMP_MI JMP_CMP_I
+
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+
+#define JMP_CMP_HI(thread, ip, operator)  \
+{                                                                              \
+	uint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \
+	uint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \
+	uint64_t a64 = *a64_ptr;                                               \
+	uint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \
+									       \
+	uint64_t b = (ip)->jmp.b_val;                                          \
+									       \
+	(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \
+}
+
+#else
+
+#define JMP_CMP_HI JMP_CMP_I
+
+#endif
+
+#define METADATA_READ(thread, offset, n_bits)                                  \
+({                                                                             \
+	uint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset];           \
+	uint64_t m64 = *m64_ptr;                                               \
+	uint64_t m64_mask = UINT64_MAX >> (64 - (n_bits));                     \
+	(m64 & m64_mask);                                                      \
+})
+
+#define METADATA_WRITE(thread, offset, n_bits, value)                          \
+{                                                                              \
+	uint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset];           \
+	uint64_t m64 = *m64_ptr;                                               \
+	uint64_t m64_mask = UINT64_MAX >> (64 - (n_bits));                     \
+									       \
+	uint64_t m_new = value;                                                \
+									       \
+	*m64_ptr = (m64 & ~m64_mask) | (m_new & m64_mask);                     \
+}
+
+#ifndef RTE_SWX_PIPELINE_THREADS_MAX
+#define RTE_SWX_PIPELINE_THREADS_MAX 16
+#endif
+
+struct rte_swx_pipeline {
+	struct struct_type_tailq struct_types;
+	struct port_in_type_tailq port_in_types;
+	struct port_in_tailq ports_in;
+	struct port_out_type_tailq port_out_types;
+	struct port_out_tailq ports_out;
+	struct extern_type_tailq extern_types;
+	struct extern_obj_tailq extern_objs;
+	struct extern_func_tailq extern_funcs;
+	struct header_tailq headers;
+	struct struct_type *metadata_st;
+	uint32_t metadata_struct_id;
+	struct action_tailq actions;
+	struct table_type_tailq table_types;
+	struct table_tailq tables;
+	struct selector_tailq selectors;
+	struct learner_tailq learners;
+	struct regarray_tailq regarrays;
+	struct meter_profile_tailq meter_profiles;
+	struct metarray_tailq metarrays;
+
+	struct port_in_runtime *in;
+	struct port_out_runtime *out;
+	struct instruction **action_instructions;
+	struct rte_swx_table_state *table_state;
+	struct table_statistics *table_stats;
+	struct selector_statistics *selector_stats;
+	struct learner_statistics *learner_stats;
+	struct regarray_runtime *regarray_runtime;
+	struct metarray_runtime *metarray_runtime;
+	struct instruction *instructions;
+	struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
+
+	uint32_t n_structs;
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_extern_objs;
+	uint32_t n_extern_funcs;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_headers;
+	uint32_t thread_id;
+	uint32_t port_id;
+	uint32_t n_instructions;
+	int build_done;
+	int numa_node;
+};
+
+#endif