diff mbox series

[40/40] examples/pipeline: add VXLAN encap example

Message ID 20200826151445.51500-41-cristian.dumitrescu@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers show
Series Pipeline alignment with the P4 language | expand

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/travis-robot success Travis build: passed
ci/Intel-compilation fail Compilation issues

Commit Message

Dumitrescu, Cristian Aug. 26, 2020, 3:14 p.m. UTC
Add VXLAN encapsulation example to the pipeline application. The VXLAN
tunnels can be generated with the vxlan.py script. Example command
line: ./build/pipeline -l0-1 -- -s ./examples/vxlan.cli

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/pipeline/Makefile                |   2 +-
 examples/pipeline/cli.c                   |   3 +
 examples/pipeline/example_vxlan.c         | 318 ++++++++++++++++++++++
 examples/pipeline/examples/vxlan.cli      |  27 ++
 examples/pipeline/examples/vxlan.py       |  71 +++++
 examples/pipeline/examples/vxlan.txt      |  16 ++
 examples/pipeline/examples/vxlan_pcap.cli |  22 ++
 examples/pipeline/meson.build             |   1 +
 8 files changed, 459 insertions(+), 1 deletion(-)
 create mode 100644 examples/pipeline/example_vxlan.c
 create mode 100644 examples/pipeline/examples/vxlan.cli
 create mode 100644 examples/pipeline/examples/vxlan.py
 create mode 100644 examples/pipeline/examples/vxlan.txt
 create mode 100644 examples/pipeline/examples/vxlan_pcap.cli

Comments

Stephen Hemminger Aug. 26, 2020, 5:05 p.m. UTC | #1
On Wed, 26 Aug 2020 16:14:45 +0100
Cristian Dumitrescu <cristian.dumitrescu@intel.com> wrote:

> +/*
> + * Packet headers.
> + */
> +static struct rte_swx_field_params ethernet_h[] = {
> +	{"dst_addr", 48},
> +	{"src_addr", 48},
> +	{"ether_type", 16},
> +};
> +

Could these tables be made const? Looks like read-only data.
Dumitrescu, Cristian Sept. 7, 2020, 9:49 p.m. UTC | #2
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Wednesday, August 26, 2020 6:05 PM
> To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 40/40] examples/pipeline: add VXLAN encap
> example
> 
> On Wed, 26 Aug 2020 16:14:45 +0100
> Cristian Dumitrescu <cristian.dumitrescu@intel.com> wrote:
> 
> > +/*
> > + * Packet headers.
> > + */
> > +static struct rte_swx_field_params ethernet_h[] = {
> > +	{"dst_addr", 48},
> > +	{"src_addr", 48},
> > +	{"ether_type", 16},
> > +};
> > +
> 
> Could these tables be made const? Looks like read-only data.

Thanks, Stephen, I just sent V2 where the examples have been completely reworked. The examples are now described in a pipeline specification file (closely aligned with P4) parsed at initialization, as opposed of C code.

Regards,
Cristian
diff mbox series

Patch

diff --git a/examples/pipeline/Makefile b/examples/pipeline/Makefile
index df5176296..9e8088ec4 100644
--- a/examples/pipeline/Makefile
+++ b/examples/pipeline/Makefile
@@ -12,7 +12,7 @@  SRCS-y += obj.c
 SRCS-y += thread.c
 SRCS-y += example_l2fwd.c
 SRCS-y += example_l2fwd_macswp.c
-
+SRCS-y += example_vxlan.c
 
 # Build using pkg-config variables if possible
 ifeq ($(shell pkg-config --exists libdpdk && echo 0),0)
diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 9547e1b4c..d98400c78 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -732,6 +732,7 @@  static const char cmd_pipeline_build_help[] =
 
 int pipeline_setup_l2fwd(struct rte_swx_pipeline *p);
 int pipeline_setup_l2fwd_macswp(struct rte_swx_pipeline *p);
