Packet parsing and type detection fail for packets containing
Arista Vendor Specific Protocol (AVSP) headers. This patch adds
support for three L2 headers: Arista TGen, Arista 64-bit Timestamp
and Arista 48-bit Timestamp.

Signed-off-by: Denis Davidoglu <denis.davidoglu@b-ulltech.com>
---
 lib/net/rte_ether.h | 31 ++++++++++++++
 lib/net/rte_net.c   | 99 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/lib/net/rte_ether.h b/lib/net/rte_ether.h
index c9a0b536c3..054a54af40 100644
--- a/lib/net/rte_ether.h
+++ b/lib/net/rte_ether.h
@@ -62,6 +62,13 @@ extern "C" {
                               ((pri) << RTE_VLAN_PRI_SHIFT) |    \
                               ((dei) << RTE_VLAN_DEI_SHIFT))
 
+/* Arista Vendor Specific Protocol (AVSP) Header Types */
+#define RTE_AVSP_SUBTYPE_TGEN            0xCAFE
+#define RTE_AVSP_VERSION_TGEN            0x0001
+#define RTE_AVSP_SUBTYPE_TIMESTAMP 0x0001
+#define RTE_AVSP_VERSION_64_MASK   0x0010
+#define RTE_AVSP_VERSION_48_MASK   0x0020
+
 /**
  * Ethernet address:
  * A universally administered address is uniquely assigned to a device by its
@@ -323,7 +330,30 @@ static_assert(sizeof(struct rte_vlan_hdr) == 4,
 static_assert(alignof(struct rte_vlan_hdr) == 2,
            "alignof(struct rte_vlan_hdr) == 2");
 
+/* Arista Vendor Specific Protocol (AVSP) Headers */
+struct __rte_packed_begin rte_avsp_common_hdr {
+     rte_be16_t subtype;
+     rte_be16_t version;
+} __rte_packed_end;
+
+struct __rte_packed_begin rte_avsp_tgen_hdr {
+     struct rte_avsp_common_hdr common;
+     rte_be16_t eth_proto; /**< Ethernet type of encapsulated frame. */
+} __rte_packed_end;
+
+struct __rte_packed_begin rte_avsp_timestamp_64_hdr {
+     struct rte_avsp_common_hdr common;
+     rte_be32_t sec; /**< Seconds (IEEE 1588 time of day format). */
+     rte_be32_t ns;  /**< Nanoseconds (IEEE 1588 time of day format). */
+     rte_be16_t eth_proto; /**< Ethernet type of encapsulated frame. */
+} __rte_packed_end;
 
+struct __rte_packed_begin rte_avsp_timestamp_48_hdr {
+     struct rte_avsp_common_hdr common;
+     rte_be16_t sec; /**< Seconds (IEEE 1588 time of day format). */
+     rte_be32_t ns;  /**< Nanoseconds (IEEE 1588 time of day format). */
+     rte_be16_t eth_proto; /**< Ethernet type of encapsulated frame. */
+} __rte_packed_end;
 
 /* Ethernet frame types */
 #define RTE_ETHER_TYPE_IPV4 0x0800 /**< IPv4 Protocol. */
