[1/2] pipeline: add vxlan encap

Message ID 1536335931-171094-1-git-send-email-cristian.dumitrescu@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Cristian Dumitrescu
Headers
Series [1/2] pipeline: add vxlan encap |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation success Compilation OK

Commit Message

Cristian Dumitrescu Sept. 7, 2018, 3:58 p.m. UTC
  Add support for VXLAN as part of the encap table action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 356 +++++++++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h |  75 +++++++
 2 files changed, 431 insertions(+)
  

Patch

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 83ffa5d..338dcfe 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -430,6 +430,7 @@  encap_valid(enum rte_table_action_encap_type encap)
 	case RTE_TABLE_ACTION_ENCAP_QINQ:
 	case RTE_TABLE_ACTION_ENCAP_MPLS:
 	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+	case RTE_TABLE_ACTION_ENCAP_VXLAN:
 		return 1;
 	default:
 		return 0;
@@ -498,6 +499,38 @@  struct encap_pppoe_data {
 	struct pppoe_ppp_hdr pppoe_ppp;
 } __attribute__((__packed__));
 
+#define IP_PROTO_UDP                                       17
+
+struct encap_vxlan_ipv4_data {
+	struct ether_hdr ether;
+	struct ipv4_hdr ipv4;
+	struct udp_hdr udp;
+	struct vxlan_hdr vxlan;
+} __attribute__((__packed__));
+
+struct encap_vxlan_ipv4_vlan_data {
+	struct ether_hdr ether;
+	struct vlan_hdr vlan;
+	struct ipv4_hdr ipv4;
+	struct udp_hdr udp;
+	struct vxlan_hdr vxlan;
+} __attribute__((__packed__));
+
+struct encap_vxlan_ipv6_data {
+	struct ether_hdr ether;
+	struct ipv6_hdr ipv6;
+	struct udp_hdr udp;
+	struct vxlan_hdr vxlan;
+} __attribute__((__packed__));
+
+struct encap_vxlan_ipv6_vlan_data {
+	struct ether_hdr ether;
+	struct vlan_hdr vlan;
+	struct ipv6_hdr ipv6;
+	struct udp_hdr udp;
+	struct vxlan_hdr vxlan;
+} __attribute__((__packed__));
+
 static size_t
 encap_data_size(struct rte_table_action_encap_config *encap)
 {
@@ -517,6 +550,18 @@  encap_data_size(struct rte_table_action_encap_config *encap)
 	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
 		return sizeof(struct encap_pppoe_data);
 
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN:
+		if (encap->vxlan.ip_version)
+			if (encap->vxlan.vlan)
+				return sizeof(struct encap_vxlan_ipv4_vlan_data);
+			else
+				return sizeof(struct encap_vxlan_ipv4_data);
+		else
+			if (encap->vxlan.vlan)
+				return sizeof(struct encap_vxlan_ipv6_vlan_data);
+			else
+				return sizeof(struct encap_vxlan_ipv6_data);
+
 	default:
 		return 0;
 	}
@@ -550,6 +595,9 @@  encap_apply_check(struct rte_table_action_encap_params *p,
 	case RTE_TABLE_ACTION_ENCAP_PPPOE:
 		return 0;
 
+	case RTE_TABLE_ACTION_ENCAP_VXLAN:
+		return 0;
+
 	default:
 		return -EINVAL;
 	}
@@ -679,6 +727,168 @@  encap_pppoe_apply(void *data,
 }
 
 static int
