[dpdk-dev] [PATCH 2/2] pipeline: autodetect endianness of action args

Cristian Dumitrescu cristian.dumitrescu at intel.com
Mon Apr 12 01:23:38 CEST 2021


Each table entry is made up of match fields and action data, with the
latter made up of the action ID and the action arguments. The approach
of having the user specify explicitly the endianness of the action
arguments is difficult to be picked up by P4 compilers, as the P4
compiler is generally unaware about this aspect.

This commit introduces the auto-detection of the endianness of the
action arguments by examining the endianness of the their destination:
network byte order (NBO) when they get copied to headers and host byte
order (HBO) when they get copied to packet meta-data or mailboxes.

The endianness specification of each action argument as part of the
rule specification, e.g. H(...) and N(...) is removed from the rule
file and auto-detected based on their destination. The DMA instruction
scope is made internal, so mov instructions need to be used. The
pattern of transferring complete headers from table entry action args
to headers is detected, and the associated set of mov instructions
plus header validate is internally detected and replaced with the
internal-only DMA instruction to preserve performance.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu at intel.com>
---
 examples/pipeline/examples/vxlan.spec      |  41 ++-
 examples/pipeline/examples/vxlan_table.py  |  44 ++--
 examples/pipeline/examples/vxlan_table.txt |  32 +--
 lib/librte_pipeline/rte_swx_ctl.c          |  15 +-
 lib/librte_pipeline/rte_swx_ctl.h          |   6 +
 lib/librte_pipeline/rte_swx_pipeline.c     | 282 ++++++++++++++++++---
 lib/librte_pipeline/rte_swx_pipeline.h     |   4 -
 7 files changed, 322 insertions(+), 102 deletions(-)

