net: support Arista L2 headers
Checks
Commit Message
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(-)
--
2.48.1
Comments
04/02/2025 16:41, Denis Davidoglu:
> 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.
I'm not familiar with these headers.
Are they standardized?
Is there a RFC?
> +/* 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
I'm not sure about adding vendor specific protocols.
What should be the policy here?
From: Thomas Monjalon <thomas@monjalon.net>
> I'm not familiar with these headers.
> Are they standardized?
> Is there a RFC?
Arista Vendor Specific Protocol is not publicly disclosed yet. However, Wireshark already includes a dissector implementetation and its source code can serve for now as a reference:
https://gitlab.com/wireshark/wireshark/-/blob/master/epan/dissectors/packet-avsp.c
> I'm not sure about adding vendor specific protocols.
> What should be the policy here?
Given the large number of registered EtherType™ assignments related to IEEE 802.3™ (ISO/IEC 8802-3) standard, supporting vendor-specific protocols should be considered. Though probably not in the way I organized it, mixing RFC-standardized and proprietary protocols in the same files. ./lib/net can have a new subdirectory for keeping them separate.
Arista timestamp is particularly valuable for stock exchanges due to efficiency. The timestamp extension is already in use at German Eurex Exchange and it needs to undergo PoC trials at Borsa İstanbul, which utilizes Nasdaq infrastructure. Some parts of it rely on DPDK and this patch will be especially useful.
On Fri, 7 Feb 2025 09:07:57 +0000
"Denis Davidoglu" <denis.davidoglu@b-ulltech.com> wrote:
> From: Thomas Monjalon <thomas@monjalon.net>
> > I'm not familiar with these headers.
> > Are they standardized?
> > Is there a RFC?
>
> Arista Vendor Specific Protocol is not publicly disclosed yet. However, Wireshark already includes a dissector implementetation and its source code can serve for now as a reference:
> https://gitlab.com/wireshark/wireshark/-/blob/master/epan/dissectors/packet-avsp.c
>
> > I'm not sure about adding vendor specific protocols.
> > What should be the policy here?
>
> Given the large number of registered EtherType™ assignments related to IEEE 802.3™ (ISO/IEC 8802-3) standard, supporting vendor-specific protocols should be considered. Though probably not in the way I organized it, mixing RFC-standardized and proprietary protocols in the same files. ./lib/net can have a new subdirectory for keeping them separate.
>
> Arista timestamp is particularly valuable for stock exchanges due to efficiency. The timestamp extension is already in use at German Eurex Exchange and it needs to undergo PoC trials at Borsa İstanbul, which utilizes Nasdaq infrastructure. Some parts of it rely on DPDK and this patch will be especially useful.
The rte_net_ptype() is intended to provide a software equivalent for the packet type
matching done in many smart NIC's. It is not meant to be a general purpose L2 packet
parser.
If a user needs to do this kind of packet processing, it belongs in the application
and all the data and metadata is exposed to do this.
@@ -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
@@ -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;