+encap_vxlan_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg)
+{
+	if ((p->vxlan.vxlan.vni > 0xFFFFFF) ||
+		(cfg->vxlan.ip_version && (p->vxlan.ipv4.dscp > 0x3F)) ||
+		(!cfg->vxlan.ip_version && (p->vxlan.ipv6.flow_label > 0xFFFFF)) ||
+		(!cfg->vxlan.ip_version && (p->vxlan.ipv6.dscp > 0x3F)) ||
+		(cfg->vxlan.vlan && (p->vxlan.vlan.vid > 0xFFF)))
+		return -1;
+
+	if (cfg->vxlan.ip_version)
+		if (cfg->vxlan.vlan) {
+			struct encap_vxlan_ipv4_vlan_data *d = data;
+
+			/* Ethernet */
+			ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
+			ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
+			d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
+
+			/* VLAN */
+			d->vlan.vlan_tci = rte_htons(VLAN(p->vxlan.vlan.pcp,
+				p->vxlan.vlan.dei,
+				p->vxlan.vlan.vid));
+			d->vlan.eth_proto = rte_htons(ETHER_TYPE_IPv4);
+
+			/* IPv4*/
+			d->ipv4.version_ihl = 0x45;
+			d->ipv4.type_of_service = p->vxlan.ipv4.dscp << 2;
+			d->ipv4.total_length = 0; /* not pre-computed */
+			d->ipv4.packet_id = 0;
+			d->ipv4.fragment_offset = 0;
+			d->ipv4.time_to_live = p->vxlan.ipv4.ttl;
+			d->ipv4.next_proto_id = IP_PROTO_UDP;
+			d->ipv4.hdr_checksum = 0;
+			d->ipv4.src_addr = rte_htonl(p->vxlan.ipv4.sa);
+			d->ipv4.dst_addr = rte_htonl(p->vxlan.ipv4.da);
+
+			d->ipv4.hdr_checksum = rte_ipv4_cksum(&d->ipv4);
+
+			/* UDP */
+			d->udp.src_port = rte_htons(p->vxlan.udp.sp);
+			d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
+			d->udp.dgram_len = 0; /* not pre-computed */
+			d->udp.dgram_cksum = 0;
+
+			/* VXLAN */
+			d->vxlan.vx_flags = rte_htonl(0x08000000);
+			d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
+
+			return 0;
+		} else {
+			struct encap_vxlan_ipv4_data *d = data;
+
+			/* Ethernet */
+			ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
+			ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
+			d->ether.ether_type = rte_htons(ETHER_TYPE_IPv4);
+
+			/* IPv4*/
+			d->ipv4.version_ihl = 0x45;
+			d->ipv4.type_of_service = p->vxlan.ipv4.dscp << 2;
+			d->ipv4.total_length = 0; /* not pre-computed */
+			d->ipv4.packet_id = 0;
+			d->ipv4.fragment_offset = 0;
+			d->ipv4.time_to_live = p->vxlan.ipv4.ttl;
+			d->ipv4.next_proto_id = IP_PROTO_UDP;
+			d->ipv4.hdr_checksum = 0;
+			d->ipv4.src_addr = rte_htonl(p->vxlan.ipv4.sa);
+			d->ipv4.dst_addr = rte_htonl(p->vxlan.ipv4.da);
+
+			d->ipv4.hdr_checksum = rte_ipv4_cksum(&d->ipv4);
+
+			/* UDP */
+			d->udp.src_port = rte_htons(p->vxlan.udp.sp);
+			d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
+			d->udp.dgram_len = 0; /* not pre-computed */
+			d->udp.dgram_cksum = 0;
+
+			/* VXLAN */
+			d->vxlan.vx_flags = rte_htonl(0x08000000);
+			d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
+
+			return 0;
+		}
+	else
+		if (cfg->vxlan.vlan) {
+			struct encap_vxlan_ipv6_vlan_data *d = data;
+
+			/* Ethernet */
+			ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
+			ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
+			d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
+
+			/* VLAN */
+			d->vlan.vlan_tci = rte_htons(VLAN(p->vxlan.vlan.pcp,
+				p->vxlan.vlan.dei,
+				p->vxlan.vlan.vid));
+			d->vlan.eth_proto = rte_htons(ETHER_TYPE_IPv6);
+
+			/* IPv6*/
+			d->ipv6.vtc_flow = rte_htonl((6 << 28) |
+				(p->vxlan.ipv6.dscp << 22) |
+				p->vxlan.ipv6.flow_label);
+			d->ipv6.payload_len = 0; /* not pre-computed */
+			d->ipv6.proto = IP_PROTO_UDP;
+			d->ipv6.hop_limits = p->vxlan.ipv6.hop_limit;
+			memcpy(d->ipv6.src_addr,
+				p->vxlan.ipv6.sa,
+				sizeof(p->vxlan.ipv6.sa));
+			memcpy(d->ipv6.dst_addr,
+				p->vxlan.ipv6.da,
+				sizeof(p->vxlan.ipv6.da));
+
+			/* UDP */
+			d->udp.src_port = rte_htons(p->vxlan.udp.sp);
+			d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
+			d->udp.dgram_len = 0; /* not pre-computed */
+			d->udp.dgram_cksum = 0;
+
+			/* VXLAN */
+			d->vxlan.vx_flags = rte_htonl(0x08000000);
+			d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
+
+			return 0;
+		} else {
+			struct encap_vxlan_ipv6_data *d = data;
+
+			/* Ethernet */
+			ether_addr_copy(&p->vxlan.ether.da, &d->ether.d_addr);
+			ether_addr_copy(&p->vxlan.ether.sa, &d->ether.s_addr);
+			d->ether.ether_type = rte_htons(ETHER_TYPE_IPv6);
+
+			/* IPv6*/
+			d->ipv6.vtc_flow = rte_htonl((6 << 28) |
+				(p->vxlan.ipv6.dscp << 22) |
+				p->vxlan.ipv6.flow_label);
+			d->ipv6.payload_len = 0; /* not pre-computed */
+			d->ipv6.proto = IP_PROTO_UDP;
+			d->ipv6.hop_limits = p->vxlan.ipv6.hop_limit;
+			memcpy(d->ipv6.src_addr,
+				p->vxlan.ipv6.sa,
+				sizeof(p->vxlan.ipv6.sa));
+			memcpy(d->ipv6.dst_addr,
+				p->vxlan.ipv6.da,
+				sizeof(p->vxlan.ipv6.da));
+
+			/* UDP */
+			d->udp.src_port = rte_htons(p->vxlan.udp.sp);
+			d->udp.dst_port = rte_htons(p->vxlan.udp.dp);
+			d->udp.dgram_len = 0; /* not pre-computed */
+			d->udp.dgram_cksum = 0;
+
+			/* VXLAN */
+			d->vxlan.vx_flags = rte_htonl(0x08000000);
+			d->vxlan.vx_vni = rte_htonl(p->vxlan.vxlan.vni << 8);
+
+			return 0;
+		}
+}
+
+static int
 encap_apply(void *data,
 	struct rte_table_action_encap_params *p,
 	struct rte_table_action_encap_config *cfg,
@@ -707,11 +917,31 @@  encap_apply(void *data,
 	case RTE_TABLE_ACTION_ENCAP_PPPOE:
 		return encap_pppoe_apply(data, p);
 
+	case RTE_TABLE_ACTION_ENCAP_VXLAN:
+		return encap_vxlan_apply(data, p, cfg);
+
 	default:
 		return -EINVAL;
 	}
 }
 