diff --git a/examples/pipeline/examples/vxlan.spec b/examples/pipeline/examples/vxlan.spec
index 347dca29d..ac62ab2be 100644
--- a/examples/pipeline/examples/vxlan.spec
+++ b/examples/pipeline/examples/vxlan.spec
@@ -60,7 +60,7 @@ metadata instanceof metadata_t
 struct vxlan_encap_args_t {
 	bit<48> ethernet_dst_addr
 	bit<48> ethernet_src_addr
-	bit<16> ethernet_ether_type
+	bit<16> ethernet_ethertype
 	bit<8> ipv4_ver_ihl
 	bit<8> ipv4_diffserv
 	bit<16> ipv4_total_len
@@ -114,11 +114,40 @@ struct vxlan_encap_args_t {
 //
 
 action vxlan_encap args instanceof vxlan_encap_args_t {
-	//Copy from table entry to headers and metadata.
-	dma h.outer_ethernet t.ethernet_dst_addr
-	dma h.outer_ipv4 t.ipv4_ver_ihl
-	dma h.outer_udp t.udp_src_port
-	dma h.outer_vxlan t.vxlan_flags
+	//Set the outer Ethernet header.
+	mov h.outer_ethernet.dst_addr t.ethernet_dst_addr
+	mov h.outer_ethernet.src_addr t.ethernet_src_addr
+	mov h.outer_ethernet.ethertype t.ethernet_ethertype
+	validate h.outer_ethernet
+
+	//Set the outer IPv4 header.
+	mov h.outer_ipv4.ver_ihl t.ipv4_ver_ihl
+	mov h.outer_ipv4.diffserv t.ipv4_diffserv
+	mov h.outer_ipv4.total_len t.ipv4_total_len
+	mov h.outer_ipv4.identification t.ipv4_identification
+	mov h.outer_ipv4.flags_offset t.ipv4_flags_offset
+	mov h.outer_ipv4.ttl t.ipv4_ttl
+	mov h.outer_ipv4.protocol t.ipv4_protocol
+	mov h.outer_ipv4.hdr_checksum t.ipv4_hdr_checksum
+	mov h.outer_ipv4.src_addr t.ipv4_src_addr
+	mov h.outer_ipv4.dst_addr t.ipv4_dst_addr
+	validate h.outer_ipv4
+
+	//Set the outer UDP header.
+	mov h.outer_udp.src_port t.udp_src_port
+	mov h.outer_udp.dst_port t.udp_dst_port
+	mov h.outer_udp.length t.udp_length
+	mov h.outer_udp.checksum t.udp_checksum
+	validate h.outer_udp
+
+	//Set the outer VXLAN header.
+	mov h.outer_vxlan.flags t.vxlan_flags
+	mov h.outer_vxlan.reserved t.vxlan_reserved
+	mov h.outer_vxlan.vni t.vxlan_vni
+	mov h.outer_vxlan.reserved2 t.vxlan_reserved2
+	validate h.outer_vxlan
+
+	//Set the output port.
 	mov m.port_out t.port_out
 
 	//Update h.outer_ipv4.total_len field.
diff --git a/examples/pipeline/examples/vxlan_table.py b/examples/pipeline/examples/vxlan_table.py
index 820c208c7..b1c6f1acd 100755
--- a/examples/pipeline/examples/vxlan_table.py
+++ b/examples/pipeline/examples/vxlan_table.py
@@ -13,28 +13,28 @@
 
 KEY = '0xaabbccdd{0:04x}'
 ACTION = 'vxlan_encap'
-ETHERNET_HEADER = 'ethernet_dst_addr N(0xa0a1a2a3{0:04x}) ' \
-    'ethernet_src_addr N(0xb0b1b2b3{0:04x}) ' \
-    'ethernet_ether_type N(0x0800)'
-IPV4_HEADER = 'ipv4_ver_ihl N(0x45) ' \
-    'ipv4_diffserv N(0) ' \
-    'ipv4_total_len N(50) ' \
-    'ipv4_identification N(0) ' \
-    'ipv4_flags_offset N(0) ' \
-    'ipv4_ttl N(64) ' \
-    'ipv4_protocol N(17) ' \
-    'ipv4_hdr_checksum N(0x{1:04x}) ' \
-    'ipv4_src_addr N(0xc0c1{0:04x}) ' \
-    'ipv4_dst_addr N(0xd0d1{0:04x})'
-UDP_HEADER = 'udp_src_port N(0xe0{0:02x}) ' \
-    'udp_dst_port N(4789) ' \
-    'udp_length N(30) ' \
-    'udp_checksum N(0)'
-VXLAN_HEADER = 'vxlan_flags N(0) ' \
-    'vxlan_reserved N(0) ' \
-    'vxlan_vni N({0:d}) ' \
-    'vxlan_reserved2 N(0)'
-PORT_OUT = 'port_out H({0:d})'
+ETHERNET_HEADER = 'ethernet_dst_addr 0xa0a1a2a3{0:04x} ' \
+    'ethernet_src_addr 0xb0b1b2b3{0:04x} ' \
+    'ethernet_ethertype 0x0800'
+IPV4_HEADER = 'ipv4_ver_ihl 0x45 ' \
+    'ipv4_diffserv 0 ' \
+    'ipv4_total_len 50 ' \
+    'ipv4_identification 0 ' \
+    'ipv4_flags_offset 0 ' \
+    'ipv4_ttl 64 ' \
+    'ipv4_protocol 17 ' \
+    'ipv4_hdr_checksum 0x{1:04x} ' \
+    'ipv4_src_addr 0xc0c1{0:04x} ' \
+    'ipv4_dst_addr 0xd0d1{0:04x}'
+UDP_HEADER = 'udp_src_port 0xe0{0:02x} ' \
+    'udp_dst_port 4789 ' \
+    'udp_length 30 ' \
+    'udp_checksum 0'
+VXLAN_HEADER = 'vxlan_flags 0 ' \
+    'vxlan_reserved 0 ' \
+    'vxlan_vni {0:d} ' \
+    'vxlan_reserved2 0'
+PORT_OUT = 'port_out {0:d}'
 
 def ipv4_header_checksum(i):
     cksum = (0x4500 + 0x0032) + (0x0000 + 0x0000) + (0x4011 + 0x0000) + (0xc0c1 + i) + (0xd0d1 + i)
diff --git a/examples/pipeline/examples/vxlan_table.txt b/examples/pipeline/examples/vxlan_table.txt
index acac80a38..25ca647ab 100644
--- a/examples/pipeline/examples/vxlan_table.txt
+++ b/examples/pipeline/examples/vxlan_table.txt
@@ -1,16 +1,16 @@
-match 0xaabbccdd0000 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30000) ethernet_src_addr N(0xb0b1b2b30000) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe928) ipv4_src_addr N(0xc0c10000) ipv4_dst_addr N(0xd0d10000) udp_src_port N(0xe000) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(0) vxlan_reserved2 N(0) port_out H(0)
-match 0xaabbccdd0001 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30001) ethernet_src_addr N(0xb0b1b2b30001) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe926) ipv4_src_addr N(0xc0c10001) ipv4_dst_addr N(0xd0d10001) udp_src_port N(0xe001) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(1) vxlan_reserved2 N(0) port_out H(1)
-match 0xaabbccdd0002 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30002) ethernet_src_addr N(0xb0b1b2b30002) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe924) ipv4_src_addr N(0xc0c10002) ipv4_dst_addr N(0xd0d10002) udp_src_port N(0xe002) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(2) vxlan_reserved2 N(0) port_out H(2)
-match 0xaabbccdd0003 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30003) ethernet_src_addr N(0xb0b1b2b30003) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe922) ipv4_src_addr N(0xc0c10003) ipv4_dst_addr N(0xd0d10003) udp_src_port N(0xe003) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(3) vxlan_reserved2 N(0) port_out H(3)
-match 0xaabbccdd0004 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30004) ethernet_src_addr N(0xb0b1b2b30004) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe920) ipv4_src_addr N(0xc0c10004) ipv4_dst_addr N(0xd0d10004) udp_src_port N(0xe004) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(4) vxlan_reserved2 N(0) port_out H(0)
-match 0xaabbccdd0005 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30005) ethernet_src_addr N(0xb0b1b2b30005) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe91e) ipv4_src_addr N(0xc0c10005) ipv4_dst_addr N(0xd0d10005) udp_src_port N(0xe005) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(5) vxlan_reserved2 N(0) port_out H(1)
-match 0xaabbccdd0006 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30006) ethernet_src_addr N(0xb0b1b2b30006) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe91c) ipv4_src_addr N(0xc0c10006) ipv4_dst_addr N(0xd0d10006) udp_src_port N(0xe006) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(6) vxlan_reserved2 N(0) port_out H(2)
-match 0xaabbccdd0007 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30007) ethernet_src_addr N(0xb0b1b2b30007) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe91a) ipv4_src_addr N(0xc0c10007) ipv4_dst_addr N(0xd0d10007) udp_src_port N(0xe007) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(7) vxlan_reserved2 N(0) port_out H(3)
-match 0xaabbccdd0008 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30008) ethernet_src_addr N(0xb0b1b2b30008) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe918) ipv4_src_addr N(0xc0c10008) ipv4_dst_addr N(0xd0d10008) udp_src_port N(0xe008) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(8) vxlan_reserved2 N(0) port_out H(0)
-match 0xaabbccdd0009 action vxlan_encap ethernet_dst_addr N(0xa0a1a2a30009) ethernet_src_addr N(0xb0b1b2b30009) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe916) ipv4_src_addr N(0xc0c10009) ipv4_dst_addr N(0xd0d10009) udp_src_port N(0xe009) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(9) vxlan_reserved2 N(0) port_out H(1)
-match 0xaabbccdd000a action vxlan_encap ethernet_dst_addr N(0xa0a1a2a3000a) ethernet_src_addr N(0xb0b1b2b3000a) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe914) ipv4_src_addr N(0xc0c1000a) ipv4_dst_addr N(0xd0d1000a) udp_src_port N(0xe00a) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(10) vxlan_reserved2 N(0) port_out H(2)
-match 0xaabbccdd000b action vxlan_encap ethernet_dst_addr N(0xa0a1a2a3000b) ethernet_src_addr N(0xb0b1b2b3000b) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe912) ipv4_src_addr N(0xc0c1000b) ipv4_dst_addr N(0xd0d1000b) udp_src_port N(0xe00b) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(11) vxlan_reserved2 N(0) port_out H(3)
-match 0xaabbccdd000c action vxlan_encap ethernet_dst_addr N(0xa0a1a2a3000c) ethernet_src_addr N(0xb0b1b2b3000c) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe910) ipv4_src_addr N(0xc0c1000c) ipv4_dst_addr N(0xd0d1000c) udp_src_port N(0xe00c) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(12) vxlan_reserved2 N(0) port_out H(0)
-match 0xaabbccdd000d action vxlan_encap ethernet_dst_addr N(0xa0a1a2a3000d) ethernet_src_addr N(0xb0b1b2b3000d) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe90e) ipv4_src_addr N(0xc0c1000d) ipv4_dst_addr N(0xd0d1000d) udp_src_port N(0xe00d) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(13) vxlan_reserved2 N(0) port_out H(1)
-match 0xaabbccdd000e action vxlan_encap ethernet_dst_addr N(0xa0a1a2a3000e) ethernet_src_addr N(0xb0b1b2b3000e) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe90c) ipv4_src_addr N(0xc0c1000e) ipv4_dst_addr N(0xd0d1000e) udp_src_port N(0xe00e) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(14) vxlan_reserved2 N(0) port_out H(2)
-match 0xaabbccdd000f action vxlan_encap ethernet_dst_addr N(0xa0a1a2a3000f) ethernet_src_addr N(0xb0b1b2b3000f) ethernet_ether_type N(0x0800) ipv4_ver_ihl N(0x45) ipv4_diffserv N(0) ipv4_total_len N(50) ipv4_identification N(0) ipv4_flags_offset N(0) ipv4_ttl N(64) ipv4_protocol N(17) ipv4_hdr_checksum N(0xe90a) ipv4_src_addr N(0xc0c1000f) ipv4_dst_addr N(0xd0d1000f) udp_src_port N(0xe00f) udp_dst_port N(4789) udp_length N(30) udp_checksum N(0) vxlan_flags N(0) vxlan_reserved N(0) vxlan_vni N(15) vxlan_reserved2 N(0) port_out H(3)
+match 0xaabbccdd0000 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30000 ethernet_src_addr 0xb0b1b2b30000 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe928 ipv4_src_addr 0xc0c10000 ipv4_dst_addr 0xd0d10000 udp_src_port 0xe000 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 0 vxlan_reserved2 0 port_out 0
+match 0xaabbccdd0001 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30001 ethernet_src_addr 0xb0b1b2b30001 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe926 ipv4_src_addr 0xc0c10001 ipv4_dst_addr 0xd0d10001 udp_src_port 0xe001 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 1 vxlan_reserved2 0 port_out 1
+match 0xaabbccdd0002 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30002 ethernet_src_addr 0xb0b1b2b30002 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe924 ipv4_src_addr 0xc0c10002 ipv4_dst_addr 0xd0d10002 udp_src_port 0xe002 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 2 vxlan_reserved2 0 port_out 2
+match 0xaabbccdd0003 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30003 ethernet_src_addr 0xb0b1b2b30003 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe922 ipv4_src_addr 0xc0c10003 ipv4_dst_addr 0xd0d10003 udp_src_port 0xe003 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 3 vxlan_reserved2 0 port_out 3
+match 0xaabbccdd0004 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30004 ethernet_src_addr 0xb0b1b2b30004 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe920 ipv4_src_addr 0xc0c10004 ipv4_dst_addr 0xd0d10004 udp_src_port 0xe004 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 4 vxlan_reserved2 0 port_out 0
+match 0xaabbccdd0005 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30005 ethernet_src_addr 0xb0b1b2b30005 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe91e ipv4_src_addr 0xc0c10005 ipv4_dst_addr 0xd0d10005 udp_src_port 0xe005 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 5 vxlan_reserved2 0 port_out 1
+match 0xaabbccdd0006 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30006 ethernet_src_addr 0xb0b1b2b30006 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe91c ipv4_src_addr 0xc0c10006 ipv4_dst_addr 0xd0d10006 udp_src_port 0xe006 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 6 vxlan_reserved2 0 port_out 2
+match 0xaabbccdd0007 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30007 ethernet_src_addr 0xb0b1b2b30007 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe91a ipv4_src_addr 0xc0c10007 ipv4_dst_addr 0xd0d10007 udp_src_port 0xe007 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 7 vxlan_reserved2 0 port_out 3
+match 0xaabbccdd0008 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30008 ethernet_src_addr 0xb0b1b2b30008 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe918 ipv4_src_addr 0xc0c10008 ipv4_dst_addr 0xd0d10008 udp_src_port 0xe008 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 8 vxlan_reserved2 0 port_out 0
+match 0xaabbccdd0009 action vxlan_encap ethernet_dst_addr 0xa0a1a2a30009 ethernet_src_addr 0xb0b1b2b30009 ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe916 ipv4_src_addr 0xc0c10009 ipv4_dst_addr 0xd0d10009 udp_src_port 0xe009 udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 9 vxlan_reserved2 0 port_out 1
+match 0xaabbccdd000a action vxlan_encap ethernet_dst_addr 0xa0a1a2a3000a ethernet_src_addr 0xb0b1b2b3000a ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe914 ipv4_src_addr 0xc0c1000a ipv4_dst_addr 0xd0d1000a udp_src_port 0xe00a udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 10 vxlan_reserved2 0 port_out 2
+match 0xaabbccdd000b action vxlan_encap ethernet_dst_addr 0xa0a1a2a3000b ethernet_src_addr 0xb0b1b2b3000b ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe912 ipv4_src_addr 0xc0c1000b ipv4_dst_addr 0xd0d1000b udp_src_port 0xe00b udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 11 vxlan_reserved2 0 port_out 3
+match 0xaabbccdd000c action vxlan_encap ethernet_dst_addr 0xa0a1a2a3000c ethernet_src_addr 0xb0b1b2b3000c ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe910 ipv4_src_addr 0xc0c1000c ipv4_dst_addr 0xd0d1000c udp_src_port 0xe00c udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 12 vxlan_reserved2 0 port_out 0
+match 0xaabbccdd000d action vxlan_encap ethernet_dst_addr 0xa0a1a2a3000d ethernet_src_addr 0xb0b1b2b3000d ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe90e ipv4_src_addr 0xc0c1000d ipv4_dst_addr 0xd0d1000d udp_src_port 0xe00d udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 13 vxlan_reserved2 0 port_out 1
+match 0xaabbccdd000e action vxlan_encap ethernet_dst_addr 0xa0a1a2a3000e ethernet_src_addr 0xb0b1b2b3000e ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe90c ipv4_src_addr 0xc0c1000e ipv4_dst_addr 0xd0d1000e udp_src_port 0xe00e udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 14 vxlan_reserved2 0 port_out 2
+match 0xaabbccdd000f action vxlan_encap ethernet_dst_addr 0xa0a1a2a3000f ethernet_src_addr 0xb0b1b2b3000f ethernet_ethertype 0x0800 ipv4_ver_ihl 0x45 ipv4_diffserv 0 ipv4_total_len 50 ipv4_identification 0 ipv4_flags_offset 0 ipv4_ttl 64 ipv4_protocol 17 ipv4_hdr_checksum 0xe90a ipv4_src_addr 0xc0c1000f ipv4_dst_addr 0xd0d1000f udp_src_port 0xe00f udp_dst_port 4789 udp_length 30 udp_checksum 0 vxlan_flags 0 vxlan_reserved 0 vxlan_vni 15 vxlan_reserved2 0 port_out 3
diff --git a/lib/librte_pipeline/rte_swx_ctl.c b/lib/librte_pipeline/rte_swx_ctl.c
index ca30767ef..4d1ff9ead 100644
--- a/lib/librte_pipeline/rte_swx_ctl.c
+++ b/lib/librte_pipeline/rte_swx_ctl.c
@@ -1721,30 +1721,19 @@ rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl,
 		struct rte_swx_ctl_action_arg_info *arg = &action->args[i];
 		char *arg_name, *arg_val;
 		uint64_t val;
