[dpdk-dev] [PATCH v2 08/16] net: support Ip tunnels in software packet type parser

Olivier Matz olivier.matz at 6wind.com
Mon Aug 29 16:35:27 CEST 2016


Add support of IP and IP6 tunnels in rte_net_get_ptype().

We need to duplicate some code because the packet types do not have the
same value for a given protocol between inner and outer.

Signed-off-by: Jean Dao <jean.dao at 6wind.com>
Signed-off-by: Olivier Matz <olivier.matz at 6wind.com>
---
 lib/librte_net/rte_net.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++-
 lib/librte_net/rte_net.h |   1 +
 2 files changed, 156 insertions(+), 3 deletions(-)

diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index d20cc65..d921db8 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -93,6 +93,79 @@ ptype_l4(uint8_t proto)
 	return ptype_l4_proto[proto];
 }
 
+/* get inner l3 packet type from ip6 next protocol */
+static uint32_t
+ptype_inner_l3_ip6(uint8_t ip6_proto)
+{
+	static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
+		[IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+	};
+
+	return RTE_PTYPE_INNER_L3_IPV6 +
+		ptype_inner_ip6_ext_proto_map[ip6_proto];
+}
+
+/* get inner l3 packet type from ip version and header length */
+static uint32_t
+ptype_inner_l3_ip(uint8_t ipv_ihl)
+{
+	static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
+		[0x45] = RTE_PTYPE_INNER_L3_IPV4,
+		[0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+	};
+
+	return ptype_inner_l3_ip_proto_map[ipv_ihl];
+}
+
+/* get inner l4 packet type from proto */
+static uint32_t
+ptype_inner_l4(uint8_t proto)
+{
+	static const uint32_t ptype_inner_l4_proto[256] = {
+		[IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
+		[IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
+		[IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
+	};
+
+	return ptype_inner_l4_proto[proto];
+}
+
+/* get the tunnel packet type if any, update proto. */
+static uint32_t
+ptype_tunnel(uint16_t *proto)
+{
+	switch (*proto) {
+	case IPPROTO_IPIP:
+		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		return RTE_PTYPE_TUNNEL_IP;
+	case IPPROTO_IPV6:
+		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
+	default:
+		return 0;
+	}
+}
+
 /* get the ipv4 header length */
 static uint8_t
 ip4_hlen(const struct ipv4_hdr *hdr)
@@ -207,9 +280,8 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		pkt_type |= ptype_l3_ip(ip4h->version_ihl);
 		hdr_lens->l3_len = ip4_hlen(ip4h);
 		off += hdr_lens->l3_len;
-		if (ip4h->fragment_offset &
-				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
-					IPV4_HDR_MF_FLAG)) {
+		if (ip4h->fragment_offset & rte_cpu_to_be_16(
+				IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
 			pkt_type |= RTE_PTYPE_L4_FRAG;
 			hdr_lens->l4_len = 0;
 			return pkt_type;
@@ -245,6 +317,7 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 
 	if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
 		hdr_lens->l4_len = sizeof(struct udp_hdr);
+		return pkt_type;
 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
 		const struct tcp_hdr *th;
 		struct tcp_hdr th_copy;
@@ -254,10 +327,89 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 			return pkt_type & (RTE_PTYPE_L2_MASK |
 				RTE_PTYPE_L3_MASK);
 		hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
+		return pkt_type;
 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
 		hdr_lens->l4_len = sizeof(struct sctp_hdr);
+		return pkt_type;
 	} else {
 		hdr_lens->l4_len = 0;
+		pkt_type |= ptype_tunnel(&proto);
+		hdr_lens->tunnel_len = 0;
+	}
+
+	/* same job for inner header: we need to duplicate the code
+	 * because the packet types do not have the same value.
+	 */
+	hdr_lens->inner_l2_len = 0;
+
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		const struct ipv4_hdr *ip4h;
+		struct ipv4_hdr ip4h_copy;
+
+		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
+		if (unlikely(ip4h == NULL))
+			return pkt_type;
+
+		pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
+		hdr_lens->inner_l3_len = ip4_hlen(ip4h);
+		off += hdr_lens->inner_l3_len;
+		if (ip4h->fragment_offset &
+				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
+					IPV4_HDR_MF_FLAG)) {
+			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
+			hdr_lens->inner_l4_len = 0;
+			return pkt_type;
+		}
+		proto = ip4h->next_proto_id;
+		pkt_type |= ptype_inner_l4(proto);
+	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		const struct ipv6_hdr *ip6h;
+		struct ipv6_hdr ip6h_copy;
+		int frag = 0;
+
+		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
+		if (unlikely(ip6h == NULL))
+			return pkt_type;
+
+		proto = ip6h->proto;
+		hdr_lens->inner_l3_len = sizeof(*ip6h);
+		off += hdr_lens->inner_l3_len;
+		pkt_type |= ptype_inner_l3_ip6(proto);
+		if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
+				RTE_PTYPE_INNER_L3_IPV6_EXT) {
+			uint32_t prev_off;
+
+			prev_off = off;
+			proto = skip_ip6_ext(proto, m, &off, &frag);
+			hdr_lens->inner_l3_len += off - prev_off;
+		}
+		if (proto == 0)
+			return pkt_type;
+		if (frag) {
+			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
+			hdr_lens->inner_l4_len = 0;
+			return pkt_type;
+		}
+		pkt_type |= ptype_inner_l4(proto);
+	}
+
+	if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
+		hdr_lens->inner_l4_len = sizeof(struct udp_hdr);
+	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
+			RTE_PTYPE_INNER_L4_TCP) {
+		const struct tcp_hdr *th;
+		struct tcp_hdr th_copy;
+
+		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
+		if (unlikely(th == NULL))
+			return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
+				RTE_PTYPE_INNER_L3_MASK);
+		hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
+	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
+			RTE_PTYPE_INNER_L4_SCTP) {
+		hdr_lens->inner_l4_len = sizeof(struct sctp_hdr);
+	} else {
+		hdr_lens->inner_l4_len = 0;
 	}
 
 	return pkt_type;
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
index 1224b0e..f433389 100644
--- a/lib/librte_net/rte_net.h
+++ b/lib/librte_net/rte_net.h
@@ -68,6 +68,7 @@ struct rte_net_hdr_lens {
  *   L2: Ether, Vlan, QinQ
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
+ *   Tunnels: IPv4, IPv6
  *
  * @param m
  *   The packet mbuf to be parsed.
-- 
2.8.1



More information about the dev mailing list