DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 1/2] pipeline: add vxlan encap
@ 2018-09-07 15:58 Cristian Dumitrescu
  2018-09-07 15:58 ` [dpdk-dev] [PATCH 2/2] examples/ip_pipeline: " Cristian Dumitrescu
  0 siblings, 1 reply; 3+ messages in thread
From: Cristian Dumitrescu @ 2018-09-07 15:58 UTC (permalink / raw)
  To: dev

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(+)

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;
 	};
 };
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dpdk-dev] [PATCH 2/2] examples/ip_pipeline: add vxlan encap
  2018-09-07 15:58 [dpdk-dev] [PATCH 1/2] pipeline: add vxlan encap Cristian Dumitrescu
@ 2018-09-07 15:58 ` Cristian Dumitrescu
  2018-09-28 10:33   ` Dumitrescu, Cristian
  0 siblings, 1 reply; 3+ messages in thread
From: Cristian Dumitrescu @ 2018-09-07 15:58 UTC (permalink / raw)
  To: dev

Add CLI support for VXLAN encap.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/cli.c | 181 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 177 insertions(+), 4 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 102a1d6..01c3769 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -961,7 +961,8 @@ static const char cmd_table_action_profile_help[] =
 "       tc <n_tc>\n"
 "       stats none | pkts | bytes | both]\n"
 "   [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]\n"
-"   [encap ether | vlan | qinq | mpls | pppoe]\n"
+"   [encap ether | vlan | qinq | mpls | pppoe |\n"
+"       vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off]\n"
 "   [nat src | dst\n"
 "       proto udp | tcp]\n"
 "   [ttl drop | fwd\n"
@@ -1157,6 +1158,8 @@ cmd_table_action_profile(char **tokens,
 	} /* tm */
 
 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
+		uint32_t n_extra_tokens = 0;
+
 		if (n_tokens < t0 + 2) {
 			snprintf(out, out_size, MSG_ARG_MISMATCH,
 				"action profile encap");
@@ -1173,13 +1176,61 @@ cmd_table_action_profile(char **tokens,
 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
 		else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
-		else {
+		else if (strcmp(tokens[t0 + 1], "vxlan") == 0) {
+			if (n_tokens < t0 + 2 + 5) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					"action profile encap vxlan");
+				return;
+			}
+
+			if (strcmp(tokens[t0 + 2], "offset") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+					"vxlan: offset");
+				return;
+			}
+
+			if (parser_read_uint32(&p.encap.vxlan.data_offset,
+				tokens[t0 + 2 + 1]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"vxlan: ether_offset");
+				return;
+			}
+
+			if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0)
+				p.encap.vxlan.ip_version = 1;
+			else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0)
+				p.encap.vxlan.ip_version = 0;
+			else {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"vxlan: ipv4 or ipv6");
+				return;
+			}
+
+			if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+					"vxlan: vlan");
+				return;
+			}
+
+			if (strcmp(tokens[t0 + 2 + 4], "on") == 0)
+				p.encap.vxlan.vlan = 1;
+			else if (strcmp(tokens[t0 + 2 + 4], "off") == 0)
+				p.encap.vxlan.vlan = 0;
+			else {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"vxlan: on or off");
+				return;
+			}
+
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN;
+			n_extra_tokens = 5;
+		} else {
 			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
 			return;
 		}
 
 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
-		t0 += 2;
+		t0 += 2 + n_extra_tokens;
 	} /* encap */
 
 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
@@ -2861,7 +2912,13 @@ parse_match(char **tokens,
  *          [label1 <label> <tc> <ttl>
  *          [label2 <label> <tc> <ttl>
  *          [label3 <label> <tc> <ttl>]]]
- *       | pppoe <da> <sa> <session_id>]
+ *       | pppoe <da> <sa> <session_id>
+ *       | vxlan ether <da> <sa>
+ *          [vlan <pcp> <dei> <vid>]
+ *          ipv4 <sa> <da> <dscp> <ttl>
+ *          | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit>
+ *          udp <sp> <dp>
+ *          vxlan <vni>]
  *    [nat ipv4 | ipv6 <addr> <port>]
  *    [ttl dec | keep]
  *    [stats]
@@ -3254,6 +3311,122 @@ parse_table_action_encap(char **tokens,
 		return 1 + 4;
 	}
 
+	/* vxlan */
+	if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) {
+		uint32_t n = 0;
+
+		n_tokens--;
+		tokens++;
+		n++;
+
+		/* ether <da> <sa> */
+		if ((n_tokens < 3) ||
+			strcmp(tokens[0], "ether") ||
+			parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa))
+			return 0;
+
+		n_tokens -= 3;
+		tokens += 3;
+		n += 3;
+
+		/* [vlan <pcp> <dei> <vid>] */
+		if (strcmp(tokens[0], "vlan") == 0) {
+			uint32_t pcp, dei, vid;
+
+			if ((n_tokens < 4) ||
+				parser_read_uint32(&pcp, tokens[1]) ||
+				(pcp > 7) ||
+				parser_read_uint32(&dei, tokens[2]) ||
+				(dei > 1) ||
+				parser_read_uint32(&vid, tokens[3]) ||
+				(vid > 0xFFF))
+				return 0;
+
+			a->encap.vxlan.vlan.pcp = pcp;
+			a->encap.vxlan.vlan.dei = dei;
+			a->encap.vxlan.vlan.vid = vid;
+
+			n_tokens -= 4;
+			tokens += 4;
+			n += 4;
+		}
+
+		/* ipv4 <sa> <da> <dscp> <ttl>
+		   | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */
+		if (strcmp(tokens[0], "ipv4") == 0) {
+			struct in_addr sa, da;
+			uint8_t dscp, ttl;
+
+			if ((n_tokens < 5) ||
+				parse_ipv4_addr(tokens[1], &sa) ||
+				parse_ipv4_addr(tokens[2], &da) ||
+				parser_read_uint8(&dscp, tokens[3]) ||
+				(dscp > 64) ||
+				parser_read_uint8(&ttl, tokens[4]))
+				return 0;
+
+			a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr);
+			a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr);
+			a->encap.vxlan.ipv4.dscp = dscp;
+			a->encap.vxlan.ipv4.ttl = ttl;
+
+			n_tokens -= 5;
+			tokens += 5;
+			n += 5;
+		} else if (strcmp(tokens[0], "ipv6") == 0) {
+			struct in6_addr sa, da;
+			uint32_t flow_label;
+			uint8_t dscp, hop_limit;
+
+			if ((n_tokens < 6) ||
+				parse_ipv6_addr(tokens[1], &sa) ||
+				parse_ipv6_addr(tokens[2], &da) ||
+				parser_read_uint32(&flow_label, tokens[3]) ||
+				parser_read_uint8(&dscp, tokens[4]) ||
+				(dscp > 64) ||
+				parser_read_uint8(&hop_limit, tokens[5]))
+				return 0;
+
+			memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
+			memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
+			a->encap.vxlan.ipv6.flow_label = flow_label;
+			a->encap.vxlan.ipv6.dscp = dscp;
+			a->encap.vxlan.ipv6.hop_limit = hop_limit;
+
+			n_tokens -= 6;
+			tokens += 6;
+			n += 6;
+		} else
+			return 0;
+
+		/* udp <sp> <dp> */
+		if ((n_tokens < 3) ||
+			strcmp(tokens[0], "udp") ||
+			parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) ||
+			parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2]))
+			return 0;
+
+		n_tokens -= 3;
+		tokens += 3;
+		n += 3;
+
+		/* vxlan <vni> */
+		if ((n_tokens < 2) ||
+			strcmp(tokens[0], "vxlan") ||
+			parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) ||
+			(a->encap.vxlan.vxlan.vni > 0xFFFFFF))
+			return 0;
+
+		n_tokens -= 2;
+		tokens += 2;
+		n += 2;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + n;
+	}
+
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] examples/ip_pipeline: add vxlan encap
  2018-09-07 15:58 ` [dpdk-dev] [PATCH 2/2] examples/ip_pipeline: " Cristian Dumitrescu
@ 2018-09-28 10:33   ` Dumitrescu, Cristian
  0 siblings, 0 replies; 3+ messages in thread
From: Dumitrescu, Cristian @ 2018-09-28 10:33 UTC (permalink / raw)
  To: Dumitrescu, Cristian, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Cristian Dumitrescu
> Sent: Friday, September 7, 2018 4:59 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 2/2] examples/ip_pipeline: add vxlan encap
> 
> Add CLI support for VXLAN encap.
> 
> Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> ---
>  examples/ip_pipeline/cli.c | 181
> ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 177 insertions(+), 4 deletions(-)
> 

Applied on next-pipeline tree.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-09-28 10:34 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-07 15:58 [dpdk-dev] [PATCH 1/2] pipeline: add vxlan encap Cristian Dumitrescu
2018-09-07 15:58 ` [dpdk-dev] [PATCH 2/2] examples/ip_pipeline: " Cristian Dumitrescu
2018-09-28 10:33   ` Dumitrescu, Cristian

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).