-		int is_nbo = 0;
 
 		arg_name = tokens[2 + i * 2];
 		arg_val = tokens[2 + i * 2 + 1];
 
-		if (strcmp(arg_name, arg->name) ||
-		    (strlen(arg_val) < 4) ||
-		    ((arg_val[0] != 'H') && (arg_val[0] != 'N')) ||
-		    (arg_val[1] != '(') ||
-		    (arg_val[strlen(arg_val) - 1] != ')'))
+		if (strcmp(arg_name, arg->name))
 			goto error;
 
-		if (arg_val[0] == 'N')
-			is_nbo = 1;
-
-		arg_val[strlen(arg_val) - 1] = 0; /* Remove the ')'. */
-		arg_val += 2; /* Remove the "H(" or "N(". */
-
 		val = strtoull(arg_val, &arg_val, 0);
 		if (arg_val[0])
 			goto error;
 
 		/* Endianness conversion. */
-		if (is_nbo)
+		if (arg->is_network_byte_order)
 			val = field_hton(val, arg->n_bits);
 
 		/* Copy to entry. */
diff --git a/lib/librte_pipeline/rte_swx_ctl.h b/lib/librte_pipeline/rte_swx_ctl.h
index b8f22c516..4e5befb50 100644
--- a/lib/librte_pipeline/rte_swx_ctl.h
+++ b/lib/librte_pipeline/rte_swx_ctl.h
@@ -168,6 +168,12 @@ struct rte_swx_ctl_action_arg_info {
 
 	/** Action argument size (in bits). */
 	uint32_t n_bits;
+
+	/** Non-zero (true) when this action argument must be stored in the
+	 * table in network byte order (NBO), zero when it must be stored in
+	 * host byte order (HBO).
+	 */
+	int is_network_byte_order;
 };
 
 /**
diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c
index ba828cbda..d9f47b07e 100644
--- a/lib/librte_pipeline/rte_swx_pipeline.c
+++ b/lib/librte_pipeline/rte_swx_pipeline.c
@@ -733,6 +733,7 @@ struct action {
 	TAILQ_ENTRY(action) node;
 	char name[RTE_SWX_NAME_SIZE];
 	struct struct_type *st;
+	int *args_endianness; /* 0 = Host Byte Order (HBO). */
 	struct instruction *instructions;
 	uint32_t n_instructions;
 	uint32_t id;