+static __rte_always_inline uint16_t
+encap_vxlan_ipv4_checksum_update(uint16_t cksum0,
+	uint16_t total_length)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Add total length (one's complement logic) */
+	cksum1 += total_length;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
 static __rte_always_inline void *
 encap(void *dst, const void *src, size_t n)
 {
@@ -720,6 +950,118 @@  encap(void *dst, const void *src, size_t n)
 }
 
 static __rte_always_inline void
+pkt_work_encap_vxlan_ipv4(struct rte_mbuf *mbuf,
+	struct encap_vxlan_ipv4_data *vxlan_tbl,
+	struct rte_table_action_encap_config *cfg)
+{
+	uint32_t ether_offset = cfg->vxlan.data_offset;
+	void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
+	struct encap_vxlan_ipv4_data *vxlan_pkt;
+	uint16_t ether_length, ipv4_total_length, ipv4_hdr_cksum, udp_length;
+
+	ether_length = (uint16_t)mbuf->pkt_len;
+	ipv4_total_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr) +
+		sizeof(struct ipv4_hdr));
+	ipv4_hdr_cksum = encap_vxlan_ipv4_checksum_update(vxlan_tbl->ipv4.hdr_checksum,
+		rte_htons(ipv4_total_length));
+	udp_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr));
+
+	vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
+	vxlan_pkt->ipv4.total_length = rte_htons(ipv4_total_length);
+	vxlan_pkt->ipv4.hdr_checksum = ipv4_hdr_cksum;
+	vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
+
+	mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
+	mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
+}
+
+static __rte_always_inline void
+pkt_work_encap_vxlan_ipv4_vlan(struct rte_mbuf *mbuf,
+	struct encap_vxlan_ipv4_vlan_data *vxlan_tbl,
+	struct rte_table_action_encap_config *cfg)
+{
+	uint32_t ether_offset = cfg->vxlan.data_offset;
+	void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
+	struct encap_vxlan_ipv4_vlan_data *vxlan_pkt;
+	uint16_t ether_length, ipv4_total_length, ipv4_hdr_cksum, udp_length;
+
+	ether_length = (uint16_t)mbuf->pkt_len;
+	ipv4_total_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr) +
+		sizeof(struct ipv4_hdr));
+	ipv4_hdr_cksum = encap_vxlan_ipv4_checksum_update(vxlan_tbl->ipv4.hdr_checksum,
+		rte_htons(ipv4_total_length));
+	udp_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr));
+
+	vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
+	vxlan_pkt->ipv4.total_length = rte_htons(ipv4_total_length);
+	vxlan_pkt->ipv4.hdr_checksum = ipv4_hdr_cksum;
+	vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
+
+	mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
+	mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
+}
+
+static __rte_always_inline void
+pkt_work_encap_vxlan_ipv6(struct rte_mbuf *mbuf,
+	struct encap_vxlan_ipv6_data *vxlan_tbl,
+	struct rte_table_action_encap_config *cfg)
+{
+	uint32_t ether_offset = cfg->vxlan.data_offset;
+	void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
+	struct encap_vxlan_ipv6_data *vxlan_pkt;
+	uint16_t ether_length, ipv6_payload_length, udp_length;
+
+	ether_length = (uint16_t)mbuf->pkt_len;
+	ipv6_payload_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr));
+	udp_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr));
+
+	vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
+	vxlan_pkt->ipv6.payload_len = rte_htons(ipv6_payload_length);
+	vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
+
+	mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
+	mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
+}
+
+static __rte_always_inline void
+pkt_work_encap_vxlan_ipv6_vlan(struct rte_mbuf *mbuf,
+	struct encap_vxlan_ipv6_vlan_data *vxlan_tbl,
+	struct rte_table_action_encap_config *cfg)
+{
+	uint32_t ether_offset = cfg->vxlan.data_offset;
+	void *ether = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ether_offset);
+	struct encap_vxlan_ipv6_vlan_data *vxlan_pkt;
+	uint16_t ether_length, ipv6_payload_length, udp_length;
+
+	ether_length = (uint16_t)mbuf->pkt_len;
+	ipv6_payload_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr));
+	udp_length = ether_length +
+		(sizeof(struct vxlan_hdr) +
+		sizeof(struct udp_hdr));
+
+	vxlan_pkt = encap(ether, vxlan_tbl, sizeof(*vxlan_tbl));
+	vxlan_pkt->ipv6.payload_len = rte_htons(ipv6_payload_length);
+	vxlan_pkt->udp.dgram_len = rte_htons(udp_length);
+
+	mbuf->data_off = ether_offset - (sizeof(struct rte_mbuf) + sizeof(*vxlan_pkt));
+	mbuf->pkt_len = mbuf->data_len = ether_length + sizeof(*vxlan_pkt);
+}
+
+static __rte_always_inline void
 pkt_work_encap(struct rte_mbuf *mbuf,
 	void *data,
 	struct rte_table_action_encap_config *cfg,
@@ -776,6 +1118,20 @@  pkt_work_encap(struct rte_mbuf *mbuf,
 		break;
 	}
 
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN:
+	{
+		if (cfg->vxlan.ip_version)
+			if (cfg->vxlan.vlan)
+				pkt_work_encap_vxlan_ipv4_vlan(mbuf, data, cfg);
+			else
+				pkt_work_encap_vxlan_ipv4(mbuf, data, cfg);
+		else
+			if (cfg->vxlan.vlan)
+				pkt_work_encap_vxlan_ipv6_vlan(mbuf, data, cfg);
+			else
+				pkt_work_encap_vxlan_ipv6(mbuf, data, cfg);
+	}
+
 	default:
 		break;
 	}
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c7f751a..73b564c 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -366,6 +366,11 @@  enum rte_table_action_encap_type {
 
 	/** IP -> { Ether | PPPoE | PPP | IP } */
 	RTE_TABLE_ACTION_ENCAP_PPPOE,
+
+	/** Ether -> { Ether | IP | UDP | VXLAN | Ether }
+	 * Ether -> { Ether | VLAN | IP | UDP | VXLAN | Ether }
+	 */
+	RTE_TABLE_ACTION_ENCAP_VXLAN,
 };
 
 /** Pre-computed Ethernet header fields for encapsulation action. */