+int pipeline_setup_vxlan(struct rte_swx_pipeline *p);
 
 static void
 cmd_pipeline_build(char **tokens,
@@ -761,6 +762,8 @@  cmd_pipeline_build(char **tokens,
 		status = pipeline_setup_l2fwd(p->p);
 	else if (!strcmp(app, "l2fwd_macswp"))
 		status = pipeline_setup_l2fwd_macswp(p->p);
+	else if (!strcmp(app, "vxlan"))
+		status = pipeline_setup_vxlan(p->p);
 	else {
 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
 		return;
diff --git a/examples/pipeline/example_vxlan.c b/examples/pipeline/example_vxlan.c
new file mode 100644
index 000000000..b4701e20f
--- /dev/null
+++ b/examples/pipeline/example_vxlan.c
@@ -0,0 +1,318 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include "rte_swx_pipeline.h"
+#include "rte_swx_table_em.h"
+
+#define CHECK(condition)                                                       \
+do {                                                                           \
+	if (!(condition)) {                                                    \
+		printf("Error in function %s at line %d\n",                    \
+			__FUNCTION__, __LINE__);                               \
+		return -1;                                                     \
+	}                                                                      \
+} while (0)
+
+/*
+ * Packet headers.
+ */
+static struct rte_swx_field_params ethernet_h[] = {
+	{"dst_addr", 48},
+	{"src_addr", 48},
+	{"ether_type", 16},
+};
+
+static struct rte_swx_field_params ipv4_h[] = {
+	{"ver_ihl", 8},
+	{"diffserv", 8},
+	{"total_len", 16},
+	{"identification", 16},
+	{"flags_offset", 16},
+	{"ttl", 8},
+	{"protocol", 8},
+	{"hdr_checksum", 16},
+	{"src_addr", 32},
+	{"dst_addr", 32},
+};
+
+static struct rte_swx_field_params udp_h[] = {
+	{"src_port", 16},
+	{"dst_port", 16},
+	{"length", 16},
+	{"checksum", 16},
+};
+
+static struct rte_swx_field_params vxlan_h[] = {
+	{"flags", 8},
+	{"reserved", 24},
+	{"vni", 24},
+	{"reserved2", 8},
+};
+
+/*
+ * Packet meta-data.
+ */
+static struct rte_swx_field_params metadata_t[] = {
+	{"port_in", 32},
+	{"port_out", 32},
+};
+
+/*
+ * Actions.
+ */
+static const char *drop_instructions[] = {
+	"mov m.port_out 4",
+	"tx m.port_out",
+};
+
+static struct rte_swx_field_params vxlan_encap_args_t[] = {
+	{"ethernet_dst_addr", 48},
+	{"ethernet_src_addr", 48},
+	{"ethernet_ether_type", 16},
+	{"ipv4_ver_ihl", 8},
+	{"ipv4_diffserv", 8},
+	{"ipv4_total_len", 16},
+	{"ipv4_identification", 16},
+	{"ipv4_flags_offset", 16},
+	{"ipv4_ttl", 8},
+	{"ipv4_protocol", 8},
+	{"ipv4_hdr_checksum", 16},
+	{"ipv4_src_addr", 32},
+	{"ipv4_dst_addr", 32},
+	{"udp_src_port", 16},
+	{"udp_dst_port", 16},
+	{"udp_length", 16},
+	{"udp_checksum", 16},
+	{"vxlan_flags", 8},
+	{"vxlan_reserved", 24},
+	{"vxlan_vni", 24},
+	{"vxlan_reserved2", 8},
+	{"port_out", 32},
+};
+
+/* Input frame:
+ *    Ethernet (14) | IPv4 (total_len)
+ *
+ * Output frame:
+ *    Ethernet (14) | IPv4 (20) | UDP (8) | VXLAN (8) | Input frame | FCS (4)
+ *
+ * Note: The input frame has its FCS removed before encapsulation in the output
+ * frame.
+ *
+ * Assumption: When read from the table, the outer IPv4 and UDP headers contain
+ * the following fields:
+ *    - t.ipv4_total_len: Set to 50, which covers the length of:
+ *         - The outer IPv4 header (20 bytes);
+ *         - The outer UDP header (8 bytes);
+ *         - The outer VXLAN header (8 bytes);
+ *         - The inner Ethernet header (14 bytes);
+ *    - t.ipv4_hdr_checksum: Includes the above total length.
+ *    - t.udp_length: Set to 30, which covers the length of:
+ *         - The outer UDP header (8 bytes);
+ *         - The outer VXLAN header (8 bytes);
+ *         - The inner Ethernet header (14 bytes);
+ *    - t.udp_checksum: Set to 0.
+ *
+ * Once the total length of the inner IPv4 packet (h.ipv4.total_len) is known,
+ * the outer IPv4 and UDP headers are updated as follows:
+ *    - h.outer_ipv4.total_len = t.ipv4_total_len + h.ipv4.total_len
+ *    - h.outer_ipv4.hdr_checksum = t.ipv4_hdr_checksum + h.ipv4.total_len
+ *    - h.outer_udp.length = t.udp_length + h.ipv4.total_len
+ *    - h.outer_udp.checksum: No change.
+ */
+static const char *vxlan_encap_instructions[] = {
+	/* Copy from table entry to haders 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",
+	"mov m.port_out t.port_out",
+
+	/* Update h.outer_ipv4.total_len field. */
+	"add h.outer_ipv4.total_len h.ipv4.total_len",
+
+	/* Update h.outer_ipv4.hdr_checksum field. */
+	"ckadd h.outer_ipv4.hdr_checksum h.ipv4.total_len",
+
+	/* Update h.outer_udp.length field. */
+	"add h.outer_udp.length h.ipv4.total_len",
+
+	"return"
+};
+
+/*
+ * Tables.
+ */
+static struct rte_swx_match_field_params table_match_fields[] = {
+	[0] = {
+		.name = "h.ethernet.dst_addr",
+		.match_type = RTE_SWX_TABLE_MATCH_EXACT,
+	},
+};
+
+static const char *table_actions[] = {"drop", "vxlan_encap"};
+
+static struct rte_swx_pipeline_table_params table_params = {
+	/* Match. */
+	.fields = table_match_fields,
+	.n_fields = RTE_DIM(table_match_fields),
+
+	/* Action. */
+	.action_names = table_actions,
+	.n_actions = RTE_DIM(table_actions),
+	.default_action_name = "drop",
+	.default_action_data = NULL,
+	.default_action_is_const = 0,
+};
+
+/*
+ * Pipeline.
+ */
+static const char *pipeline_instructions[] = {
+	"rx m.port_in",
+	"extract h.ethernet",
+	"extract h.ipv4",
+	"table vxlan",
+	"emit h.outer_ethernet",
+	"emit h.outer_ipv4",
+	"emit h.outer_udp",
+	"emit h.outer_vxlan",
+	"emit h.ethernet",
+	"emit h.ipv4",
+	"tx m.port_out",
+};
+
+int
+pipeline_setup_vxlan(struct rte_swx_pipeline *p);
+
+int
+pipeline_setup_vxlan(struct rte_swx_pipeline *p)
+{
+	int err;
+
+	/*
+	 * Packet headers.
+	 */
+	err = rte_swx_pipeline_struct_type_register(p,
+		"ethernet_h",
+		ethernet_h,
+		RTE_DIM(ethernet_h));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_struct_type_register(p,
+		"ipv4_h",
+		ipv4_h,
+		RTE_DIM(ipv4_h));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_struct_type_register(p,
+		"udp_h",
+		udp_h,
+		RTE_DIM(udp_h));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_struct_type_register(p,
+		"vxlan_h",
+		vxlan_h,
+		RTE_DIM(vxlan_h));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_header_register(p,
+		"outer_ethernet",
+		"ethernet_h");
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_header_register(p,
+		"outer_ipv4",
+		"ipv4_h");
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_header_register(p,
+		"outer_udp",
+		"udp_h");
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_header_register(p,
+		"outer_vxlan",
+		"vxlan_h");
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_header_register(p,
+		"ethernet",
+		"ethernet_h");
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_header_register(p,
+		"ipv4",
+		"ipv4_h");
+	CHECK(!err);
+
+	/*
+	 * Packet meta-data.
+	 */
+	err = rte_swx_pipeline_struct_type_register(p,
+		"metadata_t",
+		metadata_t,
+		RTE_DIM(metadata_t));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_packet_metadata_register(p,
+		"metadata_t");
+	CHECK(!err);
+
+	/*
+	 * Actions.
+	 */
+	err = rte_swx_pipeline_action_config(p,
+		"drop",
+		NULL,
+		drop_instructions,
+		RTE_DIM(drop_instructions));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_struct_type_register(p,
+		"vxlan_encap_args_t",
+		vxlan_encap_args_t,
+		RTE_DIM(vxlan_encap_args_t));
+	CHECK(!err);
+
+	err = rte_swx_pipeline_action_config(p,
+		"vxlan_encap",
+		"vxlan_encap_args_t",
+		vxlan_encap_instructions,
+		RTE_DIM(vxlan_encap_instructions));
+	CHECK(!err);
+
+	/*
+	 * Tables.
+	 */
+	err = rte_swx_pipeline_table_type_register(p,
+		"exact",
+		RTE_SWX_TABLE_MATCH_EXACT,
+		&rte_swx_table_exact_match_ops);
+	CHECK(!err);
+
+	err = rte_swx_pipeline_table_config(p,
+		"vxlan",
+		&table_params,
+		NULL,
+		NULL,
+		1 * 1024 * 1024);
+	CHECK(!err);
+
+	/*
+	 * Pipeline.
+	 */
+	err = rte_swx_pipeline_instructions_config(p,
+		pipeline_instructions,
+		RTE_DIM(pipeline_instructions));
+	CHECK(!err);
+
+	return 0;
+}
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
new file mode 100644
index 000000000..53a8b2a0a
--- /dev/null
+++ b/examples/pipeline/examples/vxlan.cli
@@ -0,0 +1,27 @@ 
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2020 Intel Corporation
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+pipeline PIPELINE0 create 0
+
+pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
+pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
+pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
+pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
+
+pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
+pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
+pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
+pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+pipeline PIPELINE0 port out 4 sink none
+
+pipeline PIPELINE0 build vxlan
+pipeline PIPELINE0 table vxlan update ./examples/vxlan.txt none none
+
+thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/vxlan.py b/examples/pipeline/examples/vxlan.py
new file mode 100644
index 000000000..179d31b53
--- /dev/null
+++ b/examples/pipeline/examples/vxlan.py
@@ -0,0 +1,71 @@ 
+#!/usr/bin/env python2
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2020 Intel Corporation
+#
+
+from __future__ import print_function
+import argparse
+import re
+import os
+
+DESCRIPTION = 'Table Generator'
+
+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})'
+
+def ipv4_header_checksum(i):
+	cksum = (0x4500 + 0x0032) + (0x0000 + 0x0000) + (0x4011 + 0x0000) + (0xc0c1 + i) + (0xd0d1 + i)
+	cksum = (cksum & 0xFFFF) + (cksum >> 16)
+	cksum = (cksum & 0xFFFF) + (cksum >> 16)
+	cksum = ~cksum & 0xFFFF
+	return cksum
+
+def table_generate(n, p):
+	for i in range(0, n):
+		print("match %s action %s %s %s %s %s %s" % (KEY.format(i),
+			ACTION,
+			ETHERNET_HEADER.format(i),
+			IPV4_HEADER.format(i, ipv4_header_checksum(i)),
+			UDP_HEADER.format(i % 256),
+			VXLAN_HEADER.format(i),
+			PORT_OUT.format(i % p)))
+
+if __name__ == '__main__':
+	parser = argparse.ArgumentParser(description=DESCRIPTION)
+
+	parser.add_argument(
+		'-n',
+		help='number of table entries (default: 65536)',
+		required=False,
+		default=65536)
+
+	parser.add_argument(
+		'-p',
+		help='number of network ports (default: 4)',
+		required=False,
+		default=4)
+
+	args = parser.parse_args()
+	table_generate(int(args.n), int(args.p))
diff --git a/examples/pipeline/examples/vxlan.txt b/examples/pipeline/examples/vxlan.txt
new file mode 100644
index 000000000..acac80a38
--- /dev/null
+++ b/examples/pipeline/examples/vxlan.txt
@@ -0,0 +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)
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
new file mode 100644
index 000000000..c406e27d3
--- /dev/null
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -0,0 +1,22 @@ 
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2020 Intel Corporation
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+pipeline PIPELINE0 create 0
+
+pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/packet.pcap
+pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/packet.pcap
+pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/packet.pcap
+pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/packet.pcap
+
+pipeline PIPELINE0 port out 0 sink none
+pipeline PIPELINE0 port out 1 sink none
+pipeline PIPELINE0 port out 2 sink none
+pipeline PIPELINE0 port out 3 sink none
+pipeline PIPELINE0 port out 4 sink none
+
+pipeline PIPELINE0 build vxlan
+pipeline PIPELINE0 table vxlan update ./examples/vxlan.txt none none
+
+thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/meson.build b/examples/pipeline/meson.build
index b13f04e01..7f6f5218b 100644
--- a/examples/pipeline/meson.build
+++ b/examples/pipeline/meson.build
@@ -17,4 +17,5 @@  sources = files(
 	'thread.c',
 	'example_l2fwd.c',
 	'example_l2fwd_macswp.c',
+	'example_vxlan.c',
 )