@@ -2342,6 +2343,18 @@ header_find(struct rte_swx_pipeline *p, const char *name)
 	return NULL;
 }
 
+static struct header *
+header_find_by_struct_id(struct rte_swx_pipeline *p, uint32_t struct_id)
+{
+	struct header *elem;
+
+	TAILQ_FOREACH(elem, &p->headers, node)
+		if (elem->struct_id == struct_id)
+			return elem;
+
+	return NULL;
+}
+
 static struct header *
 header_parse(struct rte_swx_pipeline *p,
 	     const char *name)
@@ -3722,37 +3735,6 @@ instr_mov_i_exec(struct rte_swx_pipeline *p)
 /*
  * dma.
  */
-static int
-instr_dma_translate(struct rte_swx_pipeline *p,
-		    struct action *action,
-		    char **tokens,
-		    int n_tokens,
-		    struct instruction *instr,
-		    struct instruction_data *data __rte_unused)
-{
-	char *dst = tokens[1];
-	char *src = tokens[2];
-	struct header *h;
-	struct field *tf;
-
-	CHECK(action, EINVAL);
-	CHECK(n_tokens == 3, EINVAL);
-
-	h = header_parse(p, dst);
-	CHECK(h, EINVAL);
-
-	tf = action_field_parse(action, src);
-	CHECK(tf, EINVAL);
-
-	instr->type = INSTR_DMA_HT;
-	instr->dma.dst.header_id[0] = h->id;
-	instr->dma.dst.struct_id[0] = h->struct_id;
-	instr->dma.n_bytes[0] = h->st->n_bits / 8;
-	instr->dma.src.offset[0] = tf->offset / 8;
-
-	return 0;
-}
-
 static inline void
 __instr_dma_ht_exec(struct rte_swx_pipeline *p, uint32_t n_dma);
 
