+/*-
+ * BSD LICENSE
+ *
+ * Copyright 2016 6WIND S.A.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 6WIND S.A. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#include <rte_mbuf.h>
+#include <rte_mbuf_ptype.h>
+#include <rte_byteorder.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_sctp.h>
+#include <rte_net.h>
+
+/* get l3 packet type from ip6 next protocol */
+static uint32_t
+ptype_l3_ip6(uint8_t ip6_proto)
+{
+ static const uint32_t ip6_ext_proto_map[256] = {
+ [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+ [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+ [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+ [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+ [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+ [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+ };
+
+ return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
+}
+
+/* get l3 packet type from ip version and header length */
+static uint32_t
+ptype_l3_ip(uint8_t ipv_ihl)
+{
+ static const uint32_t ptype_l3_ip_proto_map[256] = {
+ [0x45] = RTE_PTYPE_L3_IPV4,
+ [0x46] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x47] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x48] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x49] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x4A] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x4B] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x4C] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x4D] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x4E] = RTE_PTYPE_L3_IPV4_EXT,
+ [0x4F] = RTE_PTYPE_L3_IPV4_EXT,
+ };
+
+ return ptype_l3_ip_proto_map[ipv_ihl];
+}
+
+/* get l4 packet type from proto */
+static uint32_t
+ptype_l4(uint8_t proto)
+{
+ static const uint32_t ptype_l4_proto[256] = {
+ [IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
+ [IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
+ [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
+ };
+
+ return ptype_l4_proto[proto];
+}
+
+/* get the ipv4 header length */
+static uint8_t
+ip4_hlen(const struct ipv4_hdr *hdr)
+{
+ return (hdr->version_ihl & 0xf) * 4;
+}
+
+/* parse ipv6 extended headers, update offset and return next proto */
+static uint16_t
+skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
+ int *frag)
+{
+ struct ext_hdr {
+ uint8_t next_hdr;
+ uint8_t len;
+ };
+ const struct ext_hdr *xh;
+ struct ext_hdr xh_copy;
+ unsigned int i;
+
+ *frag = 0;
+
+#define MAX_EXT_HDRS 5
+ for (i = 0; i < MAX_EXT_HDRS; i++) {
+ switch (proto) {
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_DSTOPTS:
+ xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
+ &xh_copy);
+ if (xh == NULL)
+ return 0;
+ *off += (xh->len + 1) * 8;
+ proto = xh->next_hdr;
+ break;
+ case IPPROTO_FRAGMENT:
+ xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
+ &xh_copy);
+ if (xh == NULL)
+ return 0;
+ *off += 8;
+ proto = xh->next_hdr;
+ *frag = 1;
+ return proto; /* this is always the last ext hdr */
+ case IPPROTO_NONE:
+ return 0;
+ default:
+ return proto;
+ }
+ }
+ return 0;
+}
+
+/* parse mbuf data to get packet type */
+uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
+ struct rte_net_hdr_lens *hdr_lens)
+{
+ struct rte_net_hdr_lens local_hdr_lens;
+ const struct ether_hdr *eh;
+ struct ether_hdr eh_copy;
+ uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
+ uint32_t off = 0;
+ uint16_t proto;
+
+ if (hdr_lens == NULL)
+ hdr_lens = &local_hdr_lens;
+
+ eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
+ if (unlikely(eh == NULL))
+ return 0;
+ proto = eh->ether_type;
+ off = sizeof(*eh);
+ hdr_lens->l2_len = off;
+
+ 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_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)) {
+ pkt_type |= RTE_PTYPE_L4_FRAG;
+ hdr_lens->l4_len = 0;
+ return pkt_type;
+ }
+ proto = ip4h->next_proto_id;
+ pkt_type |= ptype_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->l3_len = sizeof(*ip6h);
+ off += hdr_lens->l3_len;
+ pkt_type |= ptype_l3_ip6(proto);
+ if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
+ proto = skip_ip6_ext(proto, m, &off, &frag);
+ hdr_lens->l3_len = off - hdr_lens->l2_len;
+ }
+ if (proto == 0)
+ return pkt_type;
+ if (frag) {
+ pkt_type |= RTE_PTYPE_L4_FRAG;
+ hdr_lens->l4_len = 0;
+ return pkt_type;
+ }
+ pkt_type |= ptype_l4(proto);
+ }
+
+ if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
+ hdr_lens->l4_len = sizeof(struct udp_hdr);
+ } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_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_L2_MASK |
+ RTE_PTYPE_L3_MASK);
+ hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
+ } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
+ hdr_lens->l4_len = sizeof(struct sctp_hdr);
+ } else {
+ hdr_lens->l4_len = 0;
+ }
+
+ return pkt_type;
+}
--- /dev/null
+/*-
+ * BSD LICENSE
+ *
+ * Copyright 2016 6WIND S.A.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_NET_PTYPE_H_
+#define _RTE_NET_PTYPE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Structure containing header lengths associated to a packet, filled
+ * by rte_net_get_ptype().
+ */
+struct rte_net_hdr_lens {
+ uint8_t l2_len;
+ uint8_t l3_len;
+ uint8_t l4_len;
+ uint8_t tunnel_len;
+ uint8_t inner_l2_len;
+ uint8_t inner_l3_len;
+ uint8_t inner_l4_len;
+};
+
+/**
+ * Parse an Ethernet packet to get its packet type.
+ *
+ * This function parses the network headers in mbuf data and return its
+ * packet type.
+ *
+ * If it is provided by the user, it also fills a rte_net_hdr_lens
+ * structure that contains the lengths of the parsed network
+ * headers. Each length field is valid only if the associated packet
+ * type is set. For instance, hdr_lens->l2_len is valid only if
+ * (retval & RTE_PTYPE_L2_MASK) != RTE_PTYPE_UNKNOWN.
+ *
+ * Supported packet types are:
+ * L2: Ether
+ * L3: IPv4, IPv6
+ * L4: TCP, UDP, SCTP
+ *
+ * @param m
+ * The packet mbuf to be parsed.
+ * @param hdr_lens
+ * A pointer to a structure where the header lengths will be returned,
+ * or NULL.
+ * @return
+ * The packet type of the packet.
+ */
+uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
+ struct rte_net_hdr_lens *hdr_lens);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _RTE_NET_PTYPE_H_ */