@@ -393,6 +398,34 @@  struct rte_table_action_pppoe_hdr {
 	uint16_t session_id; /**< Session ID. */
 };
 
+/** Pre-computed IPv4 header fields for encapsulation action. */
+struct rte_table_action_ipv4_header {
+	uint32_t sa; /**< Source address. */
+	uint32_t da; /**< Destination address. */
+	uint8_t dscp; /**< DiffServ Code Point (DSCP). */
+	uint8_t ttl; /**< Time To Live (TTL). */
+};
+
+/** Pre-computed IPv6 header fields for encapsulation action. */
+struct rte_table_action_ipv6_header {
+	uint8_t sa[16]; /**< Source address. */
+	uint8_t da[16]; /**< Destination address. */
+	uint32_t flow_label; /**< Flow label. */
+	uint8_t dscp; /**< DiffServ Code Point (DSCP). */
+	uint8_t hop_limit; /**< Hop Limit (HL). */
+};
+
+/** Pre-computed UDP header fields for encapsulation action. */
+struct rte_table_action_udp_header {
+	uint16_t sp; /**< Source port. */
+	uint16_t dp; /**< Destination port. */
+};
+
+/** Pre-computed VXLAN header fields for encapsulation action. */
+struct rte_table_action_vxlan_hdr {
+	uint32_t vni; /**< VXLAN Network Identifier (VNI). */
+};
+
 /** Ether encap parameters. */
 struct rte_table_action_encap_ether_params {
 	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
@@ -437,6 +470,21 @@  struct rte_table_action_encap_pppoe_params {
 	struct rte_table_action_pppoe_hdr pppoe; /**< PPPoE/PPP headers. */
 };
 
+/** VXLAN encap parameters. */
+struct rte_table_action_encap_vxlan_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr vlan; /**< VLAN header. */
+
+	RTE_STD_C11
+	union {
+		struct rte_table_action_ipv4_header ipv4; /**< IPv4 header. */
+		struct rte_table_action_ipv6_header ipv6; /**< IPv6 header. */
+	};
+
+	struct rte_table_action_udp_header udp; /**< UDP header. */
+	struct rte_table_action_vxlan_hdr vxlan; /**< VXLAN header. */
+};
+
 /** Encap action configuration (per table action profile). */
 struct rte_table_action_encap_config {
 	/** Bit mask defining the set of packet encapsulations enabled for the
@@ -446,6 +494,30 @@  struct rte_table_action_encap_config {
 	 * @see enum rte_table_action_encap_type
 	 */
 	uint64_t encap_mask;
+
+	/** Encapsulation type specific configuration. */
+	RTE_STD_C11
+	union {
+		struct {
+			/** Input packet to be encapsulated: offset within the
+			 * input packet buffer to the start of the Ethernet
+			 * frame to be encapsulated. Offset 0 points to the
+			 * first byte of the MBUF structure.
+			 */
+			uint32_t data_offset;
+
+			/** Encapsulation header: non-zero when encapsulation
+			 * header includes a VLAN tag, zero otherwise.
+			 */
+			int vlan;
+
+			/** Encapsulation header: IP version of the IP header
+			 * within the encapsulation header. Non-zero for IPv4,
+			 * zero for IPv6.
+			 */
+			int ip_version;
+		} vxlan; /**< VXLAN specific configuration. */
+	};
 };
 
 /** Encap action parameters (per table rule). */
@@ -469,6 +541,9 @@  struct rte_table_action_encap_params {
 
 		/** Only valid when *type* is set to PPPoE. */
 		struct rte_table_action_encap_pppoe_params pppoe;
+
+		/** Only valid when *type* is set to VXLAN. */
+		struct rte_table_action_encap_vxlan_params vxlan;
 	};
 };