@@ -7710,14 +7692,6 @@ instr_translate(struct rte_swx_pipeline *p,
 					   instr,
 					   data);
 
-	if (!strcmp(tokens[tpos], "dma"))
-		return instr_dma_translate(p,
-					   action,
-					   &tokens[tpos],
-					   n_tokens - tpos,
-					   instr,
-					   data);
-
 	if (!strcmp(tokens[tpos], "add"))
 		return instr_alu_add_translate(p,
 					       action,
@@ -8294,6 +8268,180 @@ instr_pattern_emit_many_tx_optimize(struct instruction *instructions,
 	return n_instructions;
 }
 
+static uint32_t
+action_arg_src_mov_count(struct action *a,
+			 uint32_t arg_id,
+			 struct instruction *instructions,
+			 struct instruction_data *instruction_data,
+			 uint32_t n_instructions);
+
+static int
+instr_pattern_mov_all_validate_search(struct rte_swx_pipeline *p,
+				      struct action *a,
+				      struct instruction *instr,
+				      struct instruction_data *data,
+				      uint32_t n_instr,
+				      struct instruction *instructions,
+				      struct instruction_data *instruction_data,
+				      uint32_t n_instructions,
+				      uint32_t *n_pattern_instr)
+{
+	struct header *h;
+	uint32_t src_field_id, i, j;
+
+	/* Prerequisites. */
+	if (!a || !a->st)
+		return 0;
+
+	/* First instruction: MOV_HM. */
+	if (data[0].invalid || (instr[0].type != INSTR_MOV_HM))
+		return 0;
+
+	h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id);
+	if (!h)
+		return 0;
+
+	for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++)
+		if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8)
+			break;
+
+	if (src_field_id == a->st->n_fields)
+		return 0;
+
+	if (instr[0].mov.dst.offset ||
+	    (instr[0].mov.dst.n_bits != h->st->fields[0].n_bits) ||
+	    instr[0].mov.src.struct_id ||
+	    (instr[0].mov.src.n_bits != a->st->fields[src_field_id].n_bits) ||
+	    (instr[0].mov.dst.n_bits != instr[0].mov.src.n_bits))
+		return 0;
+
+	if ((n_instr < h->st->n_fields + 1) ||
+	     (a->st->n_fields < src_field_id + h->st->n_fields + 1))
+		return 0;
+
+	/* Subsequent instructions: MOV_HM. */
+	for (i = 1; i < h->st->n_fields; i++)
+		if (data[i].invalid ||
+		    data[i].n_users ||
+		    (instr[i].type != INSTR_MOV_HM) ||
+		    (instr[i].mov.dst.struct_id != h->struct_id) ||
+		    (instr[i].mov.dst.offset != h->st->fields[i].offset / 8) ||
+		    (instr[i].mov.dst.n_bits != h->st->fields[i].n_bits) ||
+		    instr[i].mov.src.struct_id ||
+		    (instr[i].mov.src.offset != a->st->fields[src_field_id + i].offset / 8) ||
+		    (instr[i].mov.src.n_bits != a->st->fields[src_field_id + i].n_bits) ||
+		    (instr[i].mov.dst.n_bits != instr[i].mov.src.n_bits))
+			return 0;
+
+	/* Last instruction: HDR_VALIDATE. */
+	if ((instr[i].type != INSTR_HDR_VALIDATE) ||
+	    (instr[i].valid.header_id != h->id))
+		return 0;
+
+	/* Check that none of the action args that are used as source for this
+	 * DMA transfer are not used as source in any other mov instruction.
+	 */
+	for (j = src_field_id; j < src_field_id + h->st->n_fields; j++) {
+		uint32_t n_users;
+
+		n_users = action_arg_src_mov_count(a,
+						   j,
+						   instructions,
+						   instruction_data,
+						   n_instructions);
+		if (n_users > 1)
+			return 0;
+	}
+
+	*n_pattern_instr = 1 + i;
+	return 1;
+}
+
+static void
+instr_pattern_mov_all_validate_replace(struct rte_swx_pipeline *p,
+				       struct action *a,
+				       struct instruction *instr,
+				       struct instruction_data *data,
+				       uint32_t n_instr)
+{
+	struct header *h;
+	uint32_t src_field_id, src_offset, i;
+
+	/* Read from the instructions before they are modified. */
+	h = header_find_by_struct_id(p, instr[0].mov.dst.struct_id);
+	if (!h)
+		return;
+
+	for (src_field_id = 0; src_field_id < a->st->n_fields; src_field_id++)
+		if (instr[0].mov.src.offset == a->st->fields[src_field_id].offset / 8)
+			break;
+
+	if (src_field_id == a->st->n_fields)
+		return;
+
+	src_offset = instr[0].mov.src.offset;
+
+	/* Modify the instructions. */
+	instr[0].type = INSTR_DMA_HT;
+	instr[0].dma.dst.header_id[0] = h->id;
+	instr[0].dma.dst.struct_id[0] = h->struct_id;
+	instr[0].dma.src.offset[0] = (uint8_t)src_offset;
+	instr[0].dma.n_bytes[0] = h->st->n_bits / 8;
+
+	for (i = 1; i < n_instr; i++)
+		data[i].invalid = 1;
+
+	/* Update the endianness of the action arguments to header endianness. */
+	for (i = 0; i < h->st->n_fields; i++)
+		a->args_endianness[src_field_id + i] = 1;
+}
+
+static uint32_t
+instr_pattern_mov_all_validate_optimize(struct rte_swx_pipeline *p,
+					struct action *a,
+					struct instruction *instructions,
+					struct instruction_data *instruction_data,
+					uint32_t n_instructions)
+{
+	uint32_t i;
+
+	if (!a || !a->st)
+		return n_instructions;
+
+	for (i = 0; i < n_instructions; ) {
+		struct instruction *instr = &instructions[i];
+		struct instruction_data *data = &instruction_data[i];
+		uint32_t n_instr = 0;
+		int detected;
+
+		/* Mov all + validate. */
+		detected = instr_pattern_mov_all_validate_search(p,
+								 a,
+								 instr,
+								 data,
+								 n_instructions - i,
+								 instructions,
+								 instruction_data,
+								 n_instructions,
+								 &n_instr);
+		if (detected) {
+			instr_pattern_mov_all_validate_replace(p, a, instr, data, n_instr);
+			i += n_instr;
+			continue;
+		}
+
+		/* No pattern starting at the current instruction. */
+		i++;
+	}
+
+	/* Eliminate the invalid instructions that have been optimized out. */
+	n_instructions = instr_compact(instructions,
+				       instruction_data,
+				       n_instructions);
+
+	return n_instructions;
+}
+
 static int
 instr_pattern_dma_many_search(struct instruction *instr,
 			      struct instruction_data *data,
@@ -8378,7 +8526,9 @@ instr_pattern_dma_many_optimize(struct instruction *instructions,
 }
 
 static uint32_t
-instr_optimize(struct instruction *instructions,
+instr_optimize(struct rte_swx_pipeline *p,
+	       struct action *a,
+	       struct instruction *instructions,
 	       struct instruction_data *instruction_data,
 	       uint32_t n_instructions)
 {
@@ -8392,6 +8542,13 @@ instr_optimize(struct instruction *instructions,
 							     instruction_data,
 							     n_instructions);
 
+	/* Mov all + validate. */
+	n_instructions = instr_pattern_mov_all_validate_optimize(p,
+								 a,
+								 instructions,
+								 instruction_data,
+								 n_instructions);
+
 	/* DMA many. */
 	n_instructions = instr_pattern_dma_many_optimize(instructions,
 							 instruction_data,
@@ -8453,7 +8610,7 @@ instruction_config(struct rte_swx_pipeline *p,
 	if (err)
 		goto error;
 
-	n_instructions = instr_optimize(instr, data, n_instructions);
+	n_instructions = instr_optimize(p, a, instr, data, n_instructions);
 
 	err = instr_jmp_resolve(instr, data, n_instructions);
 	if (err)
@@ -8742,6 +8899,13 @@ rte_swx_pipeline_action_config(struct rte_swx_pipeline *p,
 	/* Node allocation. */
 	a = calloc(1, sizeof(struct action));
 	CHECK(a, ENOMEM);
+	if (args_struct_type) {
+		a->args_endianness = calloc(args_struct_type->n_fields, sizeof(int));
+		if (!a->args_endianness) {
+			free(a);
+			CHECK(0, ENOMEM);
+		}
+	}
 
 	/* Node initialization. */
 	strcpy(a->name, name);
@@ -8751,6 +8915,7 @@ rte_swx_pipeline_action_config(struct rte_swx_pipeline *p,
 	/* Instruction translation. */
 	err = instruction_config(p, a, instructions, n_instructions);
 	if (err) {
+		free(a->args_endianness);
 		free(a);
 		return err;
 	}
@@ -8802,6 +8967,40 @@ action_free(struct rte_swx_pipeline *p)
 	}
 }
 
+static uint32_t
+action_arg_src_mov_count(struct action *a,
+			 uint32_t arg_id,
+			 struct instruction *instructions,
+			 struct instruction_data *instruction_data,
+			 uint32_t n_instructions)
+{
+	uint32_t offset, n_users = 0, i;
+
+	if (!a->st ||
+	    (arg_id >= a->st->n_fields) ||
+	    !instructions ||
+	    !instruction_data ||
+	    !n_instructions)
+		return 0;
+
+	offset = a->st->fields[arg_id].offset / 8;
+
+	for (i = 0; i < n_instructions; i++) {
+		struct instruction *instr = &instructions[i];
+		struct instruction_data *data = &instruction_data[i];
+
+		if (data->invalid ||
+		    ((instr->type != INSTR_MOV) && (instr->type != INSTR_MOV_HM)) ||
+		    instr->mov.src.struct_id ||
+		    (instr->mov.src.offset != offset))
+			continue;
+
+		n_users++;
+	}
+
+	return n_users;
+}
+
 /*
  * Table.
  */
@@ -9898,6 +10097,7 @@ rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p,
 	arg = &a->st->fields[action_arg_id];
 	strcpy(action_arg->name, arg->name);
 	action_arg->n_bits = arg->n_bits;
+	action_arg->is_network_byte_order = a->args_endianness[action_arg_id];
 
 	return 0;
 }
diff --git a/lib/librte_pipeline/rte_swx_pipeline.h b/lib/librte_pipeline/rte_swx_pipeline.h
index 156b1fd67..feeb10a5c 100644
--- a/lib/librte_pipeline/rte_swx_pipeline.h
+++ b/lib/librte_pipeline/rte_swx_pipeline.h
@@ -406,10 +406,6 @@ rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
  *<pre>+------------+----------------------+-------------------+------+--------+</pre>
  *<pre>| mov        | dst = src            | mov dst src       | HMEF | HMEFTI |</pre>
  *<pre>+------------+----------------------+-------------------+------+--------+</pre>
- *<pre>| dma        | memcpy(h.hdr,        | dma h.hdr t.field | hdr  | T      |</pre>
- *<pre>|            |    &t.field,         |                   |      |        |</pre>
- *<pre>|            |    sizeof(h.hdr)     |                   |      |        |</pre>
- *<pre>+------------+----------------------+-------------------+------+--------+</pre>
  *<pre>| add        | dst += src           | add dst src       | HMEF | HMEFTI |</pre>
  *<pre>+------------+----------------------+-------------------+------+--------+</pre>
  *<pre>| sub        | dst -= src           | add dst src       | HMEF | HMEFTI |</pre>
-- 
2.17.1



More information about the dev mailing list