@@ -346,6 +376,7 @@ static_assert(alignof(struct rte_vlan_hdr) == 2,
 #define RTE_ETHER_TYPE_MPLS 0x8847 /**< MPLS ethertype. */
 #define RTE_ETHER_TYPE_MPLSM 0x8848 /**< MPLS multicast ethertype. */
 #define RTE_ETHER_TYPE_ECPRI 0xAEFE /**< eCPRI ethertype (.1Q supported). */
+#define RTE_ETHER_TYPE_AVSP 0xD28B  /**< Arista ethertype */
 
 /**
  * Extract VLAN tag information into mbuf
diff --git a/lib/net/rte_net.c b/lib/net/rte_net.c
index d680accc16..d260cfdf0a 100644
--- a/lib/net/rte_net.c
+++ b/lib/net/rte_net.c
@@ -269,7 +269,56 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
            off += 2 * sizeof(*vh);
            hdr_lens->l2_len += 2 * sizeof(*vh);
            proto = vh->eth_proto;
-     } else if ((proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS)) ||
+     }
+     if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_AVSP)) {
+           union {
+                 const struct rte_avsp_common_hdr *common;
+                 const struct rte_avsp_tgen_hdr *tgen;
+                 const struct rte_avsp_timestamp_64_hdr *t64;
+                 const struct rte_avsp_timestamp_48_hdr *t48;
+           } ah;
+           union {
+                 struct rte_avsp_common_hdr common;
+                 struct rte_avsp_tgen_hdr tgen;
+                 struct rte_avsp_timestamp_64_hdr t64;
+                 struct rte_avsp_timestamp_48_hdr t48;
+           } ah_copy;
+
+           ah.common = rte_pktmbuf_read(m, off, sizeof(*ah.common),
+                                                      &ah_copy.common);
+           if (unlikely(ah.common == NULL))
+                 return pkt_type;
+           uint16_t subtype = rte_be_to_cpu_16(ah.common->subtype);
+           uint16_t version = rte_be_to_cpu_16(ah.common->version);
+
+           if (subtype == RTE_AVSP_SUBTYPE_TGEN &&
+                       (version == RTE_AVSP_VERSION_TGEN)) {
+                 ah.tgen = rte_pktmbuf_read(m, off, sizeof(*ah.tgen), &ah_copy);
+                 if (unlikely(ah.tgen == NULL))
+                       return pkt_type;
+                 off += sizeof(*ah.tgen);
+                 hdr_lens->l2_len += sizeof(*ah.tgen);
+                 proto = ah.tgen->eth_proto;
+           } else if ((subtype == RTE_AVSP_SUBTYPE_TIMESTAMP &&
+                             (version & RTE_AVSP_VERSION_64_MASK) != 0)) {
+                 ah.t64 = rte_pktmbuf_read(m, off, sizeof(*ah.t64), &ah_copy);
+                 if (unlikely(ah.t64 == NULL))
+                       return pkt_type;
+                 off += sizeof(*ah.t64);
+                 hdr_lens->l2_len += sizeof(*ah.t64);
+                 proto = ah.t64->eth_proto;
+           } else if ((subtype == RTE_AVSP_SUBTYPE_TIMESTAMP &&
+                             (version & RTE_AVSP_VERSION_48_MASK) != 0)) {
+                 ah.t48 = rte_pktmbuf_read(m, off, sizeof(*ah.t48), &ah_copy);
+                 if (unlikely(ah.t48 == NULL))
+                       return pkt_type;
+                 off += sizeof(*ah.t48);
+                 hdr_lens->l2_len += sizeof(*ah.t48);
+                 proto = ah.t48->eth_proto;
+           } else
+                 return pkt_type;
+     }
+     if ((proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS)) ||
            (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLSM))) {
            unsigned int i;
            const struct rte_mpls_hdr *mh;
@@ -421,6 +470,54 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
            hdr_lens->inner_l2_len += 2 * sizeof(*vh);
            proto = vh->eth_proto;
      }
+     if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_AVSP)) {
+           union {
+                 const struct rte_avsp_common_hdr *common;
+                 const struct rte_avsp_tgen_hdr *tgen;
+                 const struct rte_avsp_timestamp_64_hdr *t64;
+                 const struct rte_avsp_timestamp_48_hdr *t48;
+           } ah;
+           union {
+                 struct rte_avsp_common_hdr common;
+                 struct rte_avsp_tgen_hdr tgen;
+                 struct rte_avsp_timestamp_64_hdr t64;
+                 struct rte_avsp_timestamp_48_hdr t48;
+           } ah_copy;
+
+           ah.common = rte_pktmbuf_read(m, off, sizeof(*ah.common),
+                                                      &ah_copy.common);
+           if (unlikely(ah.common == NULL))
+                 return pkt_type;
+           uint16_t subtype = rte_be_to_cpu_16(ah.common->subtype);
+           uint16_t version = rte_be_to_cpu_16(ah.common->version);
+
+           if (subtype == RTE_AVSP_SUBTYPE_TGEN &&
+                       (version == RTE_AVSP_VERSION_TGEN)) {
+                 ah.tgen = rte_pktmbuf_read(m, off, sizeof(*ah.tgen), &ah_copy);
+                 if (unlikely(ah.tgen == NULL))
+                       return pkt_type;
+                 off += sizeof(*ah.tgen);
+                 hdr_lens->inner_l2_len += sizeof(*ah.tgen);
+                 proto = ah.tgen->eth_proto;
+           } else if ((subtype == RTE_AVSP_SUBTYPE_TIMESTAMP &&
+                             (version & RTE_AVSP_VERSION_64_MASK) != 0)) {
+                 ah.t64 = rte_pktmbuf_read(m, off, sizeof(*ah.t64), &ah_copy);
+                 if (unlikely(ah.t64 == NULL))
+                       return pkt_type;
+                 off += sizeof(*ah.t64);
+                 hdr_lens->inner_l2_len += sizeof(*ah.t64);
+                 proto = ah.t64->eth_proto;
+           } else if ((subtype == RTE_AVSP_SUBTYPE_TIMESTAMP &&
+                             (version & RTE_AVSP_VERSION_48_MASK) != 0)) {
+                 ah.t48 = rte_pktmbuf_read(m, off, sizeof(*ah.t48), &ah_copy);
+                 if (unlikely(ah.t48 == NULL))
+                       return pkt_type;
+                 off += sizeof(*ah.t48);
+                 hdr_lens->inner_l2_len += sizeof(*ah.t48);
+                 proto = ah.t48->eth_proto;
+           } else
+                 return pkt_type;
+     }
 
      if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0)
            return pkt_type;
-- 
2.48.1