DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v14 18/20] net/sxe2: add mbuf validation in Tx debug mode
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Introduce the `sxe2_txrx_check_mbuf` helper function to validate outgoing
mbufs when `RTE_ETHDEV_DEBUG_TX` is enabled. This helps developers catch
malformed mbufs (e.g., invalid segment lengths, bad offload flags, or
unaligned buffers) before passing them to the hardware rings, avoiding
potential hardware hangs or silent packet drops.

The validation is fully wrapped inside `RTE_ETHDEV_DEBUG_TX` conditional
compilation blocks to ensure zero performance overhead in standard
production builds.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/net/sxe2/meson.build            |   2 +
 drivers/net/sxe2/sxe2_txrx.c            |   8 +-
 drivers/net/sxe2/sxe2_txrx_check_mbuf.c | 595 ++++++++++++++++++++++++
 drivers/net/sxe2/sxe2_txrx_check_mbuf.h |  38 ++
 4 files changed, 641 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.h

diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index d653d071a9..4fb2333926 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -78,4 +78,6 @@ sources += files(
         'sxe2_flow_parse_pattern.c',
         'sxe2_flow_parse_engine.c',
         'sxe2_dump.c',
+        'sxe2_txrx_check_mbuf.c',
+
 )
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index 3861e31688..630353461d 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -13,6 +13,7 @@
 #include "sxe2_txrx_common.h"
 #include "sxe2_txrx_vec.h"
 #include "sxe2_txrx_poll.h"
+#include "sxe2_txrx_check_mbuf.h"
 #include "sxe2_ethdev.h"
 #include "sxe2_common_log.h"
 #include "sxe2_osal.h"
@@ -120,13 +121,11 @@ uint16_t sxe2_tx_pkts_prepare(void *tx_queue,
 			rte_errno = -EINVAL;
 			goto l_end;
 		}
-#ifdef RTE_ETHDEV_DEBUG_TX
 		ret = rte_validate_tx_offload(mbuf);
 		if (ret != 0) {
 			rte_errno = -ret;
 			goto l_end;
 		}
-#endif
 		ret = rte_net_intel_cksum_prepare(mbuf);
 		if (ret != 0) {
 			rte_errno = -ret;
@@ -137,6 +136,11 @@ uint16_t sxe2_tx_pkts_prepare(void *tx_queue,
 			rte_errno = -ret;
 			goto l_end;
 		}
+		ret = sxe2_txrx_check_mbuf(mbuf);
+		if (ret != 0) {
+			rte_errno = -ret;
+			goto l_end;
+		}
 	}
 l_end:
 	return i;
diff --git a/drivers/net/sxe2/sxe2_txrx_check_mbuf.c b/drivers/net/sxe2/sxe2_txrx_check_mbuf.c
new file mode 100644
index 0000000000..7d316ae652
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_check_mbuf.c
@@ -0,0 +1,595 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_common.h>
+#include <rte_net.h>
+#include <rte_vect.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <ethdev_driver.h>
+#include <rte_geneve.h>
+
+#include "sxe2_txrx_check_mbuf.h"
+#include "sxe2_common_log.h"
+
+#define TX_IPPROTO_IPIP 4
+#define TX_IPPROTO_GRE  47
+#define GRE_CHECKSUM_PRESENT 0x8000
+#define GRE_KEY_PRESENT 0x2000
+#define GRE_SEQUENCE_PRESENT 0x1000
+#define GRE_EXT_LEN 4
+#define GRE_SUPPORTED_FIELDS (GRE_CHECKSUM_PRESENT | GRE_KEY_PRESENT | GRE_SEQUENCE_PRESENT)
+
+
+static uint16_t vxlan_gpe_udp_port = RTE_VXLAN_GPE_DEFAULT_PORT;
+static uint16_t geneve_udp_port = RTE_GENEVE_DEFAULT_PORT;
+
+static inline int32_t check_mbuf_len(struct offload_info *info, struct rte_mbuf *m)
+{
+	int32_t ret = 0;
+	if (m->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+		if (info->outer_l2_len != m->outer_l2_len) {
+			PMD_LOG_ERR(TX, "outer_l2_len error in mbuf. Original "
+				    "length:%u calculated length:%u", m->outer_l2_len,
+				    info->outer_l2_len);
+			ret = -1;
+			goto end;
+		}
+		if (info->outer_l3_len != m->outer_l3_len) {
+			PMD_LOG_ERR(TX, "outer_l3_len error in mbuf. Original "
+				    "length:%u calculated length:%u", m->outer_l3_len,
+				    info->outer_l3_len);
+			ret = -1;
+			goto end;
+		}
+	}
+
+	if (info->l2_len != m->l2_len) {
+		PMD_LOG_ERR(TX, "l2_len error in mbuf. Original "
+			"length:%u calculated length:%u", m->l2_len, info->l2_len);
+		ret = -1;
+		goto end;
+	}
+	if (info->l3_len != m->l3_len) {
+		PMD_LOG_ERR(TX, "l3_len error in mbuf. Original "
+			"length:%u calculated length:%u", m->l3_len, info->l3_len);
+		ret = -1;
+		goto end;
+	}
+	if (info->l4_len != m->l4_len) {
+		PMD_LOG_ERR(TX, "l4_len error in mbuf. Original "
+			"length:%u calculated length:%u", m->l4_len, info->l4_len);
+		ret = -1;
+		goto end;
+	}
+	ret = 0;
+
+end:
+	return ret;
+}
+
+static inline int32_t check_ether_type(struct offload_info *info, struct rte_mbuf *m)
+{
+	int32_t ret = 0;
+
+	if (m->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+		if (info->outer_ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+			if (!(m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)) {
+				PMD_LOG_ERR(TX, "Outer ethernet type is ipv4, "
+					"tx offload missing `RTE_MBUF_F_TX_OUTER_IPV4` flag");
+				ret = -1;
+				goto end;
+			}
+			if (m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV6) {
+				PMD_LOG_ERR(TX, "Outer ethernet type is ipv4, tx "
+					"offload contains wrong `RTE_MBUF_F_TX_OUTER_IPV6` flag");
+				ret = -1;
+				goto end;
+			}
+		} else if (info->outer_ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+			if (!(m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)) {
+				PMD_LOG_ERR(TX, "Outer ethernet type is ipv6, "
+					"tx offload missing `RTE_MBUF_F_TX_OUTER_IPV6` flag");
+				ret = -1;
+				goto end;
+			}
+			if (m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV4) {
+				PMD_LOG_ERR(TX, "Outer ethernet type is ipv6, tx "
+					"offload contains wrong `RTE_MBUF_F_TX_OUTER_IPV4` flag");
+				ret = -1;
+				goto end;
+			}
+		}
+	}
+
+	if (info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+		if (!(m->ol_flags & RTE_MBUF_F_TX_IPV4)) {
+			PMD_LOG_ERR(TX, "Ethernet type is ipv4, tx offload "
+				"missing `RTE_MBUF_F_TX_IPV4` flag.");
+			ret = -1;
+			goto end;
+		}
+		if (m->ol_flags & RTE_MBUF_F_TX_IPV6) {
+			PMD_LOG_ERR(TX, "Ethernet type is ipv4, tx "
+				"offload contains wrong `RTE_MBUF_F_TX_IPV6` flag");
+			ret = -1;
+			goto end;
+		}
+	} else if (info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+		if (!(m->ol_flags & RTE_MBUF_F_TX_IPV6)) {
+			PMD_LOG_ERR(TX, "Ethernet type is ipv6, tx offload "
+				"missing `RTE_MBUF_F_TX_IPV6` flag.");
+			ret = -1;
+			goto end;
+		}
+		if (m->ol_flags & RTE_MBUF_F_TX_IPV4) {
+			PMD_LOG_ERR(TX, "Ethernet type is ipv6, tx offload "
+				"contains wrong `RTE_MBUF_F_TX_IPV4` flag");
+			ret = -1;
+			goto end;
+		}
+	}
+	ret = 0;
+
+end:
+	return ret;
+}
+
+static inline void parse_ipv4(struct rte_ipv4_hdr *ipv4_hdr, struct offload_info *info)
+{
+	struct rte_tcp_hdr *tcp_hdr;
+
+	info->l3_len   = rte_ipv4_hdr_len(ipv4_hdr);
+	info->l4_proto = ipv4_hdr->next_proto_id;
+
+	if (info->l4_proto == IPPROTO_TCP) {
+		tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv4_hdr + info->l3_len);
+		info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+	} else if (info->l4_proto == IPPROTO_UDP) {
+		info->l4_len = sizeof(struct rte_udp_hdr);
+	} else {
+		info->l4_len = 0;
+	}
+}
+
+static inline void parse_ipv6(struct rte_ipv6_hdr *ipv6_hdr, struct offload_info *info)
+{
+	struct rte_tcp_hdr *tcp_hdr;
+
+	info->l3_len   = sizeof(struct rte_ipv6_hdr);
+	info->l4_proto = ipv6_hdr->proto;
+
+	if (info->l4_proto == IPPROTO_TCP) {
+		tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv6_hdr + info->l3_len);
+		info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+	} else if (info->l4_proto == IPPROTO_UDP) {
+		info->l4_len = sizeof(struct rte_udp_hdr);
+	} else {
+		info->l4_len = 0;
+	}
+}
+
+static inline void parse_ethernet(struct rte_ether_hdr *eth_hdr, struct offload_info *info)
+{
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	struct rte_vlan_hdr *vlan_hdr;
+
+	info->l2_len = sizeof(struct rte_ether_hdr);
+	info->ethertype = eth_hdr->ether_type;
+
+	while (info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN) ||
+		   info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_QINQ)) {
+		vlan_hdr = (struct rte_vlan_hdr *)
+			((char *)eth_hdr + info->l2_len);
+		info->l2_len   += sizeof(struct rte_vlan_hdr);
+		info->ethertype = vlan_hdr->eth_proto;
+	}
+
+	switch (info->ethertype) {
+	case RTE_STATIC_BSWAP16(RTE_ETHER_TYPE_IPV4):
+		ipv4_hdr = (struct rte_ipv4_hdr *)((char *)eth_hdr + info->l2_len);
+		parse_ipv4(ipv4_hdr, info);
+		break;
+	case RTE_STATIC_BSWAP16(RTE_ETHER_TYPE_IPV6):
+		ipv6_hdr = (struct rte_ipv6_hdr *)((char *)eth_hdr + info->l2_len);
+		parse_ipv6(ipv6_hdr, info);
+		break;
+	default:
+		info->l4_len = 0;
+		info->l3_len = 0;
+		info->l4_proto = 0;
+		break;
+	}
+}
+
+static inline void update_tunnel_outer(struct offload_info *info)
+{
+	info->is_tunnel       = 1;
+	info->outer_ethertype = info->ethertype;
+	info->outer_l2_len    = info->l2_len;
+	info->outer_l3_len    = info->l3_len;
+	info->outer_l4_proto  = info->l4_proto;
+}
+
+static inline void parse_gtp(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	struct rte_gtp_hdr *gtp_hdr;
+	uint8_t gtp_len = sizeof(*gtp_hdr);
+	uint8_t ip_ver;
+
+	if (udp_hdr->dst_port != rte_cpu_to_be_16(RTE_GTPC_UDP_PORT) &&
+		udp_hdr->src_port != rte_cpu_to_be_16(RTE_GTPC_UDP_PORT) &&
+		udp_hdr->dst_port != rte_cpu_to_be_16(RTE_GTPU_UDP_PORT))
+		goto end;
+
+	update_tunnel_outer(info);
+	info->l2_len = 0;
+
+	gtp_hdr = (struct rte_gtp_hdr *)((char *)udp_hdr + sizeof(*udp_hdr));
+
+	if (gtp_hdr->msg_type == 0xff) {
+		ip_ver = *(uint8_t *)((char *)udp_hdr + sizeof(*udp_hdr) + sizeof(*gtp_hdr));
+		ip_ver = (ip_ver) & 0xf0;
+
+		if (ip_ver == RTE_GTP_TYPE_IPV4) {
+			ipv4_hdr = (struct rte_ipv4_hdr *)((char *)gtp_hdr + gtp_len);
+			info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+			parse_ipv4(ipv4_hdr, info);
+		} else if (ip_ver == RTE_GTP_TYPE_IPV6) {
+			ipv6_hdr = (struct rte_ipv6_hdr *)((char *)gtp_hdr + gtp_len);
+			info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+			parse_ipv6(ipv6_hdr, info);
+		}
+	} else {
+		info->ethertype = 0;
+		info->l4_len    = 0;
+		info->l3_len    = 0;
+		info->l4_proto  = 0;
+	}
+
+	info->l2_len += RTE_ETHER_GTP_HLEN;
+
+end:
+	return;
+}
+
+static inline void parse_vxlan(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+	struct rte_ether_hdr *eth_hdr;
+
+	if (udp_hdr->dst_port != rte_cpu_to_be_16(RTE_VXLAN_DEFAULT_PORT))
+		goto end;
+
+	update_tunnel_outer(info);
+
+	eth_hdr = (struct rte_ether_hdr *)((char *)udp_hdr +
+		sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr));
+
+	parse_ethernet(eth_hdr, info);
+	info->l2_len += RTE_ETHER_VXLAN_HLEN;
+
+end:
+	return;
+}
+
+static inline void parse_vxlan_gpe(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+	struct rte_ether_hdr *eth_hdr;
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	struct rte_vxlan_gpe_hdr *vxlan_gpe_hdr;
+	uint8_t vxlan_gpe_len = sizeof(*vxlan_gpe_hdr);
+
+	if (udp_hdr->dst_port != rte_cpu_to_be_16(vxlan_gpe_udp_port))
+		goto end;
+
+	vxlan_gpe_hdr = (struct rte_vxlan_gpe_hdr *)((char *)udp_hdr + sizeof(struct rte_udp_hdr));
+
+	if (!vxlan_gpe_hdr->proto || vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_IPV4) {
+		update_tunnel_outer(info);
+
+		ipv4_hdr = (struct rte_ipv4_hdr *)((char *)vxlan_gpe_hdr + vxlan_gpe_len);
+
+		parse_ipv4(ipv4_hdr, info);
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+		info->l2_len = 0;
+
+	} else if (vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_IPV6) {
+		update_tunnel_outer(info);
+
+		ipv6_hdr = (struct rte_ipv6_hdr *)((char *)vxlan_gpe_hdr + vxlan_gpe_len);
+
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+		parse_ipv6(ipv6_hdr, info);
+		info->l2_len = 0;
+
+	} else if (vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_ETH) {
+		update_tunnel_outer(info);
+
+		eth_hdr = (struct rte_ether_hdr *)((char *)vxlan_gpe_hdr + vxlan_gpe_len);
+
+		parse_ethernet(eth_hdr, info);
+	} else {
+		goto end;
+	}
+
+	info->l2_len += RTE_ETHER_VXLAN_GPE_HLEN;
+
+end:
+	return;
+}
+
+static inline void parse_geneve(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+	struct rte_ether_hdr *eth_hdr;
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	struct rte_geneve_hdr *geneve_hdr;
+	uint16_t geneve_len;
+
+	if (udp_hdr->dst_port != rte_cpu_to_be_16(geneve_udp_port))
+		goto end;
+
+	geneve_hdr = (struct rte_geneve_hdr *)((char *)udp_hdr + sizeof(struct rte_udp_hdr));
+	geneve_len = sizeof(struct rte_geneve_hdr) + geneve_hdr->opt_len * 4;
+	if (!geneve_hdr->proto || geneve_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+		update_tunnel_outer(info);
+		ipv4_hdr = (struct rte_ipv4_hdr *)((char *)geneve_hdr + geneve_len);
+		parse_ipv4(ipv4_hdr, info);
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+		info->l2_len = 0;
+	} else if (geneve_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+		update_tunnel_outer(info);
+		ipv6_hdr = (struct rte_ipv6_hdr *)((char *)geneve_hdr + geneve_len);
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+		parse_ipv6(ipv6_hdr, info);
+		info->l2_len = 0;
+
+	} else if (geneve_hdr->proto == rte_cpu_to_be_16(RTE_GENEVE_TYPE_ETH)) {
+		update_tunnel_outer(info);
+		eth_hdr = (struct rte_ether_hdr *)((char *)geneve_hdr + geneve_len);
+		parse_ethernet(eth_hdr, info);
+	} else {
+		goto end;
+	}
+
+	info->l2_len += (sizeof(struct rte_udp_hdr) + sizeof(struct rte_geneve_hdr) +
+		((struct rte_geneve_hdr *)geneve_hdr)->opt_len * 4);
+
+end:
+	return;
+}
+
+static inline void parse_gre(struct simple_gre_hdr *gre_hdr, struct offload_info *info)
+{
+	struct rte_ether_hdr *eth_hdr;
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	uint8_t gre_len = 0;
+
+	gre_len += sizeof(struct simple_gre_hdr);
+
+	if (gre_hdr->flags & rte_cpu_to_be_16(GRE_KEY_PRESENT))
+		gre_len += GRE_EXT_LEN;
+	if (gre_hdr->flags & rte_cpu_to_be_16(GRE_SEQUENCE_PRESENT))
+		gre_len += GRE_EXT_LEN;
+	if (gre_hdr->flags & rte_cpu_to_be_16(GRE_CHECKSUM_PRESENT))
+		gre_len += GRE_EXT_LEN;
+
+	if (gre_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+		update_tunnel_outer(info);
+
+		ipv4_hdr = (struct rte_ipv4_hdr *)((char *)gre_hdr + gre_len);
+
+		parse_ipv4(ipv4_hdr, info);
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+		info->l2_len = 0;
+
+	} else if (gre_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+		update_tunnel_outer(info);
+
+		ipv6_hdr = (struct rte_ipv6_hdr *)((char *)gre_hdr + gre_len);
+
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+		parse_ipv6(ipv6_hdr, info);
+		info->l2_len = 0;
+
+	} else if (gre_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB)) {
+		update_tunnel_outer(info);
+
+		eth_hdr = (struct rte_ether_hdr *)((char *)gre_hdr + gre_len);
+
+		parse_ethernet(eth_hdr, info);
+	} else {
+		goto end;
+	}
+
+	info->l2_len += gre_len;
+
+end:
+	return;
+}
+
+static inline void parse_encap_ip(void *encap_ip, struct offload_info *info)
+{
+	struct rte_ipv4_hdr *ipv4_hdr = encap_ip;
+	struct rte_ipv6_hdr *ipv6_hdr = encap_ip;
+	uint8_t ip_version;
+
+	ip_version = ((ipv4_hdr->version_ihl & 0xf0) >> 4);
+
+	if (ip_version != 4 && ip_version != 6)
+		goto end;
+
+	info->is_tunnel = 1;
+	info->outer_ethertype = info->ethertype;
+	info->outer_l2_len = info->l2_len;
+	info->outer_l3_len = info->l3_len;
+
+	if (ip_version == 4) {
+		parse_ipv4(ipv4_hdr, info);
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+	} else {
+		parse_ipv6(ipv6_hdr, info);
+		info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+	}
+	info->l2_len = 0;
+
+end:
+	return;
+}
+
+__rte_unused int32_t sxe2_txrx_check_mbuf(struct rte_mbuf *m)
+{
+	int32_t ret = 0;
+	struct rte_ether_hdr *eth_hdr;
+	void *l3_hdr = NULL;
+	struct offload_info info = {0};
+	uint64_t ol_flags = m->ol_flags;
+	uint64_t tunnel_type = ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK;
+
+	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
+	parse_ethernet(eth_hdr, &info);
+	l3_hdr = (char *)eth_hdr + info.l2_len;
+	if (info.l4_proto == IPPROTO_UDP) {
+		struct rte_udp_hdr *udp_hdr;
+
+		udp_hdr = (struct rte_udp_hdr *)((char *)l3_hdr + info.l3_len);
+		if ((info.l2_len + info.l3_len + sizeof(struct rte_udp_hdr)) > m->data_len) {
+			PMD_LOG_ERR(TX, "UDP header exceeds mbuf data length");
+			ret = -1;
+			goto end;
+		}
+		parse_gtp(udp_hdr, &info);
+		if (info.is_tunnel) {
+			if (!tunnel_type) {
+				PMD_LOG_ERR(TX, "gtp tunnel packet missing tx "
+					"offload missing `RTE_MBUF_F_TX_TUNNEL_GTP` flag");
+				ret = -1;
+				goto end;
+			}
+			if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_GTP) {
+				PMD_LOG_ERR(TX, "gtp tunnel packet, tx offload has wrong "
+					"`%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_GTP` flag",
+				rte_get_tx_ol_flag_name(tunnel_type));
+				ret = -1;
+				goto end;
+			}
+			goto check_len;
+		}
+		parse_vxlan_gpe(udp_hdr, &info);
+		if (info.is_tunnel) {
+			if (!tunnel_type) {
+				PMD_LOG_ERR(TX, "vxlan gpe tunnel packet missing tx "
+					"offload missing `RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE` flag");
+				ret = -1;
+				goto end;
+			}
+			if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE) {
+				PMD_LOG_ERR(TX, "vxlan gpe tunnel packet, tx offload has "
+					"wrong `%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE` flag",
+				rte_get_tx_ol_flag_name(tunnel_type));
+				ret = -1;
+				goto end;
+			}
+			goto check_len;
+		}
+		parse_vxlan(udp_hdr, &info);
+		if (info.is_tunnel) {
+			if (!tunnel_type) {
+				PMD_LOG_ERR(TX, "vxlan tunnel packet missing tx "
+					"offload missing `RTE_MBUF_F_TX_TUNNEL_VXLAN` flag");
+				ret = -1;
+				goto end;
+			}
+			if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_VXLAN) {
+				PMD_LOG_ERR(TX, "vxlan tunnel packet, tx offload has "
+					"wrong `%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_VXLAN` flag",
+				rte_get_tx_ol_flag_name(tunnel_type));
+				ret = -1;
+				goto end;
+			}
+			goto check_len;
+		}
+		parse_geneve(udp_hdr, &info);
+		if (info.is_tunnel) {
+			if (!tunnel_type) {
+				PMD_LOG_ERR(TX, "geneve tunnel packet missing tx "
+					"offload missing `RTE_MBUF_F_TX_TUNNEL_GENEVE` flag");
+				ret = -1;
+				goto end;
+			}
+			if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_GENEVE) {
+				PMD_LOG_ERR(TX, "geneve tunnel packet, tx offload has "
+					"wrong `%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_GENEVE` flag",
+				rte_get_tx_ol_flag_name(tunnel_type));
+				ret = -1;
+				goto end;
+			}
+			goto check_len;
+		}
+
+		if (unlikely(RTE_ETH_IS_TUNNEL_PKT(m->packet_type) != 0)) {
+			PMD_LOG_ERR(TX, "Unknown tunnel packet UDP dst port:%u",
+				    udp_hdr->dst_port);
+			ret = -1;
+			goto end;
+		}
+	} else if (info.l4_proto == TX_IPPROTO_GRE) {
+		struct simple_gre_hdr *gre_hdr;
+
+		gre_hdr = (struct simple_gre_hdr *)((char *)l3_hdr + info.l3_len);
+		parse_gre(gre_hdr, &info);
+		if (info.is_tunnel) {
+			if (!tunnel_type) {
+				PMD_LOG_ERR(TX, "gre tunnel packet missing tx "
+					"offload missing `RTE_MBUF_F_TX_TUNNEL_GRE` flag.");
+				ret = -1;
+				goto end;
+			}
+			if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_GRE) {
+				PMD_LOG_ERR(TX, "gre tunnel packet, tx offload has "
+					"wrong `%s` flag, correct is `RTE_MBUF_F_TX_TUNNEL_GRE` flag",
+				rte_get_tx_ol_flag_name(tunnel_type));
+				ret = -1;
+				goto end;
+			}
+			goto check_len;
+		}
+	} else if (info.l4_proto == TX_IPPROTO_IPIP) {
+		void *encap_ip_hdr;
+
+		encap_ip_hdr = (char *)l3_hdr + info.l3_len;
+		parse_encap_ip(encap_ip_hdr, &info);
+		if (info.is_tunnel) {
+			if (!tunnel_type) {
+				PMD_LOG_ERR(TX, "Ipip tunnel packet missing tx "
+					"offload missing `RTE_MBUF_F_TX_TUNNEL_IPIP` flag");
+				ret = -1;
+				goto end;
+			}
+			if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_IPIP) {
+				PMD_LOG_ERR(TX, "Ipip tunnel packet, tx offload has "
+					"wrong `%s` flag, correct is `RTE_MBUF_F_TX_TUNNEL_IPIP` flag",
+				rte_get_tx_ol_flag_name(tunnel_type));
+				ret = -1;
+				goto end;
+			}
+			goto check_len;
+		}
+	}
+
+check_len:
+	if (check_mbuf_len(&info, m) != 0) {
+		ret = -1;
+		goto end;
+	}
+	ret = check_ether_type(&info, m);
+
+end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_txrx_check_mbuf.h b/drivers/net/sxe2/sxe2_txrx_check_mbuf.h
new file mode 100644
index 0000000000..98197f85d9
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_check_mbuf.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_TXRX_CHECK_MBUF_H__
+#define __SXE2_TXRX_CHECK_MBUF_H__
+
+#include <rte_common.h>
+#include <rte_net.h>
+#include <rte_vect.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <ethdev_driver.h>
+
+struct offload_info {
+	uint16_t ethertype;
+	uint8_t  gso_enable;
+	uint16_t l2_len;
+	uint16_t l3_len;
+	uint16_t l4_len;
+	uint8_t  l4_proto;
+	uint8_t  is_tunnel;
+	uint16_t outer_ethertype;
+	uint16_t outer_l2_len;
+	uint16_t outer_l3_len;
+	uint8_t  outer_l4_proto;
+	uint16_t tso_segsz;
+	uint16_t tunnel_tso_segsz;
+	uint32_t pkt_len;
+};
+
+struct simple_gre_hdr {
+	uint16_t flags;
+	uint16_t proto;
+};
+
+__rte_unused int32_t sxe2_txrx_check_mbuf(struct rte_mbuf *m);
+#endif /* __SXE2_TXRX_CHECK_MBUF_H__ */
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 03/20] drivers: add supported packet types get callback
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Implement dev_supported_ptypes_get ethdev callback for sxe2 PMD.
This allows applications to query the packet types the driver
is capable of identifying, such as L2, L3 (IPv4/IPv6), and
L4 (TCP/UDP/SCTP) layers.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_ptype.h | 1793 ++++++++++++++++++++++++++++++
 drivers/net/sxe2/meson.build     |    1 +
 drivers/net/sxe2/sxe2_cmd_chnl.c |   22 +
 drivers/net/sxe2/sxe2_cmd_chnl.h |    2 +
 drivers/net/sxe2/sxe2_drv_cmd.h  |    6 +
 drivers/net/sxe2/sxe2_ethdev.c   |  169 ++-
 drivers/net/sxe2/sxe2_ethdev.h   |   19 +-
 drivers/net/sxe2/sxe2_mac.c      |  103 ++
 drivers/net/sxe2/sxe2_mac.h      |   50 +
 9 files changed, 2126 insertions(+), 39 deletions(-)
 create mode 100644 drivers/common/sxe2/sxe2_ptype.h
 create mode 100644 drivers/net/sxe2/sxe2_mac.c
 create mode 100644 drivers/net/sxe2/sxe2_mac.h

diff --git a/drivers/common/sxe2/sxe2_ptype.h b/drivers/common/sxe2/sxe2_ptype.h
new file mode 100644
index 0000000000..9c19570979
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_ptype.h
@@ -0,0 +1,1793 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef _SXE2_PTYPE_H_
+#define _SXE2_PTYPE_H_
+#include <rte_ethdev.h>
+
+static inline const uint32_t *
+sxe2_dev_supported_ptypes_get(struct rte_eth_dev *dev, size_t *no_of_elements)
+{
+	const uint32_t *ret = NULL;
+
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L2_ETHER,
+		RTE_PTYPE_L2_ETHER_TIMESYNC,
+		RTE_PTYPE_L2_ETHER_LLDP,
+		RTE_PTYPE_L2_ETHER_ARP,
+		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
+		RTE_PTYPE_L4_FRAG,
+		RTE_PTYPE_L4_ICMP,
+		RTE_PTYPE_L4_NONFRAG,
+		RTE_PTYPE_L4_SCTP,
+		RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L4_UDP,
+		RTE_PTYPE_TUNNEL_GRENAT,
+		RTE_PTYPE_TUNNEL_IP,
+		RTE_PTYPE_INNER_L2_ETHER,
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
+		RTE_PTYPE_INNER_L4_FRAG,
+		RTE_PTYPE_INNER_L4_ICMP,
+		RTE_PTYPE_INNER_L4_NONFRAG,
+		RTE_PTYPE_INNER_L4_SCTP,
+		RTE_PTYPE_INNER_L4_TCP,
+		RTE_PTYPE_INNER_L4_UDP,
+		RTE_PTYPE_UNKNOWN
+	};
+
+	if (dev->rx_pkt_burst != NULL) {
+		*no_of_elements = RTE_DIM(ptypes);
+		ret = ptypes;
+	} else {
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+static inline void sxe2_init_ptype_list(uint32_t *ptype)
+{
+	/* ptype[0] reserved */
+	ptype[1] = RTE_PTYPE_L2_ETHER;
+	ptype[2] = RTE_PTYPE_L2_ETHER_TIMESYNC;
+	/* ptype[3] - ptype[5] reserved */
+	ptype[6] = RTE_PTYPE_L2_ETHER_LLDP;
+	/* ECP */
+	ptype[7] = RTE_PTYPE_UNKNOWN;
+	/* ptype[8] - ptype[9] reserved */
+	/* EAPol */
+	ptype[10] = RTE_PTYPE_UNKNOWN;
+	ptype[11] = RTE_PTYPE_L2_ETHER_ARP;
+	/* ptype[12] - ptype[21] reserved */
+
+	/* Non tunneled IPv4 */
+	ptype[22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_L4_FRAG;
+	ptype[23] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_L4_NONFRAG;
+	ptype[24] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_L4_UDP;
+	/* ptype[25] reserved */
+	ptype[26] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_L4_TCP;
+	ptype[27] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_L4_SCTP;
+	ptype[28] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_L4_ICMP;
+
+	/* IPv4 --> IPv4 */
+	ptype[29] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[30] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[31] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[32] reserved */
+	ptype[33] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[34] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[35] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 --> IPv6 */
+	ptype[36] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[37] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[38] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[39] reserved */
+	ptype[40] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 --> GRE/GENEVE/VXLAN */
+	ptype[43] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT;
+
+	/* IPv4 --> GRE/GENEVE/VXLAN --> IPv4 */
+	ptype[44] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[47] reserved */
+	ptype[48] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[50] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 --> GRE/GENEVE/VXLAN --> IPv6 */
+	ptype[51] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[52] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[53] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[54] reserved */
+	ptype[55] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[56] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[57] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 --> GRE/GENEVE/VXLAN --> MAC */
+	ptype[58] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER;
+
+	/* IPv4 --> GRE/GENEVE/VXLAN --> MAC --> IPv4 */
+	ptype[59] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[60] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[62] reserved */
+	ptype[63] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[64] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[65] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 --> GRE/GENEVE/VXLAN --> MAC --> IPv6 */
+	ptype[66] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[67] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[68] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[69] reserved */
+	ptype[70] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[71] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[72] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 --> GRE/GENEVE/VXLAN --> MAC/VLAN */
+	ptype[73] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN;
+	/* IPv4 --> GRE/GENEVE/VXLAN --> MAC/VLAN --> IPv4 */
+	ptype[74] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[75] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[76] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[77] reserved */
+	ptype[78] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP;
+	ptype[79] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP;
+	ptype[80] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 --> GRE/GENEVE/VXLAN --> MAC/VLAN --> IPv6 */
+	ptype[81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_FRAG;
+	ptype[82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[83] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[64] reserved */
+	ptype[85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP;
+	ptype[86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP;
+	ptype[87] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_ICMP;
+	/* Non tunneled IPv6 */
+	ptype[88] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_L4_FRAG;
+	ptype[89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_L4_NONFRAG;
+	ptype[90] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_L4_UDP;
+	/* ptype[91] reserved */
+	ptype[92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_L4_TCP;
+	ptype[93] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_L4_SCTP;
+	ptype[94] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_L4_ICMP;
+
+	/* IPv6 --> IPv4 */
+	ptype[95] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[96] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[97] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[98] reserved */
+	ptype[99] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_IP |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[100] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[101] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> IPv6 */
+	ptype[102] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[103] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[104] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[105] reserved */
+	ptype[106] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[107] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[108] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_IP |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN */
+	ptype[109] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> IPv4 */
+	ptype[110] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[111] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[112] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[113] reserved */
+	ptype[114] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[115] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[116] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> IPv6 */
+	ptype[117] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[118] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[119] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[120] reserved */
+	ptype[121] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[122] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[123] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> MAC */
+	ptype[124] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> MAC --> IPv4 */
+	ptype[125] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[126] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[127] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[128] reserved */
+	ptype[129] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[130] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[131] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> MAC --> IPv6 */
+	ptype[132] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[133] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[134] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[135] reserved */
+	ptype[136] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[137] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[138] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> MAC/VLAN */
+	ptype[139] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> MAC/VLAN --> IPv4 */
+	ptype[140] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[141] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[142] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[143] reserved */
+	ptype[144] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP;
+	ptype[145] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP;
+	ptype[146] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 --> GRE/GENEVE/VXLAN --> MAC/VLAN --> IPv6 */
+	ptype[147] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[148] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[149] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[150] reserved */
+	ptype[151] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP;
+	ptype[152] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP;
+	ptype[153] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_ICMP;
+	/* ptype[154] - ptype[159] reserved */
+	/* IPSec */
+	ptype[160] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_ESP;
+	ptype[161] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_ESP;
+	/* AH */
+	ptype[162] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[163] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* NAT-T-ESP */
+	ptype[164] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_ESP;
+	ptype[165] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_ESP;
+	/* SDN-ESP */
+	ptype[166] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_ESP;
+	ptype[167] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_ESP;
+	/* ptype[168] - ptype[271] reserved */
+	/* IPV4 --> VRRP */
+	ptype[272] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPV4 --> OSPF */
+	ptype[273] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPV6 --> VRRP */
+	ptype[274] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPV6 --> VRRP */
+	ptype[275] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* ATAoE */
+	ptype[276] = RTE_PTYPE_UNKNOWN;
+	/* Control */
+	ptype[278] = RTE_PTYPE_UNKNOWN;
+	/* ptype[279] - ptype[324] reserved */
+	/* GTP */
+	ptype[325] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPC;
+	ptype[326] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPC;
+	ptype[327] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPC;
+	ptype[328] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPC;
+	ptype[329] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU;
+	ptype[330] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU;
+	ptype[331] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_FRAG;
+	ptype[332] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[333] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[334] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_TCP;
+	ptype[335] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_ICMP;
+	ptype[336] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_FRAG;
+	ptype[337] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[338] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[339] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_TCP;
+	ptype[340] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_ICMP;
+	ptype[341] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_FRAG;
+	ptype[342] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[343] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[344] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_TCP;
+	ptype[345] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_ICMP;
+	ptype[346] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_FRAG;
+	ptype[347] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[348] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[349] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_TCP;
+	ptype[350] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_GTPU |
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_ICMP;
+	/* PFCP */
+	ptype[351] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP;
+	ptype[352] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP;
+	ptype[353] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP;
+	ptype[354] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP;
+	/* ptype[355] - ptype[359] reserved */
+	/* L2TPv3 */
+	ptype[360] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_L2TP;
+	ptype[361] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_L2TP;
+	/* ptype[362] - ptype[370] reserved */
+	/* eCPRI */
+	ptype[371] = RTE_PTYPE_UNKNOWN;
+	ptype[381] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[391] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[396] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, IGMP */
+	ptype[397] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, EIGRP */
+	ptype[398] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, EIGRP */
+	ptype[399] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, PIM */
+	ptype[400] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, PIM */
+	ptype[401] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, IGMP */
+	ptype[402] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, IGMP */
+	ptype[403] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, EIGRP */
+	ptype[404] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, EIGRP */
+	ptype[405] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, PIM */
+	ptype[406] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, PIM */
+	ptype[407] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, VRRP */
+	ptype[408] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, VRRP */
+	ptype[409] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, VRRP */
+	ptype[410] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, VRRP */
+	ptype[411] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, OSPF */
+	ptype[412] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, OSPF */
+	ptype[413] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, OSPF */
+	ptype[414] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, OSPF */
+	ptype[415] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, L2_TP_V3 */
+	ptype[416] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, L2_TP_V3 */
+	ptype[417] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, L2_TP_V3 */
+	ptype[418] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, L2_TP_V3 */
+	ptype[419] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, AH */
+	ptype[420] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, AH */
+	ptype[421] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, AH */
+	ptype[422] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, AH */
+	ptype[423] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv4, ESP */
+	ptype[424] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv4, ESP */
+	ptype[425] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv4, UDP, TUN, MAC, IPv6, ESP */
+	ptype[426] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* MAC, IPv6, UDP, TUN, MAC, IPv6, ESP */
+	ptype[427] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	/* TP-TUN GTPU */
+	ptype[450] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[451] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[452] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[453] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[454] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[455] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[456] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[457] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[458] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[459] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[460] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[461] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[462] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[463] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[464] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[465] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[466] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[467] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[468] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[469] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[470] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[471] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[472] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[473] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[474] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[475] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[476] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[477] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[478] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[479] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[480] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[481] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[482] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[483] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[484] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[485] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[486] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[487] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[488] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[489] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[490] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[491] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[492] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[493] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[494] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[495] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[496] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	ptype[497] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_TUNNEL_IP | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_INNER_L4_UDP;
+	/* ptype[498] - ptype[767] reserved */
+	/* L2(NETWORK CPU) */
+	/* ISIS */
+	ptype[768] = RTE_PTYPE_UNKNOWN;
+	/* SDF */
+	ptype[769] = RTE_PTYPE_UNKNOWN;
+	/* PPoE_NEGO */
+	ptype[770] = RTE_PTYPE_L2_ETHER_PPPOE;
+	/* PPoE_PROTOCOL */
+	ptype[771] = RTE_PTYPE_L2_ETHER_PPPOE;
+	ptype[772] = RTE_PTYPE_L2_ETHER_PPPOE;
+	/* LACP */
+	ptype[773] = RTE_PTYPE_UNKNOWN;
+	/* ptype[774] - ptype[775] reserved */
+	/* IPv4 L3(NETWORK CPU) */
+	ptype[776] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_IGMP;
+	/* EIGRP */
+	ptype[777] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* PIM */
+	ptype[778] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[779] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_L2TP;
+	ptype[780] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_L2TP;
+	ptype[781] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_L2TP;
+	/* ptype[782] - ptype[783] reserved */
+	/* IPv6 L3(NETWORK CPU) */
+	ptype[784] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_IGMP;
+	/* EIGRP */
+	ptype[785] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* PIM */
+	ptype[786] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[787] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_L2TP;
+	ptype[788] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_L2TP;
+	ptype[789] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP | RTE_PTYPE_TUNNEL_L2TP;
+	/* ptype[790] - ptype[791] reserved */
+	/* IPv4 L4(NETWORK CPU) */
+	ptype[792] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_TCP;
+	ptype[793] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_TCP;
+	ptype[794] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[795] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[796] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[797] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP;
+	ptype[798] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[799] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[800] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[801] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	/* ptype[802] - ptype[807] reserved */
+	/* IPv6 L4(NETWORK CPU) */
+	ptype[808] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_TCP;
+	ptype[809] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_TCP;
+	ptype[810] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[811] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[812] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+		RTE_PTYPE_L4_UDP;
+	ptype[813] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[814] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[815] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[816] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	ptype[817] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_UDP;
+	/* ptype[818] - ptype[819] reserved */
+	/* IPv6 -> MAC */
+	ptype[820] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPv6 -> MAC -> IPv4*/
+	ptype[821] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[822] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[823] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[824] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[825] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[826] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPv6 -> MAC -> IPv4*/
+	ptype[827] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[828] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[829] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[830] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[831] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[832] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* ptype[833] - ptype[834] reserved */
+	/* IPv6 -> MAC/VLAN */
+	ptype[835] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPv6 -> MAC/VLAN -> IPv4 */
+	ptype[836] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[837] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[838] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[839] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[840] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[841] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	/* IPv6 -> MAC/VLAN -> IPv6 */
+	ptype[842] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[843] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[844] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[845] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[846] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+	ptype[847] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_L4_NONFRAG;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> PAY */
+	ptype[878] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> IPv4 */
+	ptype[877] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[876] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[879] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	ptype[880] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[875] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[874] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> IPv6 */
+	ptype[871] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[870] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[872] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	ptype[873] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[869] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[868] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> PAY */
+	ptype[891] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT;
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> IPv4 */
+	ptype[890] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[889] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[892] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[893] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[888] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[887] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> IPv6 */
+	ptype[884] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[883] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[885] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[886] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[882] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[881] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 -> UDP -> GRE -> PAY */
+	ptype[904] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT;
+	/* IPv6 -> UDP -> GRE -> IPv4 */
+	ptype[903] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[902] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[905] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[906] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[901] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[900] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv6 -> UDP -> GRE -> IPv6 */
+	ptype[897] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[896] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[898] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[899] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[895] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[894] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 -> UDP -> GRE -> PAY */
+	ptype[917] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT;
+	/* IPv4 -> UDP -> GRE -> IPv4 */
+	ptype[916] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[915] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[918] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[919] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[914] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[913] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 -> UDP -> GRE -> IPv6 */
+	ptype[910] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[909] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[911] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[912] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[908] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[907] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> MACVLAN -> PAY */
+	ptype[930] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> MACVLAN -> IPv4 */
+	ptype[929] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[928] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[931] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	ptype[932] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[927] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[926] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> MACVLAN -> IPv6 */
+	ptype[923] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[922] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[924] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	ptype[925] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[921] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[920] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> MACVLAN -> PAY */
+	ptype[943] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN;
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> MACVLAN -> IPv4 */
+	ptype[942] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[941] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[944] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[945] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[940] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[939] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> MACVLAN -> IPv6 */
+	ptype[936] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[935] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[937] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[938] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[934] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[933] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 > UDP -> GRE -> MACVLAN -> PAY */
+	ptype[956] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN;
+	/* IPv6 -> UDP -> GRE -> MACVLAN -> IPv4 */
+	ptype[955] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[954] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[957] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[958] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[953] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[952] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv6 -> UDP -> GRE -> MACVLAN -> IPv6 */
+	ptype[949] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[948] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[950] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[951] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[947] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[946] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 -> UDP -> GRE -> MACVLAN -> PAY */
+	ptype[969] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN;
+	/* IPv4 -> UDP -> GRE -> MACVLAN -> IPv4 */
+	ptype[968] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[967] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[970] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[971] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[966] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[965] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 -> UDP -> GRE -> MACVLAN -> IPv6 */
+	ptype[962] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[961] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[963] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[964] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[960] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[959] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER_VLAN |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> MAC -> PAY */
+	ptype[982] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> MAC -> IPv4 */
+	ptype[981] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[980] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[983] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	ptype[984] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[979] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[978] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 -> UDP -> VXLAN/GENEVE -> MAC -> IPv6 */
+	ptype[975] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_FRAG;
+	ptype[974] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[976] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_UDP;
+	ptype[977] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_TCP;
+	ptype[973] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_SCTP;
+	ptype[972] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> MAC -> PAY */
+	ptype[995] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER;
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> MAC -> IPv4 */
+	ptype[994] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[993] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[996] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[997] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[992] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[991] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 -> UDP -> VXLAN/GENEVE -> MAC -> IPv6 */
+	ptype[988] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[987] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[989] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[990] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[986] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[985] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv6 > UDP -> GRE -> MAC -> PAY */
+	ptype[1008] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER;
+	/* IPv6 -> UDP -> GRE -> MAC -> IPv4 */
+	ptype[1007] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[1006] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[1009] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[1010] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[1005] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[1004] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv6 -> UDP -> GRE -> MAC -> IPv6 */
+	ptype[1001] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[1000] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[1002] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[1003] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[999] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[998] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+
+	/* IPv4 -> UDP -> GRE -> MAC -> PAY */
+	ptype[1021] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				 RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER;
+	/* IPv4 -> UDP -> GRE -> MAC -> IPv4 */
+	ptype[1020] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[1019] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[1022] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[1023] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[1018] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[1017] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+	/* IPv4 -> UDP -> GRE -> MAC -> IPv6 */
+	ptype[1014] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_FRAG;
+	ptype[1013] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_NONFRAG;
+	ptype[1015] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_UDP;
+	ptype[1016] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_TCP;
+	ptype[1012] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_SCTP;
+	ptype[1011] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+				RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+				RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+				RTE_PTYPE_INNER_L4_ICMP;
+}
+
+#endif /* _RTE_PTYPE_TUNNEL_GRENAT_H_ */
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index c225dd7cd8..b14b5120c1 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -60,4 +60,5 @@ sources += files(
         'sxe2_txrx_poll.c',
         'sxe2_txrx.c',
         'sxe2_txrx_vec.c',
+        'sxe2_mac.c',
 )
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index d16b6528d0..07eeb7f38c 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -321,3 +321,25 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
 
 	return ret;
 }
+
+int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_link_info_resp resp = {0};
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_LINK_STATUS_GET,
+				 NULL, 0,
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "link status get failed, ret=%d", ret);
+		goto l_end;
+	}
+	adapter->link_ctxt.speed = resp.speed;
+	adapter->link_ctxt.link_up = resp.status;
+
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index ed5e842346..cda676ed97 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -34,4 +34,6 @@ int32_t sxe2_drv_txq_ctxt_cfg(struct sxe2_adapter *adapter,
 			      struct sxe2_tx_queue *txq,
 			      uint16_t txq_cnt);
 
+int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
+
 #endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index ccc9c20ef4..a0f08b5184 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -227,6 +227,12 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_info_get_resp {
 	struct sxe2_drv_msix_caps used_msix;
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_link_info_resp {
+	uint32_t speed;
+	uint8_t status;
+	uint8_t rsv[3];
+} __rte_packed_end;
+
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
 	SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 066e1faf7e..80881595d6 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -27,7 +27,9 @@
 #include "sxe2_tx.h"
 #include "sxe2_rx.h"
 #include "sxe2_txrx.h"
+#include "sxe2_mac.h"
 #include "sxe2_common.h"
+#include "sxe2_ptype.h"
 #include "sxe2_common_log.h"
 #include "sxe2_host_regs.h"
 #include "sxe2_ioctl_chnl_func.h"
@@ -78,6 +80,41 @@ static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_pf[SXE2_PCI_MAP_RES_
 				      .reg_width = 10},
 };
 
+static int32_t sxe2_dev_configure(struct rte_eth_dev *dev);
+static int32_t sxe2_dev_start(struct rte_eth_dev *dev);
+static int32_t sxe2_dev_stop(struct rte_eth_dev *dev);
+static int32_t sxe2_dev_close(struct rte_eth_dev *dev);
+static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info);
+static const uint32_t *sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev
+				__rte_unused, size_t *no_of_elements __rte_unused);
+
+static const struct eth_dev_ops sxe2_eth_dev_ops = {
+	.dev_configure              = sxe2_dev_configure,
+	.dev_start                  = sxe2_dev_start,
+	.dev_stop                   = sxe2_dev_stop,
+	.dev_close                  = sxe2_dev_close,
+	.dev_infos_get              = sxe2_dev_infos_get,
+	.dev_supported_ptypes_get   = sxe2_dev_supported_ptypes_get,
+	.link_update                = sxe2_link_update,
+
+	.rx_queue_start             = sxe2_rx_queue_start,
+	.rx_queue_stop              = sxe2_rx_queue_stop,
+	.tx_queue_start             = sxe2_tx_queue_start,
+	.tx_queue_stop              = sxe2_tx_queue_stop,
+	.rx_queue_setup             = sxe2_rx_queue_setup,
+	.rx_queue_release           = sxe2_rx_queue_release,
+	.tx_queue_setup             = sxe2_tx_queue_setup,
+	.tx_queue_release           = sxe2_tx_queue_release,
+	.rxq_info_get               = sxe2_rx_queue_info_get,
+	.txq_info_get               = sxe2_tx_queue_info_get,
+	.rx_burst_mode_get          = sxe2_rx_burst_mode_get,
+	.tx_burst_mode_get          = sxe2_tx_burst_mode_get,
+	.tx_done_cleanup            = sxe2_tx_done_cleanup,
+
+	.mtu_set                    = sxe2_mtu_set,
+	.buffer_split_supported_hdr_ptypes_get = sxe2_buffer_split_supported_hdr_ptypes_get,
+};
+
 static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
 {
 	int32_t ret = 0;
@@ -122,6 +159,12 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
 	sxe2_rx_mode_func_set(dev);
 	sxe2_tx_mode_func_set(dev);
 
+	ret = sxe2_link_update_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret);
+		goto l_end;
+	}
+
 	ret = sxe2_queues_start(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "enable queues failed");
@@ -136,16 +179,6 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
 	return ret;
 }
 
-static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
-{
-	(void)sxe2_dev_stop(dev);
-	(void)sxe2_queues_release(dev);
-	sxe2_vsi_uninit(dev);
-	sxe2_dev_pci_map_uinit(dev);
-
-	return 0;
-}
-
 static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
 			struct rte_eth_dev_info *dev_info)
 {
@@ -270,28 +303,59 @@ static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
-static const struct eth_dev_ops sxe2_eth_dev_ops = {
-	.dev_configure              = sxe2_dev_configure,
-	.dev_start                  = sxe2_dev_start,
-	.dev_stop                   = sxe2_dev_stop,
-	.dev_close                  = sxe2_dev_close,
-	.dev_infos_get              = sxe2_dev_infos_get,
+static const uint32_t *
+sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev __rte_unused,
+					   size_t *no_of_elements __rte_unused)
+{
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L2_ETHER,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_UDP,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_SCTP,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_UDP,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_SCTP,
+
+		RTE_PTYPE_TUNNEL_GRENAT,
+
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER,
+
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
+
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP,
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP,
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP,
+
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP,
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP,
+		RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER |
+			RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP,
+
+		RTE_PTYPE_UNKNOWN
+	};
 
-	.rx_queue_start             = sxe2_rx_queue_start,
-	.rx_queue_stop              = sxe2_rx_queue_stop,
-	.tx_queue_start             = sxe2_tx_queue_start,
-	.tx_queue_stop              = sxe2_tx_queue_stop,
-	.rx_queue_setup             = sxe2_rx_queue_setup,
-	.rx_queue_release           = sxe2_rx_queue_release,
-	.tx_queue_setup             = sxe2_tx_queue_setup,
-	.tx_queue_release           = sxe2_tx_queue_release,
+	return ptypes;
+}
 
-	.rxq_info_get               = sxe2_rx_queue_info_get,
-	.txq_info_get               = sxe2_tx_queue_info_get,
-	.rx_burst_mode_get          = sxe2_rx_burst_mode_get,
-	.tx_burst_mode_get          = sxe2_tx_burst_mode_get,
-	.tx_done_cleanup            = sxe2_tx_done_cleanup,
-};
+static inline void sxe2_init_ptype_tbl(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	uint32_t *ptype = adapter->ptype_tbl;
+
+	PMD_INIT_FUNC_TRACE();
+
+	sxe2_init_ptype_list(ptype);
+}
 
 struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
 						    enum sxe2_pci_map_resource res_type)
@@ -360,6 +424,29 @@ void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter,
 	return addr;
 }
 
+static int32_t sxe2_eth_init(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+
+	ret = sxe2_link_update_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret);
+		goto l_end;
+	}
+
+	ret = sxe2_mtu_set(dev, dev->data->mtu);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to set mtu, ret=%d", ret);
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+static void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
 static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
 			struct sxe2_drv_dev_caps_resp *dev_caps)
 {
@@ -765,6 +852,8 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto l_end;
 	}
 
+	sxe2_init_ptype_tbl(dev);
+
 	ret = sxe2_hw_init(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "Failed to initialize hw, ret=[%d]", ret);
@@ -789,18 +878,38 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_dev_info_err;
 	}
 
+	ret = sxe2_eth_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize eth parameters, ret=%d", ret);
+		goto init_eth_err;
+	}
+
 	goto l_end;
 
+init_eth_err:
 init_dev_info_err:
 	sxe2_vsi_uninit(dev);
 init_vsi_err:
+	sxe2_dev_pci_map_uinit(dev);
 l_end:
 	return ret;
 }
 
+static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
+{
+	(void)sxe2_dev_stop(dev);
+	(void)sxe2_queues_release(dev);
+	sxe2_vsi_uninit(dev);
+	sxe2_dev_pci_map_uinit(dev);
+	sxe2_eth_uinit(dev);
+
+	return 0;
+}
+
 static int32_t sxe2_dev_uninit(struct rte_eth_dev *dev)
 {
 	int32_t ret = 0;
+
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		goto l_end;
 
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index a3706945e8..9de47d8338 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -120,12 +120,6 @@ enum {
 	SXE2_FLAGS_NBITS
 };
 
-struct sxe2_link_context {
-	rte_spinlock_t link_lock;
-	bool link_up;
-	uint32_t  speed;
-};
-
 struct sxe2_devargs {
 	uint8_t flow_dup_pattern_mode;
 	uint8_t func_flow_direct_en;
@@ -267,6 +261,12 @@ struct sxe2_sched_hw_cap {
 	uint8_t adj_lvl;
 };
 
+struct sxe2_link_context {
+	rte_spinlock_t link_lock;
+	bool link_up;
+	uint32_t  speed;
+};
+
 struct sxe2_adapter {
 	struct sxe2_common_device      *cdev;
 	struct sxe2_dev_info            dev_info;
@@ -276,9 +276,10 @@ struct sxe2_adapter {
 	struct sxe2_irq_context       irq_ctxt;
 	struct sxe2_queue_context     q_ctxt;
 	struct sxe2_vsi_context       vsi_ctxt;
-	struct sxe2_devargs			  devargs;
-	uint16_t                           dev_port_id;
-	uint64_t                           cap_flags;
+	struct sxe2_link_context      link_ctxt;
+	struct sxe2_devargs           devargs;
+	uint16_t                      dev_port_id;
+	uint64_t                      cap_flags;
 	enum sxe2_dev_type            dev_type;
 	uint32_t    ptype_tbl[SXE2_MAX_PTYPE_NUM];
 	struct rte_ether_addr           mac_addr;
diff --git a/drivers/net/sxe2/sxe2_mac.c b/drivers/net/sxe2/sxe2_mac.c
new file mode 100644
index 0000000000..3c2f909002
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_mac.c
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_os.h>
+#include "sxe2_osal.h"
+#include "sxe2_mac.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_host_regs.h"
+
+int32_t sxe2_link_update_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret;
+
+	PMD_INIT_FUNC_TRACE();
+
+	rte_spinlock_init(&adapter->link_ctxt.link_lock);
+
+	ret = sxe2_drv_mac_link_status_get(adapter);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get link status, ret=%d", ret);
+		goto l_end;
+	}
+
+	(void)sxe2_link_update(dev, 0);
+
+l_end:
+	return ret;
+}
+int32_t sxe2_link_update(struct rte_eth_dev *dev, __rte_unused int32_t wait_to_complete)
+{
+	struct rte_eth_link new_link;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	memset(&new_link, 0, sizeof(new_link));
+
+	switch (adapter->link_ctxt.speed) {
+	case 0:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+		break;
+	case 10:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_10M;
+		break;
+	case 100:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_100M;
+		break;
+	case 1000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_1G;
+		break;
+	case 10000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_10G;
+		break;
+	case 20000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_20G;
+		break;
+	case 25000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_25G;
+		break;
+	case 40000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_40G;
+		break;
+	case 50000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_50G;
+		break;
+	case 100000:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_100G;
+		break;
+	default:
+		new_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+		break;
+	}
+
+	new_link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+	new_link.link_status = adapter->link_ctxt.link_up ? RTE_ETH_LINK_UP :
+					     RTE_ETH_LINK_DOWN;
+	new_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+				RTE_ETH_LINK_SPEED_FIXED);
+
+	return rte_eth_linkstatus_set(dev, &new_link);
+}
+
+int32_t sxe2_mtu_set(struct rte_eth_dev *dev, uint16_t mtu __rte_unused)
+{
+	int32_t ret                      = -1;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	PMD_INIT_FUNC_TRACE();
+
+	if (dev->data->dev_started != 0) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "port %d must be stopped before configuration",
+				dev->data->port_id);
+		ret = -1;
+		goto l_end;
+	}
+
+	ret = 0;
+
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_mac.h b/drivers/net/sxe2/sxe2_mac.h
new file mode 100644
index 0000000000..f2f3edaeff
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_mac.h
@@ -0,0 +1,50 @@
+
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_MAC_H__
+#define __SXE2_MAC_H__
+#include <ethdev_driver.h>
+#include "sxe2_host_regs.h"
+
+#define SXE2_NUM_MACADDR_MAX   64
+
+#define SXE2_DPDK_OFFLOAD_OUTER_INSERT_8021Q SXE2_VSI_L2TAGSTXVALID_ID_OUT_VLAN1
+#define SXE2_DPDK_OFFLOAD_OUTER_INSERT_8021AD SXE2_VSI_L2TAGSTXVALID_ID_STAG
+#define SXE2_DPDK_OFFLOAD_OUTER_INSERT_QINQ1 SXE2_VSI_L2TAGSTXVALID_ID_OUT_VLAN2
+#define SXE2_DPDK_OFFLOAD_OUTER_INSERT_VLAN  SXE2_VSI_L2TAGSTXVALID_ID_VLAN
+
+#define SXE2_DPDK_OFFLOAD_OUTER_INSERT_ENABLE SXE2_VSI_L2TAGSTXVALID_L2TAG1_VALID
+
+#define SXE2_DPDK_OFFLOAD_OUTER_STRIP_8021Q SXE2_VSI_TSR_ID_OUT_VLAN1
+#define SXE2_DPDK_OFFLOAD_OUTER_STRIP_8021AD SXE2_VSI_TSR_ID_STAG
+#define SXE2_DPDK_OFFLOAD_OUTER_STRIP_QINQ1 SXE2_VSI_TSR_ID_OUT_VLAN2
+
+#define SXE2_DPDK_OFFLOAD_INNER_INSERT_QINQ1  SXE2_VSI_L2TAGSTXVALID_ID_VLAN
+#define SXE2_DPDK_OFFLOAD_INNER_INSERT_ENABLE SXE2_VSI_L2TAGSTXVALID_L2TAG2_VALID
+
+#define SXE2_DPDK_OFFLOAD_INNER_STRIP_QINQ1 SXE2_VSI_TSR_ID_VLAN
+
+#define SXE2_DPDK_OFFLOAD_FIELD                (0X0F)
+#define SXE2_DPDK_OFFLOAD_TAGID_FIELD          (0X07)
+
+#define SXE2_DPDK_OFFLOAD_OUTER_STRIP_MASK (SXE2_DPDK_OFFLOAD_OUTER_STRIP_8021Q | \
+					SXE2_DPDK_OFFLOAD_OUTER_STRIP_8021AD | \
+					SXE2_DPDK_OFFLOAD_OUTER_STRIP_QINQ1)
+#define SXE2_DPDK_OFFLOAD_STRIP_OFFSET SXE2_VSI_TSR_SHOW_TAG_S
+
+#define SXE2_DPDK_OFFLOAD_INSERT_ENABLE (RTE_BIT32(3))
+
+struct sxe2_mac_mc_list {
+	uint32_t count;
+	struct rte_ether_addr addr[SXE2_NUM_MACADDR_MAX];
+};
+
+int32_t sxe2_link_update_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_link_update(struct rte_eth_dev *dev, __rte_unused int32_t wait_to_complete);
+
+int32_t sxe2_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
+
+#endif /* __SXE2_MAC_H__ */
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 14/20] net/sxe2: implement get monitor address
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch implements the 'get_monitor_addr' ethdev ops in the sxe2
PMD. This interface allows the Ethernet device to provide the
address of the next expected Rx descriptor to the power management
library.

The implementation calculates the address of the next Rx descriptor
based on the receive queue's current hardware ring position and
descriptor size. Applications can then use this address with
rte_power_monitor() to put the CPU into a low-power state until
new packets are written to the descriptor by the hardware.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/net/sxe2/sxe2_ethdev.c |  2 ++
 drivers/net/sxe2/sxe2_rx.c     | 21 +++++++++++++++++++++
 drivers/net/sxe2/sxe2_rx.h     |  2 ++
 3 files changed, 25 insertions(+)

diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 74b841c2ef..d1ced7d427 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -184,6 +184,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.queue_stats_mapping_set    = sxe2_queue_stats_mapping_set,
 
 	.fw_version_get             = sxe2_fw_version_string_get,
+
+	.get_monitor_addr           = sxe2_get_monitor_addr,
 };
 
 static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
diff --git a/drivers/net/sxe2/sxe2_rx.c b/drivers/net/sxe2/sxe2_rx.c
index 007192c7d8..79e65cfbf1 100644
--- a/drivers/net/sxe2/sxe2_rx.c
+++ b/drivers/net/sxe2/sxe2_rx.c
@@ -557,3 +557,24 @@ void __rte_cold sxe2_rxqs_all_stop(struct rte_eth_dev *dev)
 		}
 	}
 }
+
+static int32_t sxe2_monitor_callback(const uint64_t value,
+				 const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused)
+{
+	const uint64_t dd_state = rte_cpu_to_le_64(SXE2_RX_DESC_STATUS_DD_MASK);
+	return (value & dd_state) == dd_state ? -1 : 0;
+}
+
+int32_t sxe2_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
+{
+	volatile union sxe2_rx_desc *rxdp;
+	struct sxe2_rx_queue *rxq = (struct sxe2_rx_queue *)rx_queue;
+
+	rxdp = &rxq->desc_ring[rxq->processing_idx];
+
+	pmc->addr = &rxdp->wb.status_err_ptype_len;
+	pmc->fn   = sxe2_monitor_callback;
+	pmc->size = sizeof(uint16_t);
+
+	return 0;
+}
diff --git a/drivers/net/sxe2/sxe2_rx.h b/drivers/net/sxe2/sxe2_rx.h
index 295d9005e0..c2582bc571 100644
--- a/drivers/net/sxe2/sxe2_rx.h
+++ b/drivers/net/sxe2/sxe2_rx.h
@@ -29,4 +29,6 @@ int32_t __rte_cold sxe2_rxqs_all_start(struct rte_eth_dev *dev);
 
 void __rte_cold sxe2_rxqs_all_stop(struct rte_eth_dev *dev);
 
+int32_t sxe2_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
+
 #endif /* SXE2_RX_H */
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 12/20] net/sxe2: add support for custom UDP tunnel ports
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch enables the configuration of custom UDP port numbers for
tunneling protocols in the SXE2 PMD.

The change includes:
- Adding a new entry in the tunnel port lookup table.
- Updating the hardware profile to recognize
  the custom UDP port as a tunnel type.
- Enabling inner header parsing for packets arriving on these ports.

This allows the Switch module to correctly apply recipes based on
inner packet fields (e.g., inner MAC or IP).

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/net/sxe2/sxe2_cmd_chnl.c           |  96 ++++++++++
 drivers/net/sxe2/sxe2_cmd_chnl.h           |  17 ++
 drivers/net/sxe2/sxe2_drv_cmd.h            |  16 ++
 drivers/net/sxe2/sxe2_ethdev.c             | 206 ++++++++++++++++++++-
 drivers/net/sxe2/sxe2_ethdev.h             |  12 ++
 drivers/net/sxe2/sxe2_flow.c               |  54 ++++++
 drivers/net/sxe2/sxe2_flow.h               |   3 +-
 drivers/net/sxe2/sxe2_flow_define.h        |   1 +
 drivers/net/sxe2/sxe2_flow_parse_pattern.c | 113 +++++++++++
 drivers/net/sxe2/sxe2_flow_parse_pattern.h |   6 +
 drivers/net/sxe2/sxe2_txrx_poll.c          |  46 ++++-
 11 files changed, 566 insertions(+), 4 deletions(-)

diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 6e2dd139a5..926eaee062 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -1455,6 +1455,102 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
 	return ret;
 }
 
+int32_t sxe2_drv_udp_tunnel_add(struct sxe2_adapter *adapter,
+			    enum sxe2_udp_tunnel_protocol tunnel_proto,
+			    uint16_t udp_port)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_udp_tunnel_req req = {};
+	struct sxe2_drv_cmd_params cmd = {};
+	int32_t ret = -1;
+
+	req.type = tunnel_proto;
+	req.port = udp_port;
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_ADD,
+				 &req, sizeof(req),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Failed to add udp proto %d port %d, ret=%d",
+				tunnel_proto, udp_port, ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_udp_tunnel_del(struct sxe2_adapter *adapter,
+			    enum sxe2_udp_tunnel_protocol tunnel_proto,
+			    uint16_t udp_port)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_udp_tunnel_req req = {};
+	struct sxe2_drv_cmd_params cmd = {};
+	int32_t ret = -1;
+
+	req.type = tunnel_proto;
+	req.port = udp_port;
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_DEL,
+				 &req, sizeof(req),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Failed to del udp proto %d port %d, ret=%d",
+				tunnel_proto, udp_port, ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_get_udp_tunnel_port(struct sxe2_adapter *adapter,
+				 enum sxe2_flow_udp_tunnel_protocol proto,
+				 uint16_t *port)
+{
+	int32_t ret = 0;
+	static const uint16_t flow_proto_to_udp_tunnel_proto[SXE2_FLOW_UDP_TUNNEL_MAX] = {
+		[SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN,
+		[SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+		[SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE] = SXE2_UDP_TUNNEL_PROTOCOL_GENEVE,
+		[SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U] = SXE2_UDP_TUNNEL_PROTOCOL_GTP_U,
+		[SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE] = SXE2_UDP_TUNNEL_PROTOCOL_NVGRE,
+	};
+	struct sxe2_udp_tunnel_cfg tunnel_config = {};
+
+	tunnel_config.protocol = flow_proto_to_udp_tunnel_proto[proto];
+	ret = sxe2_drv_udp_tunnel_get(adapter, &tunnel_config);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get udp tunnel port, ret=%d", ret);
+		goto l_end;
+	}
+
+	*port = tunnel_config.fw_port;
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_udp_tunnel_get(struct sxe2_adapter *adapter,
+			    struct sxe2_udp_tunnel_cfg *tunnel_config)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_udp_tunnel_req req = {};
+	struct sxe2_drv_udp_tunnel_resp resp = {};
+	struct sxe2_drv_cmd_params cmd = {};
+	int32_t ret = -1;
+
+	req.type = tunnel_config->protocol;
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_GET,
+				 &req, sizeof(req),
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Failed to get udp proto %d port, ret=%d", req.type, ret);
+
+	tunnel_config->fw_port   = resp.port;
+	tunnel_config->fw_status = resp.enable;
+	tunnel_config->fw_dst_en = resp.dst;
+	tunnel_config->fw_src_en = resp.src;
+	tunnel_config->fw_used   = resp.fw_used;
+
+	return ret;
+}
+
 int32_t sxe2_drv_queue_info_get_update(struct sxe2_adapter *adapter, struct eth_queue_stats *qstats)
 {
 	struct sxe2_drv_cmd_params param = {0};
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 52cd9922ad..97007c7cfa 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -67,6 +67,23 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
 
 int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
 
+int32_t sxe2_drv_udp_tunnel_add(struct sxe2_adapter *adapter,
+			    enum sxe2_udp_tunnel_protocol tunnel_proto,
+			    uint16_t udp_port);
+
+int32_t sxe2_drv_udp_tunnel_del(struct sxe2_adapter *adapter,
+			    enum sxe2_udp_tunnel_protocol tunnel_proto,
+			    uint16_t udp_port);
+
+int32_t sxe2_drv_udp_tunnel_get(struct sxe2_adapter *adapter,
+			    struct sxe2_udp_tunnel_cfg *tunnel_config);
+
+int32_t sxe2_drv_get_udp_tunnel_port(struct sxe2_adapter *adapter,
+				 enum sxe2_flow_udp_tunnel_protocol proto,
+				 uint16_t *port);
+
+int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi);
+
 int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi);
 
 int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 38eb2d5cac..f7acd20642 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -617,6 +617,22 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_query_stat_resp {
 	uint64_t stat_bytes;
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_udp_tunnel_req {
+	uint8_t type;
+	uint8_t rsv;
+	uint16_t port;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_udp_tunnel_resp {
+	uint8_t type;
+	uint8_t enable;
+	uint8_t dst;
+	uint8_t src;
+	uint16_t port;
+	uint8_t fw_used;
+	uint8_t rsv;
+} __rte_packed_end;
+
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
 	SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 24ac6b6038..58b56428f9 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -40,10 +40,11 @@
 #include "sxe2_ioctl_chnl_func.h"
 #include "sxe2_ethdev_repr.h"
 #include "sxe2vf_regs.h"
+#include "sxe2_switchdev.h"
 
 #define SXE2_PCI_VENDOR_ID_1    0x1ff2
 #define SXE2_PCI_DEVICE_ID_PF_1 0x10b1
-#define SXE2_PCI_DEVICE_ID_VF_1 0x10b2
+#define SXE2_PCI_DEVICE_ID_VF_1 0x10b
 
 #define SXE2_PCI_VENDOR_ID_2    0x1d94
 #define SXE2_PCI_DEVICE_ID_PF_2 0x1260
@@ -115,6 +116,11 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev);
 static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info);
 static const uint32_t *sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev
 				__rte_unused, size_t *no_of_elements __rte_unused);
+static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
+					struct rte_eth_udp_tunnel *tunnel_udp);
+static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
+					struct rte_eth_udp_tunnel *tunnel_udp);
+
 
 static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.dev_configure              = sxe2_dev_configure,
@@ -162,6 +168,9 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.rss_hash_update            = sxe2_dev_rss_hash_update,
 	.rss_hash_conf_get          = sxe2_dev_rss_hash_conf_get,
 
+	.udp_tunnel_port_add        = sxe2_udp_tunnel_port_add,
+	.udp_tunnel_port_del        = sxe2_udp_tunnel_port_del,
+
 	.flow_ops_get               = sxe2_flow_ops_get,
 	.tm_ops_get                 = sxe2_tm_ops_get,
 
@@ -226,6 +235,12 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
 	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
 	PMD_INIT_FUNC_TRACE();
 
+	ret = sxe2_flow_init_udp_tunnel_port(dev);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", ret);
+		goto l_end;
+	}
+
 	ret = sxe2_queues_init(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "Failed to init queues.");
@@ -271,6 +286,188 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
 	return ret;
 }
 
+static enum sxe2_udp_tunnel_protocol
+sxe2_udp_tunnel_type_rte_to_sxe2(enum rte_eth_tunnel_type rte_type)
+{
+	static enum sxe2_udp_tunnel_protocol sxe2_udp_proto_map[RTE_ETH_TUNNEL_TYPE_MAX] = {
+		[RTE_ETH_TUNNEL_TYPE_NONE] = SXE2_UDP_TUNNEL_MAX,
+		[RTE_ETH_TUNNEL_TYPE_VXLAN] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN,
+		[RTE_ETH_TUNNEL_TYPE_GENEVE] = SXE2_UDP_TUNNEL_PROTOCOL_GENEVE,
+		[RTE_ETH_TUNNEL_TYPE_TEREDO] = SXE2_UDP_TUNNEL_PROTOCOL_TEREDO,
+		[RTE_ETH_TUNNEL_TYPE_NVGRE] = SXE2_UDP_TUNNEL_PROTOCOL_NVGRE,
+		[RTE_ETH_TUNNEL_TYPE_IP_IN_GRE] = SXE2_UDP_TUNNEL_MAX,
+		[RTE_ETH_L2_TUNNEL_TYPE_E_TAG] = SXE2_UDP_TUNNEL_MAX,
+		[RTE_ETH_TUNNEL_TYPE_VXLAN_GPE] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+		[RTE_ETH_TUNNEL_TYPE_ECPRI]  = SXE2_UDP_TUNNEL_PROTOCOL_ECPRI
+	};
+
+	if (rte_type >= RTE_ETH_TUNNEL_TYPE_MAX) {
+		PMD_LOG_ERR(DRV, "Invalid rte_eth_tunnel_type %d!", rte_type);
+		rte_type = RTE_ETH_TUNNEL_TYPE_NONE;
+	}
+
+	return sxe2_udp_proto_map[rte_type];
+}
+
+int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad,
+				    enum sxe2_udp_tunnel_protocol tunnel_proto,
+				    uint16_t udp_port)
+{
+	struct sxe2_udp_tunnel_cfg *tunnel_config;
+	int32_t ret = -1;
+
+	rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+
+	tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+
+	if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) {
+		if (udp_port == tunnel_config->dev_port &&
+			tunnel_config->dev_ref_cnt < 0xFFFFU) {
+			tunnel_config->dev_ref_cnt++;
+			ret = 0;
+			goto l_unlock_end;
+		} else {
+			PMD_LOG_ERR(DRV, "Adding multiple ports to the same protocol "
+				    "is not supported!");
+			ret = -EINVAL;
+			goto l_unlock_end;
+		}
+	} else {
+		ret = sxe2_drv_udp_tunnel_add(ad, tunnel_proto, udp_port);
+		if (ret != 0)
+			goto l_unlock_end;
+
+		tunnel_config->protocol = tunnel_proto;
+		tunnel_config->dev_port = udp_port;
+		tunnel_config->dev_status  = SXE2_UDP_TUNNEL_ENABLE;
+		tunnel_config->dev_ref_cnt++;
+	}
+
+l_unlock_end:
+	rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+	return ret;
+}
+
+int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad,
+				    enum sxe2_udp_tunnel_protocol tunnel_proto,
+				    uint16_t udp_port)
+{
+	struct sxe2_udp_tunnel_cfg *tunnel_config;
+	int32_t ret = -1;
+
+	rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+	tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+
+	if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE &&
+		udp_port == tunnel_config->dev_port) {
+		if (tunnel_config->dev_ref_cnt > 1) {
+			tunnel_config->dev_ref_cnt--;
+			ret = 0;
+			goto l_unlock_end;
+		} else {
+			ret = sxe2_drv_udp_tunnel_del(ad, tunnel_proto, udp_port);
+			if (ret != 0)
+				goto l_unlock_end;
+
+			tunnel_config->dev_status  = SXE2_UDP_TUNNEL_DISABLE;
+			tunnel_config->dev_ref_cnt = 0;
+		}
+		goto l_unlock_end;
+	}
+
+	ret = -EINVAL;
+
+l_unlock_end:
+	rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+	return ret;
+}
+
+int32_t sxe2_udp_tunnel_port_get_common(struct sxe2_adapter *ad,
+				    struct sxe2_udp_tunnel_cfg *tunnel_config)
+{
+	return sxe2_drv_udp_tunnel_get(ad, tunnel_config);
+}
+
+static int32_t sxe2_udp_tunnel_port_clear(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_udp_tunnel_cfg *tunnel_config;
+	int32_t ret = 0;
+	uint16_t tunnel_proto = 0;
+
+	rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+
+	for (tunnel_proto = 0; tunnel_proto < SXE2_UDP_TUNNEL_MAX; tunnel_proto++) {
+		tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+		if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) {
+			ret = sxe2_drv_udp_tunnel_del(ad, tunnel_config->protocol,
+					tunnel_config->dev_port);
+			if (ret) {
+				PMD_LOG_ERR(DRV, "Failed to delete udp tunnel port %d, proto %d",
+					    tunnel_config->dev_port, tunnel_config->protocol);
+				goto l_unlock_end;
+			}
+
+			tunnel_config->dev_status  = SXE2_UDP_TUNNEL_DISABLE;
+			tunnel_config->dev_ref_cnt = 0;
+		}
+	}
+l_unlock_end:
+	rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+	return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
+			struct rte_eth_udp_tunnel *tunnel_udp)
+{
+	int32_t ret = 0;
+	enum sxe2_udp_tunnel_protocol tunnel_proto;
+	struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (tunnel_udp->udp_port == 0) {
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type);
+	if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) {
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_udp_tunnel_port_add_common(ad, tunnel_proto, tunnel_udp->udp_port);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Add tunnel port failed, ret = %d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
+			struct rte_eth_udp_tunnel *tunnel_udp)
+{
+	int32_t ret = 0;
+	enum sxe2_udp_tunnel_protocol tunnel_proto;
+	struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type);
+	if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) {
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_udp_tunnel_port_del_common(ad, tunnel_proto, tunnel_udp->udp_port);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Delete tunnel port failed, ret = %d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
 static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
 			struct rte_eth_dev_info *dev_info)
 {
@@ -1300,15 +1497,20 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 	(void)sxe2_dev_stop(dev);
 	(void)sxe2_queues_release(dev);
 	sxe2_mp_uninit(dev);
-	(void)sxe2_rss_disable(dev);
 	(void)sxe2_sched_uinit(dev);
+	(void)sxe2_rss_disable(dev);
+	(void)sxe2_flow_uninit(dev);
+	(void)sxe2_udp_tunnel_port_clear(dev);
 	sxe2_vsi_uninit(dev);
 	sxe2_security_uinit(dev);
 	sxe2_intr_uninit(dev);
 	(void)sxe2_switchdev_uninit(dev);
 	sxe2_sw_uninit(dev);
+	(void)sxe2_switchdev_uninit(dev);
+	sxe2_dev_pci_map_uinit(dev);
 	sxe2_eth_uinit(dev);
 	sxe2_dev_pci_map_uinit(dev);
+	sxe2_free_repr_info(dev);
 
 l_end:
 	return 0;
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 756924ca0a..34f9aa46b2 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -319,6 +319,7 @@ struct sxe2_adapter {
 	struct sxe2_sched_hw_cap      sched_ctxt;
 	struct sxe2_tm_context        tm_ctxt;
 	struct sxe2_devargs           devargs;
+	struct sxe2_udp_tunnel_ctx    udp_tunnel_ctx;
 	struct sxe2_security_ctx      security_ctx;
 	struct sxe2_repr_context      repr_ctxt;
 	struct sxe2_switchdev_info    switchdev_info;
@@ -371,6 +372,17 @@ void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
 
 int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
 
+void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
+
+int32_t sxe2_udp_tunnel_port_get_common(struct sxe2_adapter *ad,
+		struct sxe2_udp_tunnel_cfg *tunnel_config);
+
+int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad,
+		enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port);
+
+int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad,
+		enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port);
+
 void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
 
 void sxe2_eth_uinit(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_flow.c b/drivers/net/sxe2/sxe2_flow.c
index 6999cb0725..63cfc36968 100644
--- a/drivers/net/sxe2/sxe2_flow.c
+++ b/drivers/net/sxe2/sxe2_flow.c
@@ -523,6 +523,51 @@ static int32_t sxe2_flow_adjust_action(struct rte_eth_dev *dev __rte_unused,
 	return ret;
 }
 
+int32_t sxe2_flow_init_udp_tunnel_port(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+	uint16_t i = 0;
+	uint16_t *flow_udp_tunnel_port = NULL;
+
+	memset(adapter->flow_ctxt.tunnel_port_list, 0,
+	       sizeof(adapter->flow_ctxt.tunnel_port_list));
+
+	flow_udp_tunnel_port = adapter->flow_ctxt.tunnel_port_list;
+	for (i = 0; i < SXE2_FLOW_UDP_TUNNEL_MAX; i++) {
+		if (flow_udp_tunnel_port[i] == 0) {
+			ret = sxe2_drv_get_udp_tunnel_port(adapter, i,
+							   &flow_udp_tunnel_port[i]);
+			if (ret != 0) {
+				PMD_LOG_ERR(DRV, "Failed to get udp tunnel port, proto: %d,"
+					    "ret: %d", i, ret);
+				goto l_end;
+			}
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flowlist_add_tunnel_port(struct rte_eth_dev *dev,
+			struct rte_flow *flow_list,
+			struct rte_flow_error *error)
+{
+	struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+	struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+	enum sxe2_flow_tunnel_type tunnel_type = flow->meta.tunnel_type;
+	DECLARE_BITMAP(flow_type, SXE2_EXPANSION_MAX);
+	sxe2_bitmap_zero(flow_type, SXE2_EXPANSION_MAX);
+	sxe2_bitmap_copy(flow_type, flow->flow_type, SXE2_EXPANSION_MAX);
+	int32_t ret = 0;
+
+	if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV)
+		return sxe2_flow_add_tunnel_port(dev, error, flow, flow_type, tunnel_type);
+
+	return ret;
+}
+
 static int32_t sxe2_flow_check_item_empty(uint8_t *item, uint16_t size)
 {
 	uint16_t i = 0;
@@ -679,6 +724,10 @@ static int32_t sxe2_flow_post_proc(struct rte_eth_dev *dev,
 {
 	int32_t ret = 0;
 
+	ret = sxe2_flowlist_add_tunnel_port(dev, flow_list, error);
+	if (ret)
+		goto l_end;
+
 	ret = sxe2_flowlist_add_proto_type(dev, flow_list, error);
 	if (ret)
 		goto l_end;
@@ -1308,6 +1357,11 @@ int32_t sxe2_flow_init(struct rte_eth_dev *dev)
 
 	adapter->flow_ctxt.fnav_inited = 1;
 	rte_spinlock_init(&adapter->flow_ctxt.flow_list_lock);
+
+	ret = sxe2_flow_init_udp_tunnel_port(dev);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", ret);
+
 	return ret;
 }
 
diff --git a/drivers/net/sxe2/sxe2_flow.h b/drivers/net/sxe2/sxe2_flow.h
index 9970fddcf0..daaeedd4dc 100644
--- a/drivers/net/sxe2/sxe2_flow.h
+++ b/drivers/net/sxe2/sxe2_flow.h
@@ -8,7 +8,6 @@
 #include "sxe2_osal.h"
 #include "sxe2_common.h"
 
-
 int32_t sxe2_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops);
 
 int32_t sxe2_flow_init(struct rte_eth_dev *dev);
@@ -26,4 +25,6 @@ int32_t sxe2_flow_query_mgr(struct sxe2_adapter *adapter,
 			struct sxe2_flow *flow,
 			struct sxe2_fnav_cid_mgr **mgr_ptr,
 			struct rte_flow_error *error);
+
+int32_t sxe2_flow_init_udp_tunnel_port(struct rte_eth_dev *dev);
 #endif /* __SXE2_FLOW_H__ */
diff --git a/drivers/net/sxe2/sxe2_flow_define.h b/drivers/net/sxe2/sxe2_flow_define.h
index d2f6000efa..263a573f04 100644
--- a/drivers/net/sxe2/sxe2_flow_define.h
+++ b/drivers/net/sxe2/sxe2_flow_define.h
@@ -119,6 +119,7 @@ struct sxe2_flow_context {
 	struct rte_flow_list_t rte_flow_list;
 	rte_spinlock_t flow_list_lock;
 	struct sxe2_fnav_count_resource hw_res;
+	uint16_t tunnel_port_list[SXE2_FLOW_UDP_TUNNEL_MAX];
 	uint32_t fnav_inited;
 };
 #define SXE2_INVALID_RSS_ATTR	\
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.c b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
index 189abb1a33..f5bf8922c6 100644
--- a/drivers/net/sxe2/sxe2_flow_parse_pattern.c
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
@@ -1637,6 +1637,119 @@ static int32_t sxe2_flow_parse_pattern_vxlan_gpe(const struct rte_flow_item *ite
 	return ret;
 }
 
+static int32_t sxe2_flow_parse_pattern_ipip(struct sxe2_flow *flow, BITMAP_TYPE *flow_type)
+{
+	sxe2_set_bit(SXE2_EXPANSION_IPIP, flow_type);
+	if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow_type)) {
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, flow->pattern_outer.map_spec);
+		if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type))
+			flow->pattern_outer.item_spec.ipv4.protocol = SXE2_FLOW_IP_PROTOCOL_IPV4;
+		if (sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type))
+			flow->pattern_outer.item_spec.ipv4.protocol = SXE2_FLOW_IP_PROTOCOL_IPV6;
+	}
+	if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow_type)) {
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, flow->pattern_outer.map_spec);
+		if (sxe2_test_bit(SXE2_EXPANSION_ETH, flow_type)) {
+			flow->pattern_outer.item_spec.ipv6.nexthdr = SXE2_FLOW_IP_PROTOCOL_ETH;
+		} else {
+			if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type))
+				flow->pattern_outer.item_spec.ipv6.nexthdr =
+					SXE2_FLOW_IP_PROTOCOL_IPV4;
+			if (sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type))
+				flow->pattern_outer.item_spec.ipv6.nexthdr =
+					SXE2_FLOW_IP_PROTOCOL_IPV6;
+		}
+	}
+	return 0;
+}
+
+static int32_t sxe2_flow_add_udp_tunnel_port(struct sxe2_adapter *adapter,
+					 enum sxe2_flow_udp_tunnel_protocol proto,
+					 struct sxe2_flow *flow,
+					 BITMAP_TYPE *flow_type)
+{
+	int32_t ret = 0;
+	uint16_t tun_port;
+
+	tun_port = adapter->flow_ctxt.tunnel_port_list[proto];
+	if (tun_port == 0xffff || tun_port == 0) {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "UDP tunnel port not initialized, proto: %d", proto);
+		goto l_end;
+	}
+	if (!sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type)) {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "UDP must be over tunnel");
+		goto l_end;
+	}
+	sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, flow->pattern_outer.map_spec);
+	flow->pattern_outer.item_spec.udp.dest = rte_cpu_to_be_16(tun_port);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_flow_add_tunnel_port(struct rte_eth_dev *dev,
+			struct rte_flow_error *error,
+			struct sxe2_flow *flow, BITMAP_TYPE *flow_type,
+			enum sxe2_flow_tunnel_type tunnel_type)
+{
+	int32_t ret = 0;
+	enum sxe2_flow_udp_tunnel_protocol proto = SXE2_FLOW_UDP_TUNNEL_MAX;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_flow_pattern *pattern = &flow->pattern_outer;
+	switch (tunnel_type) {
+	case SXE2_FLOW_TUNNEL_TYPE_VXLAN:
+		if (sxe2_test_bit(SXE2_EXPANSION_ETH, flow_type)) {
+			proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN;
+		} else if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type) ||
+			sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type)) {
+			proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE;
+		}
+		break;
+	case SXE2_FLOW_TUNNEL_TYPE_GTPU:
+		proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U;
+		break;
+	case SXE2_FLOW_TUNNEL_TYPE_GENEVE:
+		proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE;
+		break;
+	case SXE2_FLOW_TUNNEL_TYPE_GRE:
+		if (sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type)) {
+			proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE;
+		} else {
+			if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow_type)) {
+				pattern->item_spec.ipv4.protocol = SXE2_FLOW_IP_PROTOCOL_GRE;
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_spec);
+			}
+			if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow_type)) {
+				pattern->item_spec.ipv6.nexthdr = SXE2_FLOW_IP_PROTOCOL_GRE;
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, pattern->map_spec);
+			}
+		}
+		break;
+	case SXE2_FLOW_TUNNEL_TYPE_IPIP:
+		ret = sxe2_flow_parse_pattern_ipip(flow, flow_type);
+		break;
+	default:
+		break;
+	}
+	if (proto != SXE2_FLOW_UDP_TUNNEL_MAX) {
+		ret = sxe2_flow_add_udp_tunnel_port(adapter, proto, flow, flow_type);
+		if (ret != 0) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					NULL, "Failed to add udp port for tunnel.");
+			PMD_LOG_ERR(DRV, "Failed to add udp port for tunnel, ret %d.", ret);
+			goto l_end;
+		}
+	}
+	if (tunnel_type != SXE2_FLOW_TUNNEL_TYPE_NONE) {
+		if (!sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type))
+			sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, pattern->hdrs);
+	}
+l_end:
+	return ret;
+}
+
 struct sxe2_flow_parse_pattern_ops sxe2_flow_parse_pattern_list[] = {
 	[SXE2_EXPANSION_OUTER_ETH] = {
 		.is_inner = false,
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.h b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
index 69d83a6ea6..8442c35cae 100644
--- a/drivers/net/sxe2/sxe2_flow_parse_pattern.h
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
@@ -37,4 +37,10 @@ int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev,
 			    struct rte_flow_error *error,
 			    struct sxe2_flow *flow);
 
+int32_t sxe2_flow_add_tunnel_port(struct rte_eth_dev *dev,
+			      struct rte_flow_error *error,
+			      struct sxe2_flow *flow,
+			      BITMAP_TYPE *flow_type,
+			      enum sxe2_flow_tunnel_type tunnel_type);
+
 #endif /* SXE2_FLOW_PARSE_PATTERN_H_ */
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index f3c4fa0d91..746f9cc2d5 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -234,6 +234,44 @@ sxe2_tx_pkt_data_desc_count(struct rte_mbuf *tx_pkt)
 	return count;
 }
 
+static __rte_always_inline void sxe2_tx_desc_tunneling_params_fill(uint64_t offloads,
+					union sxe2_tx_offload_info ol_info,
+					uint32_t *desc_tunneling_params)
+{
+	if (offloads & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+		*desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV4;
+	else if (offloads & RTE_MBUF_F_TX_OUTER_IPV4)
+		*desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV4_NO_CSUM;
+	else if (offloads & RTE_MBUF_F_TX_OUTER_IPV6)
+		*desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV6;
+
+	*desc_tunneling_params |=
+			SXE2_TX_CTXT_DESC_EIPLEN_VAL(ol_info.outer_l3_len);
+	switch (offloads & RTE_MBUF_F_TX_TUNNEL_MASK) {
+	case RTE_MBUF_F_TX_TUNNEL_IPIP:
+		break;
+	case RTE_MBUF_F_TX_TUNNEL_VXLAN:
+	case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+	case RTE_MBUF_F_TX_TUNNEL_GTP:
+	case RTE_MBUF_F_TX_TUNNEL_GENEVE:
+		*desc_tunneling_params |= SXE2_TX_CTXT_DESC_UDP_TUNNE;
+		break;
+	case RTE_MBUF_F_TX_TUNNEL_GRE:
+		*desc_tunneling_params |= SXE2_TX_CTXT_DESC_GRE_TUNNE;
+		break;
+	default:
+		PMD_LOG_ERR(TX, "Tunnel type [0x%" PRIx64 "] is not supported.",
+			    (uint64_t)(offloads & RTE_MBUF_F_TX_TUNNEL_MASK));
+		return;
+	}
+	*desc_tunneling_params |= SXE2_TX_CTXT_DESC_NATLEN_VAL(ol_info.l2_len);
+	if (!(*desc_tunneling_params & SXE2_TX_CTXT_DESC_EIPT_NONE) &&
+			(*desc_tunneling_params & SXE2_TX_CTXT_DESC_UDP_TUNNE) &&
+			(offloads & RTE_MBUF_F_TX_OUTER_UDP_CKSUM)) {
+		*desc_tunneling_params |= SXE2_TX_CTXT_DESC_L4T_CS_MASK;
+	}
+}
+
 static __rte_always_inline void
 sxe2_tx_desc_checksum_fill(uint64_t offloads, uint32_t *desc_cmd, uint32_t *desc_offset,
 		union sxe2_tx_offload_info ol_info)
@@ -414,7 +452,13 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
 			}
 		}
 
-		desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.l2_len);
+		if ((offloads & RTE_MBUF_F_TX_TUNNEL_MASK) && ctxt_desc_num) {
+			desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.outer_l2_len);
+			sxe2_tx_desc_tunneling_params_fill(offloads, ol_info,
+						&desc_tunneling_params);
+		} else {
+			desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.l2_len);
+		}
 
 		if (offloads & SXE2_TX_OFFLOAD_CKSUM_MASK) {
 			sxe2_tx_desc_checksum_fill(offloads, &desc_cmd,
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 08/20] net/sxe2: support statistics and multi-process
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

- The statistics support includes:
- Basic statistics (ipackets, opackets, ibytes, obytes, etc.)
- Extended statistics (xstats) for detailed hardware counters.
- Per-queue statistics for both RX and TX.

The multi-process support allows secondary processes to retrieve
statistics. Since secondary processes cannot access hardware registers
directly, an IPC mechanism is implemented using the DPDK MP API.

Atomic operations are used when reading 64-bit counters to ensure
data consistency between processes.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/net/sxe2/meson.build     |   2 +
 drivers/net/sxe2/sxe2_cmd_chnl.c | 340 +++++++++++++++++-
 drivers/net/sxe2/sxe2_cmd_chnl.h |  23 ++
 drivers/net/sxe2/sxe2_drv_cmd.h  | 120 +++++++
 drivers/net/sxe2/sxe2_ethdev.c   |  38 +-
 drivers/net/sxe2/sxe2_mp.c       | 414 ++++++++++++++++++++++
 drivers/net/sxe2/sxe2_mp.h       |  67 ++++
 drivers/net/sxe2/sxe2_stats.c    | 586 +++++++++++++++++++++++++++++++
 drivers/net/sxe2/sxe2_stats.h    |  39 ++
 9 files changed, 1616 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/sxe2/sxe2_mp.c
 create mode 100644 drivers/net/sxe2/sxe2_mp.h
 create mode 100644 drivers/net/sxe2/sxe2_stats.c
 create mode 100644 drivers/net/sxe2/sxe2_stats.h

diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 86973edc99..8c8f16863e 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -66,4 +66,6 @@ sources += files(
         'sxe2_tm.c',
         'sxe2_ipsec.c',
         'sxe2_security.c',
+        'sxe2_mp.c',
+        'sxe2_stats.c',
 )
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 7711e8e57d..a1fc8a50e3 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -348,6 +348,184 @@ int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+int32_t sxe2_drv_get_mac_stats(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	uint8_t i = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_vsi *vsi = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_stats *stats = &vsi->vsi_stats.vsi_hw_stats;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_mac_stats_resp resp = {0};
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_MAC_STATS_GET,
+				 NULL, 0,
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "vsi stats get failed, ret=%d", ret);
+		goto l_end;
+	}
+
+	stats->rx_out_of_buffer        = rte_le_to_cpu_64(resp.rx_out_of_buffer);
+	stats->rx_qblock_drop          = rte_le_to_cpu_64(resp.rx_qblock_drop);
+	stats->tx_frame_good           = rte_le_to_cpu_64(resp.tx_frame_good);
+	stats->rx_frame_good           = rte_le_to_cpu_64(resp.rx_frame_good);
+	stats->rx_crc_errors           = rte_le_to_cpu_64(resp.rx_crc_errors);
+	stats->tx_bytes_good           = rte_le_to_cpu_64(resp.tx_bytes_good);
+	stats->rx_bytes_good           = rte_le_to_cpu_64(resp.rx_bytes_good);
+	stats->tx_multicast_good       = rte_le_to_cpu_64(resp.tx_multicast_good);
+	stats->tx_broadcast_good       = rte_le_to_cpu_64(resp.tx_broadcast_good);
+	stats->rx_multicast_good       = rte_le_to_cpu_64(resp.rx_multicast_good);
+	stats->rx_broadcast_good       = rte_le_to_cpu_64(resp.rx_broadcast_good);
+	stats->rx_len_errors           = rte_le_to_cpu_64(resp.rx_len_errors);
+	stats->rx_out_of_range_errors  = rte_le_to_cpu_64(resp.rx_out_of_range_errors);
+	stats->rx_oversize_pkts_phy    = rte_le_to_cpu_64(resp.rx_oversize_pkts_phy);
+	stats->rx_symbol_err	       = rte_le_to_cpu_64(resp.rx_symbol_err);
+	stats->rx_pause_frame	       = rte_le_to_cpu_64(resp.rx_pause_frame);
+	stats->tx_pause_frame	       = rte_le_to_cpu_64(resp.tx_pause_frame);
+	stats->rx_discards_phy	       = rte_le_to_cpu_64(resp.rx_discards_phy);
+	stats->rx_discards_ips_phy     = rte_le_to_cpu_64(resp.rx_discards_ips_phy);
+	stats->tx_dropped_link_down    = rte_le_to_cpu_64(resp.tx_dropped_link_down);
+	stats->rx_undersize_good       = rte_le_to_cpu_64(resp.rx_undersize_good);
+	stats->rx_runt_error	       = rte_le_to_cpu_64(resp.rx_runt_error);
+	stats->tx_bytes_good_bad       = rte_le_to_cpu_64(resp.tx_bytes_good_bad);
+	stats->tx_frame_good_bad       = rte_le_to_cpu_64(resp.tx_frame_good_bad);
+	stats->rx_jabbers              = rte_le_to_cpu_64(resp.rx_jabbers);
+	stats->rx_size_64              = rte_le_to_cpu_64(resp.rx_size_64);
+	stats->rx_size_65_127          = rte_le_to_cpu_64(resp.rx_size_65_127);
+	stats->rx_size_128_255         = rte_le_to_cpu_64(resp.rx_size_128_255);
+	stats->rx_size_256_511         = rte_le_to_cpu_64(resp.rx_size_256_511);
+	stats->rx_size_512_1023        = rte_le_to_cpu_64(resp.rx_size_512_1023);
+	stats->rx_size_1024_1522       = rte_le_to_cpu_64(resp.rx_size_1024_1522);
+	stats->rx_size_1523_max        = rte_le_to_cpu_64(resp.rx_size_1523_max);
+	stats->rx_pcs_symbol_err_phy   = rte_le_to_cpu_64(resp.rx_pcs_symbol_err_phy);
+	stats->rx_corrected_bits_phy   = rte_le_to_cpu_64(resp.rx_corrected_bits_phy);
+	stats->rx_err_lane_0_phy       = rte_le_to_cpu_64(resp.rx_err_lane_0_phy);
+	stats->rx_err_lane_1_phy       = rte_le_to_cpu_64(resp.rx_err_lane_1_phy);
+	stats->rx_err_lane_2_phy       = rte_le_to_cpu_64(resp.rx_err_lane_2_phy);
+	stats->rx_err_lane_3_phy       = rte_le_to_cpu_64(resp.rx_err_lane_3_phy);
+	stats->rx_illegal_bytes        = rte_le_to_cpu_64(resp.rx_illegal_bytes);
+	stats->rx_oversize_good        = rte_le_to_cpu_64(resp.rx_oversize_good);
+	stats->tx_unicast              = rte_le_to_cpu_64(resp.tx_unicast);
+	stats->tx_broadcast            = rte_le_to_cpu_64(resp.tx_broadcast);
+	stats->tx_multicast            = rte_le_to_cpu_64(resp.tx_multicast);
+	stats->tx_vlan_packet_good     = rte_le_to_cpu_64(resp.tx_vlan_packet_good);
+	stats->tx_size_64              = rte_le_to_cpu_64(resp.tx_size_64);
+	stats->tx_size_65_127          = rte_le_to_cpu_64(resp.tx_size_65_127);
+	stats->tx_size_128_255         = rte_le_to_cpu_64(resp.tx_size_128_255);
+	stats->tx_size_256_511         = rte_le_to_cpu_64(resp.tx_size_256_511);
+	stats->tx_size_512_1023        = rte_le_to_cpu_64(resp.tx_size_512_1023);
+	stats->tx_size_1024_1522       = rte_le_to_cpu_64(resp.tx_size_1024_1522);
+	stats->tx_size_1523_max        = rte_le_to_cpu_64(resp.tx_size_1523_max);
+	stats->tx_underflow_error      = rte_le_to_cpu_64(resp.tx_underflow_error);
+	stats->rx_byte_good_bad        = rte_le_to_cpu_64(resp.rx_byte_good_bad);
+	stats->rx_frame_good_bad       = rte_le_to_cpu_64(resp.rx_frame_good_bad);
+	stats->rx_unicast_good         = rte_le_to_cpu_64(resp.rx_unicast_good);
+	stats->rx_vlan_packets         = rte_le_to_cpu_64(resp.rx_vlan_packets);
+
+	for (i = 0; i < SXE2_MAX_USER_PRIORITY; i++) {
+		stats->rx_prio_buf_discard[i]  =
+			rte_le_to_cpu_64(resp.rx_prio_buf_discard[i]);
+		stats->prio_xoff_rx[i]  =
+			rte_le_to_cpu_64(resp.prio_xoff_rx[i]);
+		stats->prio_xoff_tx[i]  =
+			rte_le_to_cpu_64(resp.prio_xoff_tx[i]);
+		stats->prio_xon_rx[i]  =
+			rte_le_to_cpu_64(resp.prio_xon_rx[i]);
+		stats->prio_xon_tx[i]  =
+			rte_le_to_cpu_64(resp.prio_xon_tx[i]);
+		stats->prio_xon_2_xoff[i]  =
+			rte_le_to_cpu_64(resp.prio_xon_2_xoff[i]);
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_mac_stats_reset(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_MAC_STATS_CLEAR,
+				 NULL, 0,
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "mac stats reset failed, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_get_vsi_stats(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_vsi *vsi = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_stats *new_stats = &vsi->vsi_stats.vsi_hw_stats;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_vsi_stats_req req = {0};
+	struct sxe2_drv_vsi_stats_resp resp = {0};
+
+	req.vsi_id = rte_cpu_to_le_16(vsi->vsi_id);
+	req.sw_stats.rx_bytes = rte_cpu_to_le_64(vsi->vsi_stats.stats.ibytes);
+	req.sw_stats.rx_packets = rte_cpu_to_le_64(vsi->vsi_stats.stats.ipackets);
+	req.sw_stats.tx_bytes = rte_cpu_to_le_64(vsi->vsi_stats.stats.obytes);
+	req.sw_stats.tx_packets = rte_cpu_to_le_64(vsi->vsi_stats.stats.opackets);
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_VSI_STATS_GET,
+				 &req, sizeof(req),
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "vsi stats get failed, ret=%d", ret);
+		goto l_end;
+	}
+
+	new_stats->rx_vsi_unicast_packets   = rte_le_to_cpu_64(resp.rx_vsi_unicast_packets);
+	new_stats->rx_vsi_bytes             = rte_le_to_cpu_64(resp.rx_vsi_bytes);
+	new_stats->tx_vsi_unicast_packets   = rte_le_to_cpu_64(resp.tx_vsi_unicast_packets);
+	new_stats->tx_vsi_bytes             = rte_le_to_cpu_64(resp.tx_vsi_bytes);
+	new_stats->rx_vsi_multicast_packets = rte_le_to_cpu_64(resp.rx_vsi_multicast_packets);
+	new_stats->tx_vsi_multicast_packets = rte_le_to_cpu_64(resp.tx_vsi_multicast_packets);
+	new_stats->rx_vsi_broadcast_packets = rte_le_to_cpu_64(resp.rx_vsi_broadcast_packets);
+	new_stats->tx_vsi_broadcast_packets = rte_le_to_cpu_64(resp.tx_vsi_broadcast_packets);
+	new_stats->opackets = new_stats->tx_vsi_unicast_packets +
+			      new_stats->tx_vsi_multicast_packets +
+			      new_stats->tx_vsi_broadcast_packets;
+	new_stats->obytes = new_stats->tx_vsi_bytes;
+	new_stats->ipackets = new_stats->rx_vsi_unicast_packets +
+			      new_stats->rx_vsi_multicast_packets +
+			      new_stats->rx_vsi_broadcast_packets;
+	new_stats->ibytes = new_stats->rx_vsi_bytes;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_vsi_stats_reset(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_VSI_STATS_CLEAR,
+				 NULL, 0, NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "vsi stats reset failed, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
 int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set)
 {
 	int32_t ret = 0;
@@ -409,8 +587,9 @@ int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *
 	mac_filter_cfg_req.type = SXE2_MAC_FILTER_TYPE_UC;
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_MAC_ADDR_UC,
-		 &mac_filter_cfg_req, sizeof(mac_filter_cfg_req),
-		 NULL, 0);
+				 &mac_filter_cfg_req,
+				 sizeof(mac_filter_cfg_req),
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret)
@@ -435,8 +614,8 @@ int32_t sxe2_drv_mc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *
 	mac_filter_cfg_req.type = SXE2_MAC_FILTER_TYPE_MC;
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_MAC_ADDR_MC,
-		 &mac_filter_cfg_req, sizeof(mac_filter_cfg_req),
-		 NULL, 0);
+				  &mac_filter_cfg_req, sizeof(mac_filter_cfg_req),
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret)
@@ -455,7 +634,7 @@ int32_t sxe2_drv_vlan_config_query(struct sxe2_adapter *adapter)
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_VLAN_CFG_QUERY,
 				 NULL, 0,
 				 &vlan_cfg_query_resp,
-	 sizeof(vlan_cfg_query_resp));
+				 sizeof(vlan_cfg_query_resp));
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret)
@@ -566,7 +745,8 @@ int32_t sxe2_drv_rss_key_set(struct sxe2_adapter *adapter, uint8_t *key, uint16_
 	rte_memcpy(req->key, key, key_size);
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_KEY_SET,
-		req, buf_size, NULL, 0);
+				 req, buf_size,
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret) {
@@ -602,7 +782,8 @@ int32_t sxe2_drv_rss_lut_set(struct sxe2_adapter *adapter, uint8_t *lut, uint16_
 	rte_memcpy(req->lut, lut, lut_size);
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_LUT_SET,
-		req, buf_size, NULL, 0);
+				 req, buf_size,
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret) {
@@ -629,7 +810,8 @@ int32_t sxe2_drv_rss_hash_ctrl_func(struct sxe2_adapter *adapter, enum sxe2_rss_
 	req.func = func;
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_FUNC_SET,
-		&req, sizeof(req), NULL, 0);
+				 &req, sizeof(req),
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret)
@@ -665,7 +847,8 @@ int32_t sxe2_drv_rss_hf_add(struct sxe2_adapter *adapter,
 	sxe2_drv_flow_bitmap_fill(req.hash_flds, rss_conf->flds);
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_HF_ADD,
-		&req, sizeof(req), NULL, 0);
+				 &req, sizeof(req),
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret)
@@ -703,7 +886,8 @@ int32_t sxe2_drv_rss_hf_clear(struct sxe2_adapter *adapter)
 	int32_t ret = 0;
 
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_HF_CLEAR,
-		NULL, 0, NULL, 0);
+				 NULL, 0,
+				 NULL, 0);
 
 	ret = sxe2_drv_cmd_exec(cdev, &param);
 	if (ret)
@@ -878,7 +1062,6 @@ int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter)
 	return ret;
 }
 
-
 int32_t sxe2_drv_ipsec_get_capa(struct sxe2_adapter *adapter)
 {
 	int32_t ret = -1;
@@ -1074,3 +1257,138 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
 	return ret;
 }
 
+int32_t sxe2_drv_queue_info_get_update(struct sxe2_adapter *adapter, struct eth_queue_stats *qstats)
+{
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_queue_map_info resp = {0};
+	struct sxe2_common_device *cdev = adapter->cdev;
+	uint8_t pool_idx;
+	uint8_t index;
+	int32_t ret;
+
+	if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_Q_MAP)) {
+		ret = 0;
+		goto l_end;
+	}
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_TX_RX_MAP_GET,
+				 NULL, 0,
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "get queue info map failed, ret=%d", ret);
+		goto l_end;
+	}
+
+	for (pool_idx = 0; pool_idx < SXE2_RXQ_STATS_MAP_MAX_NUM; pool_idx++) {
+		qstats->q_ipackets[pool_idx] = resp.rxq_stats_map_info[pool_idx].rxq_lan_in_pkt_cnt;
+		qstats->q_ibytes[pool_idx] = resp.rxq_stats_map_info[pool_idx].rxq_lan_in_byte_cnt;
+	}
+
+	for (index = 0; index < SXE2_TXQ_STATS_MAP_MAX_NUM; index++) {
+		qstats->q_opackets[index] = resp.txq_stats_map_info[index].txq_lan_pkt_cnt;
+		qstats->q_obytes[index] = resp.txq_stats_map_info[index].txq_lan_byte_cnt;
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_rxq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_rx_map_req req = {0};
+	struct sxe2_rx_queue *rxq = NULL;
+
+	rxq = eth_dev->data->rx_queues[queue_id];
+	if (rxq == NULL) {
+		PMD_LOG_ERR(DRV, "Rx queue %u is not available or setup",
+				queue_id);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	req.queue_id = rxq->queue_id;
+	req.pool_idx = pool_idx;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RX_MAP_SET,
+				 &req, sizeof(req),
+				 NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_LOG_ERR(DRV, "get dev caps failed, ret=%d", ret);
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_txq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_tx_map_req req = {0};
+	struct sxe2_tx_queue *txq = NULL;
+
+	txq = eth_dev->data->tx_queues[queue_id];
+	if (txq == NULL) {
+		PMD_LOG_ERR(DRV, "Rx queue %u is not available or setup", queue_id);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	req.queue_id = txq->queue_id;
+	req.pool_idx = pool_idx;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_TX_MAP_SET,
+				 &req, sizeof(req),
+				 NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_LOG_ERR(DRV, "get dev caps failed, ret=%d", ret);
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_mapping_reset(struct rte_eth_dev *eth_dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_TX_RX_MAP_RESET,
+				 NULL, 0,
+				 NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Reset queue mapping failed, ret=%d", ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_mapping_stats_info_clear(struct rte_eth_dev *eth_dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_TX_RX_MAP_INFO_CLEAR,
+				 NULL, 0,
+				 NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Clear map stats info failed, ret=%d", ret);
+
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index dac487fe7d..80ad10ac00 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -64,6 +64,29 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
 
 int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
 
+int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_get_mac_stats(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_mac_stats_reset(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_get_vsi_stats(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_vsi_stats_reset(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_queue_info_get_update(struct sxe2_adapter *adapter,
+				       struct eth_queue_stats *qstats);
+
+int32_t sxe2_drv_rxq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx);
+
+int32_t sxe2_drv_txq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx);
+
+int32_t sxe2_drv_mapping_reset(struct rte_eth_dev *eth_dev);
+
+int32_t sxe2_drv_mapping_stats_info_clear(struct rte_eth_dev *eth_dev);
+
+int32_t sxe2_drv_rxq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx);
+
 int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
 
 int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 39a108d76a..7935a28dc1 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -436,6 +436,126 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_rxsa_del_req {
 	uint8_t drv_id;
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_sw_stats {
+	uint64_t rx_packets;
+	uint64_t rx_bytes;
+	uint64_t tx_packets;
+	uint64_t tx_bytes;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_stats_req {
+	uint16_t vsi_id;
+	uint8_t  rsv[2];
+	struct sxe2_drv_vsi_sw_stats sw_stats;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_stats_resp {
+	uint64_t rx_vsi_unicast_packets;
+	uint64_t rx_vsi_bytes;
+	uint64_t tx_vsi_unicast_packets;
+	uint64_t tx_vsi_bytes;
+	uint64_t rx_vsi_multicast_packets;
+	uint64_t tx_vsi_multicast_packets;
+	uint64_t rx_vsi_broadcast_packets;
+	uint64_t tx_vsi_broadcast_packets;
+} __rte_packed_end;
+
+#define SXE2_MAX_USER_PRIORITY         (8)
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_mac_stats_resp {
+	uint64_t rx_out_of_buffer;
+	uint64_t rx_qblock_drop;
+	uint64_t tx_frame_good;
+	uint64_t rx_frame_good;
+	uint64_t rx_crc_errors;
+	uint64_t tx_bytes_good;
+	uint64_t rx_bytes_good;
+	uint64_t tx_multicast_good;
+	uint64_t tx_broadcast_good;
+	uint64_t rx_multicast_good;
+	uint64_t rx_broadcast_good;
+	uint64_t rx_len_errors;
+	uint64_t rx_out_of_range_errors;
+	uint64_t rx_oversize_pkts_phy;
+	uint64_t rx_symbol_err;
+	uint64_t rx_pause_frame;
+	uint64_t tx_pause_frame;
+	uint64_t rx_discards_phy;
+	uint64_t rx_discards_ips_phy;
+	uint64_t tx_dropped_link_down;
+	uint64_t rx_undersize_good;
+	uint64_t rx_runt_error;
+	uint64_t tx_bytes_good_bad;
+	uint64_t tx_frame_good_bad;
+	uint64_t rx_jabbers;
+	uint64_t rx_size_64;
+	uint64_t rx_size_65_127;
+	uint64_t rx_size_128_255;
+	uint64_t rx_size_256_511;
+	uint64_t rx_size_512_1023;
+	uint64_t rx_size_1024_1522;
+	uint64_t rx_size_1523_max;
+	uint64_t rx_pcs_symbol_err_phy;
+	uint64_t rx_corrected_bits_phy;
+	uint64_t rx_err_lane_0_phy;
+	uint64_t rx_err_lane_1_phy;
+	uint64_t rx_err_lane_2_phy;
+	uint64_t rx_err_lane_3_phy;
+	uint64_t rx_prio_buf_discard[SXE2_MAX_USER_PRIORITY];
+	uint64_t rx_illegal_bytes;
+	uint64_t rx_oversize_good;
+	uint64_t tx_unicast;
+	uint64_t tx_broadcast;
+	uint64_t tx_multicast;
+	uint64_t tx_vlan_packet_good;
+	uint64_t tx_size_64;
+	uint64_t tx_size_65_127;
+	uint64_t tx_size_128_255;
+	uint64_t tx_size_256_511;
+	uint64_t tx_size_512_1023;
+	uint64_t tx_size_1024_1522;
+	uint64_t tx_size_1523_max;
+	uint64_t tx_underflow_error;
+	uint64_t rx_byte_good_bad;
+	uint64_t rx_frame_good_bad;
+	uint64_t rx_unicast_good;
+	uint64_t rx_vlan_packets;
+	uint64_t prio_xoff_rx[SXE2_MAX_USER_PRIORITY];
+	uint64_t prio_xon_rx[SXE2_MAX_USER_PRIORITY];
+	uint64_t prio_xon_tx[SXE2_MAX_USER_PRIORITY];
+	uint64_t prio_xoff_tx[SXE2_MAX_USER_PRIORITY];
+	uint64_t prio_xon_2_xoff[SXE2_MAX_USER_PRIORITY];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_txq_map_info {
+	uint32_t txq_lan_pkt_cnt;
+	uint32_t txq_lan_byte_cnt;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_rxq_map_info {
+	uint64_t rxq_lan_in_pkt_cnt;
+	uint64_t rxq_lan_in_byte_cnt;
+	uint64_t rxq_fd_in_pkt_cnt;
+	uint64_t rxq_mng_in_pkt_cnt;
+	uint64_t rxq_mng_in_byte_cnt;
+	uint64_t rxq_mng_out_pkt_cnt;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_queue_map_info {
+	struct sxe2_rxq_map_info rxq_stats_map_info[SXE2_RXQ_STATS_MAP_MAX_NUM];
+	struct sxe2_txq_map_info txq_stats_map_info[SXE2_TXQ_STATS_MAP_MAX_NUM];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_rx_map_req {
+	uint16_t queue_id;
+	uint8_t pool_idx;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_tx_map_req {
+	uint16_t queue_id;
+	uint8_t pool_idx;
+} __rte_packed_end;
+
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
 	SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 9c9d98782b..46c6c993bf 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -31,6 +31,8 @@
 #include "sxe2_common.h"
 #include "sxe2_ptype.h"
 #include "sxe2_common_log.h"
+#include "sxe2_mp.h"
+#include "sxe2_stats.h"
 #include "sxe2_host_regs.h"
 #include "sxe2_ioctl_chnl_func.h"
 
@@ -132,6 +134,14 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.rss_hash_conf_get          = sxe2_dev_rss_hash_conf_get,
 
 	.tm_ops_get                 = sxe2_tm_ops_get,
+
+	.stats_get                  = sxe2_stats_info_get,
+	.stats_reset                = sxe2_stats_info_reset,
+	.xstats_get                 = sxe2_xstats_info_get,
+	.xstats_get_names           = sxe2_xstats_names_get,
+	.xstats_reset               = sxe2_stats_info_reset,
+
+	.queue_stats_mapping_set    = sxe2_queue_stats_mapping_set,
 };
 
 static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -1023,6 +1033,9 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 		sxe2_rx_mode_func_set(dev);
 		sxe2_tx_mode_func_set(dev);
+		ret = sxe2_mp_init(dev);
+		if (ret != 0)
+			PMD_LOG_ERR(INIT, "Failed to mp init (secondary), ret=%d", ret);
 		goto l_end;
 	}
 
@@ -1076,12 +1089,27 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_sched_err;
 	}
 
+	ret = sxe2_stats_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to stats init, ret=%d", ret);
+		goto init_xstats_err;
+	}
+
+	ret = sxe2_mp_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to mp init, ret=%d", ret);
+		goto init_xstats_err;
+	}
+
 	goto l_end;
 
-init_security_err:
-	sxe2_eth_uinit(dev);
+init_xstats_err:
+	(void)sxe2_sched_uinit(dev);
 init_sched_err:
 init_rss_err:
+	sxe2_security_uinit(dev);
+init_security_err:
+	sxe2_eth_uinit(dev);
 init_eth_err:
 init_dev_info_err:
 	sxe2_vsi_uninit(dev);
@@ -1093,8 +1121,13 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 
 static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 {
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		sxe2_mp_uninit(dev);
+		goto l_end;
+	}
 	(void)sxe2_dev_stop(dev);
 	(void)sxe2_queues_release(dev);
+	sxe2_mp_uninit(dev);
 	(void)sxe2_rss_disable(dev);
 	(void)sxe2_sched_uinit(dev);
 	sxe2_vsi_uninit(dev);
@@ -1102,6 +1135,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 	sxe2_dev_pci_map_uinit(dev);
 	sxe2_eth_uinit(dev);
 
+l_end:
 	return 0;
 }
 
diff --git a/drivers/net/sxe2/sxe2_mp.c b/drivers/net/sxe2/sxe2_mp.c
new file mode 100644
index 0000000000..a4a5c76495
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_mp.c
@@ -0,0 +1,414 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+ #include <stdlib.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <ethdev_driver.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_string_fns.h>
+
+#include "sxe2_mp.h"
+#include "sxe2_stats.h"
+#include "sxe2_common_log.h"
+
+static RTE_ATOMIC(uint16_t)primary_ethdev_cnt;
+static RTE_ATOMIC(uint16_t)secondary_ethdev_cnt;
+static const struct rte_memzone *sxe2_mp_mz;
+
+static int32_t sxe2_mp_acquire_token(void);
+static void sxe2_mp_release_token(void);
+
+static int32_t sxe2_mp_primary_handle(const struct rte_mp_msg *mp_msg,
+				   const void *peer);
+
+static int32_t sxe2_mp_secondary_handle(const struct rte_mp_msg *mp_msg,
+					 const void *peer);
+
+static int32_t
+sxe2_mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
+{
+	struct rte_mp_msg reply;
+	const struct sxe2_mp_param *param =
+			(const struct sxe2_mp_param *)mp_msg->param;
+	struct sxe2_mp_param *reply_param = (struct sxe2_mp_param *)reply.param;
+	struct rte_eth_dev *dev;
+	int32_t ret = 0;
+	struct sxe2_mp_shared_data *mz_data;
+	int32_t send_reply = 0;
+	int32_t cnt = 0;
+
+	if (!rte_eth_dev_is_valid_port(param->port_id)) {
+		PMD_LOG_ERR(DRV, "primary process: invalid port_id %u",
+				param->port_id);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev = &rte_eth_devices[param->port_id];
+	sxe2_mp_mz = rte_memzone_lookup(SXE2_MP_MZ_NAME);
+	if (sxe2_mp_mz == NULL) {
+		PMD_LOG_ERR(DRV, "Failed to lookup memzone %s", SXE2_MP_MZ_NAME);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+	send_reply = 1;
+
+	memset(&reply, 0, sizeof(reply));
+	(void)strlcpy(reply.name, SXE2_MP_NAME, sizeof(reply.name));
+	reply.len_param = sizeof(*reply_param);
+
+	switch (param->type) {
+	case SXE2_MP_REQ_GET_STATS:
+		ret = sxe2_stats_info_get(dev,
+					  &mz_data->payload.stats_blk.stats,
+					  &mz_data->payload.stats_blk.qstats);
+		break;
+	case SXE2_MP_REQ_GET_XSTATS:
+		cnt = sxe2_xstats_info_get(dev,
+				mz_data->payload.xstats_blk.xstats,
+				SXE2_MP_MAX_XSTATS);
+
+		if (cnt >= 0) {
+			mz_data->payload.xstats_blk.xstats_num = (uint32_t)cnt;
+			ret = 0;
+		} else {
+			mz_data->payload.xstats_blk.xstats_num = 0;
+			ret = cnt;
+		}
+		break;
+	case SXE2_MP_REQ_RESET_STATS:
+		ret = sxe2_stats_hw_reset(dev);
+		break;
+	default:
+		PMD_LOG_ERR(DRV, "primary process: unrecognized msg type: %d",
+				param->type);
+		send_reply = false;
+		ret = -EINVAL;
+		goto out;
+	}
+out:
+	if (!send_reply)
+		return ret;
+
+	reply_param->result = ret;
+	reply_param->type = param->type;
+	reply_param->port_id = param->port_id;
+
+	return rte_mp_reply(&reply, peer);
+}
+
+static int32_t
+sxe2_mp_secondary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
+			 const void *peer __rte_unused)
+{
+	PMD_LOG_WARN(DRV, "the secondary process handler should not be called");
+	return 0;
+}
+
+static int32_t
+sxe2_mp_init_primary(__rte_unused struct rte_eth_dev *dev)
+{
+	int32_t ret;
+
+	if (sxe2_mp_mz == NULL) {
+		sxe2_mp_mz = rte_memzone_reserve(SXE2_MP_MZ_NAME,
+				sizeof(struct sxe2_mp_shared_data),
+				rte_socket_id(), 0);
+		if (sxe2_mp_mz == NULL && rte_errno != EEXIST) {
+			PMD_LOG_ERR(DRV, "Failed to reserve memzone %s, error: %d",
+					SXE2_MP_MZ_NAME, -rte_errno);
+			ret = -rte_errno;
+			goto out;
+		}
+
+		sxe2_mp_mz = rte_memzone_lookup(SXE2_MP_MZ_NAME);
+		if (sxe2_mp_mz == NULL) {
+			PMD_LOG_ERR(DRV, "Failed to lookup memzone %s", SXE2_MP_MZ_NAME);
+			ret = -ENOENT;
+			goto out;
+		}
+
+		struct sxe2_mp_shared_data *mz =
+			(struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+		rte_atomic_store_explicit(&mz->in_use, 0, rte_memory_order_release);
+	}
+
+	ret = rte_mp_action_register(SXE2_MP_NAME, sxe2_mp_primary_handle);
+	if (ret && rte_errno == ENOTSUP) {
+		PMD_LOG_INFO(DRV, "Primary not support IPC.");
+		ret = 0;
+		goto out;
+	} else if (ret && rte_errno != EEXIST) {
+		PMD_LOG_ERR(DRV, "Failed to register MP primary handle, error: %d",
+			-rte_errno);
+		goto out;
+	}
+
+	rte_atomic_fetch_add_explicit(&primary_ethdev_cnt, 1, rte_memory_order_relaxed);
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static int32_t
+sxe2_mp_init_secondary(__rte_unused struct rte_eth_dev *dev)
+{
+	int32_t ret;
+
+	sxe2_mp_mz = rte_memzone_lookup(SXE2_MP_MZ_NAME);
+	if (sxe2_mp_mz == NULL) {
+		PMD_LOG_ERR(DRV, "Failed to lookup memzone %s", SXE2_MP_MZ_NAME);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ret = rte_mp_action_register(SXE2_MP_NAME, sxe2_mp_secondary_handle);
+	if (ret && rte_errno != EEXIST) {
+		PMD_LOG_ERR(DRV, "Failed to register MP secondary handle, error: %d",
+				-rte_errno);
+		goto out;
+	}
+
+	rte_atomic_fetch_add_explicit(&secondary_ethdev_cnt, 1, rte_memory_order_relaxed);
+
+	ret = 0;
+out:
+	return ret;
+}
+
+int32_t
+sxe2_mp_init(struct rte_eth_dev *dev)
+{
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		return sxe2_mp_init_primary(dev);
+	else
+		return sxe2_mp_init_secondary(dev);
+}
+
+void
+sxe2_mp_uninit(__rte_unused struct rte_eth_dev *dev)
+{
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		if (rte_atomic_fetch_sub_explicit(&primary_ethdev_cnt, 1,
+			rte_memory_order_acq_rel) == 1) {
+			rte_mp_action_unregister(SXE2_MP_NAME);
+			if (sxe2_mp_mz != NULL) {
+				rte_memzone_free(sxe2_mp_mz);
+				sxe2_mp_mz = NULL;
+			}
+		}
+	} else {
+		if (rte_atomic_fetch_sub_explicit(&secondary_ethdev_cnt, 1,
+			rte_memory_order_acq_rel) == 1)
+			rte_mp_action_unregister(SXE2_MP_NAME);
+	}
+}
+
+static int32_t sxe2_mp_acquire_token(void)
+{
+	struct sxe2_mp_shared_data *mz;
+	uint16_t expected;
+
+	if (sxe2_mp_mz == NULL)
+		return -EINVAL;
+
+	mz = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+
+	for (int32_t i = 0; i < SXE2_MP_MAX_SPIN; i++) {
+		expected = 0;
+		if (rte_atomic_compare_exchange_strong_explicit(&mz->in_use, &expected, 1,
+			rte_memory_order_acquire, rte_memory_order_relaxed))
+			return 0;
+
+		rte_pause();
+	}
+	return -EBUSY;
+}
+
+static void sxe2_mp_release_token(void)
+{
+	struct sxe2_mp_shared_data *mz;
+
+	if (sxe2_mp_mz == NULL)
+		return;
+
+	mz = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+	rte_atomic_store_explicit(&mz->in_use, 0, rte_memory_order_release);
+}
+
+int32_t sxe2_mp_request_simple(struct rte_eth_dev *dev,
+			   enum sxe2_mp_req_type type,
+			   int32_t *result_out)
+{
+	struct rte_mp_msg msg;
+	struct rte_mp_reply reply = { 0 };
+	struct timespec ts = { .tv_sec = SXE2_MP_MSG_TIMEOUT, .tv_nsec = 0 };
+	struct sxe2_mp_param *param = (struct sxe2_mp_param *)msg.param;
+	struct sxe2_mp_shared_data *mz_data;
+	int32_t ret = 0;
+
+	mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+
+	memset(&mz_data->payload, 0, sizeof(mz_data->payload));
+	memset(&msg, 0, sizeof(msg));
+	(void)strlcpy(msg.name, SXE2_MP_NAME, sizeof(msg.name));
+	msg.len_param = sizeof(*param);
+	param->type = type;
+	param->port_id = dev->data->port_id;
+
+	ret = rte_mp_request_sync(&msg, &reply, &ts);
+	if (ret != 0) {
+		PMD_LOG_ERR(DRV,
+				"IPC request(type=%d) failed for port %u: %s",
+				type, dev->data->port_id, rte_strerror(rte_errno));
+		ret = -rte_errno;
+		goto out;
+	}
+
+	if (reply.nb_received == 0) {
+		PMD_LOG_ERR(DRV, "No response received from primary for type=%d, port %u",
+			type, dev->data->port_id);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	*result_out = ((struct sxe2_mp_param *)reply.msgs[0].param)->result;
+
+out:
+	if (reply.msgs != NULL)
+		free(reply.msgs);
+
+	return ret;
+}
+
+int32_t sxe2_mp_req_get_stats(struct rte_eth_dev *dev,
+		      struct rte_eth_stats *stats,
+		      struct eth_queue_stats *qstats)
+{
+	struct sxe2_mp_shared_data *mz_data;
+	int32_t mp_ret;
+	int32_t ret;
+	int32_t token_acquired = 0;
+
+	if (sxe2_mp_mz == NULL)
+		return -EINVAL;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		PMD_LOG_WARN(DRV, "Primary process direct execution for port %u",
+			     dev->data->port_id);
+		return sxe2_stats_info_get(dev, stats, qstats);
+	}
+
+	int32_t token_ret = sxe2_mp_acquire_token();
+	if (token_ret != 0)
+		return token_ret;
+	token_acquired = 1;
+
+	mp_ret = sxe2_mp_request_simple(dev, SXE2_MP_REQ_GET_STATS, &ret);
+	if (mp_ret != 0) {
+		ret = mp_ret;
+		goto out;
+	}
+
+	if (ret != 0) {
+		PMD_LOG_ERR(DRV, "Primary failed to exec request (type=%d), result: %d for port %u",
+			    SXE2_MP_REQ_GET_STATS, ret, dev->data->port_id);
+		goto out;
+	}
+
+	mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+	memcpy(stats, &mz_data->payload.stats_blk.stats, sizeof(*stats));
+	memcpy(qstats, &mz_data->payload.stats_blk.qstats, sizeof(*qstats));
+	PMD_LOG_DEBUG(DRV, "sxe2_mp: stats received via IPC for port %u",
+			  dev->data->port_id);
+	ret = 0;
+out:
+	if (token_acquired)
+		sxe2_mp_release_token();
+	return ret;
+}
+
+int32_t sxe2_mp_req_get_xstats(struct rte_eth_dev *dev,
+			   struct rte_eth_xstat *xstats, uint32_t usr_cnt)
+{
+	struct sxe2_mp_shared_data *mz_data;
+	int32_t ret;
+	int32_t mp_ret;
+	int32_t token_acquired = 0;
+
+	if (sxe2_mp_mz == NULL)
+		return -EINVAL;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		PMD_LOG_WARN(DRV, "Primary process direct execution for port %u",
+			     dev->data->port_id);
+		return sxe2_xstats_info_get(dev, xstats, usr_cnt);
+	}
+
+	int32_t token_ret = sxe2_mp_acquire_token();
+	if (token_ret != 0)
+		return token_ret;
+	token_acquired = 1;
+
+	mp_ret = sxe2_mp_request_simple(dev, SXE2_MP_REQ_GET_XSTATS, &ret);
+	if (mp_ret != 0) {
+		ret = mp_ret;
+		goto out;
+	}
+
+	if (ret != 0) {
+		PMD_LOG_ERR(DRV, "Primary failed to exec request (type=%d), result: %d for port %u",
+			    SXE2_MP_REQ_GET_XSTATS, ret, dev->data->port_id);
+		goto out;
+	}
+
+	mz_data = (struct sxe2_mp_shared_data *)sxe2_mp_mz->addr;
+	if (usr_cnt < mz_data->payload.xstats_blk.xstats_num) {
+		PMD_LOG_ERR(DRV, "user usr_cnt:%u less than xstats cnt:%u.",
+			    usr_cnt, mz_data->payload.xstats_blk.xstats_num);
+		ret = (int32_t)mz_data->payload.xstats_blk.xstats_num;
+		goto out;
+	}
+
+	memcpy(xstats, mz_data->payload.xstats_blk.xstats,
+		   mz_data->payload.xstats_blk.xstats_num *
+			   sizeof(struct rte_eth_xstat));
+	ret = (int32_t)mz_data->payload.xstats_blk.xstats_num;
+
+	PMD_LOG_DEBUG(DRV,
+			  "xstats received via IPC for port %u (cnt=%d)",
+			  dev->data->port_id, ret);
+out:
+	if (token_acquired)
+		sxe2_mp_release_token();
+	return ret;
+}
+
+int32_t
+sxe2_mp_req_reset_stats(struct rte_eth_dev *dev)
+{
+	int32_t mp_ret;
+	int32_t ret = 0;
+
+	if (sxe2_mp_mz == NULL)
+		return -EINVAL;
+
+	mp_ret = sxe2_mp_request_simple(dev, SXE2_MP_REQ_RESET_STATS, &ret);
+	if (mp_ret != 0)
+		return mp_ret;
+
+	if (ret != 0) {
+		PMD_LOG_ERR(DRV,
+				"Primary failed SXE2_MP_REQ_RESET_STATS, result: %d for port %u",
+				ret, dev->data->port_id);
+		return ret;
+	}
+	return 0;
+}
diff --git a/drivers/net/sxe2/sxe2_mp.h b/drivers/net/sxe2/sxe2_mp.h
new file mode 100644
index 0000000000..da9cc91d8d
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_mp.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_MP_H
+#define SXE2_MP_H
+
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_memzone.h>
+#include <rte_stdatomic.h>
+
+#define SXE2_MP_NAME		"sxe2_mp_msg"
+#define SXE2_MP_MZ_NAME		"sxe2_stats_mz"
+
+#define SXE2_MP_MSG_TIMEOUT 30
+
+#define SXE2_MP_MAX_XSTATS	128
+
+#define SXE2_MP_MAX_SPIN	100000
+
+enum sxe2_mp_req_type {
+	SXE2_MP_REQ_GET_STATS = 1,
+	SXE2_MP_REQ_GET_XSTATS,
+	SXE2_MP_REQ_RESET_STATS,
+};
+
+struct sxe2_mp_param {
+	enum sxe2_mp_req_type type;
+	uint32_t port_id;
+	int result;
+};
+
+union sxe2_mp_shared_payload {
+	struct {
+		struct rte_eth_stats stats;
+		struct eth_queue_stats qstats;
+	} stats_blk;
+	struct {
+		struct rte_eth_xstat xstats[SXE2_MP_MAX_XSTATS];
+		uint32_t xstats_num;
+	} xstats_blk;
+};
+
+struct sxe2_mp_shared_data {
+	RTE_ATOMIC(uint16_t)in_use;
+	union sxe2_mp_shared_payload payload;
+};
+
+int sxe2_mp_init(struct rte_eth_dev *dev);
+
+void sxe2_mp_uninit(struct rte_eth_dev *dev);
+
+int sxe2_mp_request_simple(struct rte_eth_dev *dev,
+			   enum sxe2_mp_req_type type,
+			   int *result_out);
+
+int sxe2_mp_req_get_stats(struct rte_eth_dev *dev,
+			  struct rte_eth_stats *stats,
+			  struct eth_queue_stats *qstats);
+
+int sxe2_mp_req_get_xstats(struct rte_eth_dev *dev,
+			   struct rte_eth_xstat *xstats, uint32_t usr_cnt);
+
+int sxe2_mp_req_reset_stats(struct rte_eth_dev *dev);
+
+#endif
diff --git a/drivers/net/sxe2/sxe2_stats.c b/drivers/net/sxe2/sxe2_stats.c
new file mode 100644
index 0000000000..7ea2815fa3
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_stats.c
@@ -0,0 +1,586 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_eal.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_vsi.h"
+#include "sxe2_common_log.h"
+#include "sxe2_stats.h"
+#include "sxe2_queue.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_mp.h"
+
+#define SXE2_XSTAT_CNT_PF RTE_DIM(sxe2_xstats_field_pf)
+#define SXE2_XSTAT_CNT_VF RTE_DIM(sxe2_xstats_field_vf)
+
+static struct sxe2_stats_field sxe2_xstats_field_pf[] = {
+	{"rx_qblock_drop", offsetof(struct sxe2_stats, rx_qblock_drop)},
+	{"rx_out_of_buffer", offsetof(struct sxe2_stats, rx_out_of_buffer)},
+	{"tx_packets_phy", offsetof(struct sxe2_stats, tx_frame_good)},
+	{"rx_packets_phy", offsetof(struct sxe2_stats, rx_frame_good)},
+	{"rx_crc_errors_phy", offsetof(struct sxe2_stats, rx_crc_errors)},
+	{"tx_bytes_phy", offsetof(struct sxe2_stats, tx_bytes_good)},
+	{"rx_bytes_phy", offsetof(struct sxe2_stats, rx_bytes_good)},
+	{"tx_multicast_phy", offsetof(struct sxe2_stats, tx_multicast_good)},
+	{"tx_broadcast_phy", offsetof(struct sxe2_stats, tx_broadcast_good)},
+	{"rx_multicast_phy", offsetof(struct sxe2_stats, rx_multicast_good)},
+	{"rx_broadcast_phy", offsetof(struct sxe2_stats, rx_broadcast_good)},
+	{"rx_in_range_len_errs_phy", offsetof(struct sxe2_stats, rx_len_errors)},
+	{"rx_out_of_range_len_phy", offsetof(struct sxe2_stats, rx_out_of_range_errors)},
+	{"rx_oversize_pkts_phy", offsetof(struct sxe2_stats, rx_oversize_pkts_phy)},
+	{"rx_symbol_err_phy", offsetof(struct sxe2_stats, rx_symbol_err)},
+	{"rx_pause_ctrl_phy", offsetof(struct sxe2_stats, rx_pause_frame)},
+	{"tx_pause_ctrl_phy", offsetof(struct sxe2_stats, tx_pause_frame)},
+	{"rx_discards_phy", offsetof(struct sxe2_stats, rx_discards_phy)},
+	{"rx_discards_ips_phy", offsetof(struct sxe2_stats, rx_discards_ips_phy)},
+	{"tx_dropped_link_down_phy", offsetof(struct sxe2_stats, tx_dropped_link_down)},
+	{"rx_undersize_pkts_phy", offsetof(struct sxe2_stats, rx_undersize_good)},
+	{"rx_fragments_phy", offsetof(struct sxe2_stats, rx_runt_error)},
+	{"tx_bytes_all_phy", offsetof(struct sxe2_stats, tx_bytes_good_bad)},
+	{"tx_packets_all_phy", offsetof(struct sxe2_stats, tx_frame_good_bad)},
+	{"rx_jabbers_phy", offsetof(struct sxe2_stats, rx_jabbers)},
+	{"rx_64_bytes_phy", offsetof(struct sxe2_stats, rx_size_64)},
+	{"rx_65_to_127_bytes_phy", offsetof(struct sxe2_stats, rx_size_65_127)},
+	{"rx_128_to_255_bytes_phy", offsetof(struct sxe2_stats, rx_size_128_255)},
+	{"rx_256_to_511_bytes_phy", offsetof(struct sxe2_stats, rx_size_256_511)},
+	{"rx_512_to_1023_bytes_phy", offsetof(struct sxe2_stats, rx_size_512_1023)},
+	{"rx_1024_to_1522_bytes_phy", offsetof(struct sxe2_stats, rx_size_1024_1522)},
+	{"rx_1523_to_max_bytes_phy", offsetof(struct sxe2_stats, rx_size_1523_max)},
+	{"rx_pcs_symbol_err_phy", offsetof(struct sxe2_stats, rx_pcs_symbol_err_phy)},
+	{"rx_corrected_bits_phy", offsetof(struct sxe2_stats, rx_corrected_bits_phy)},
+	{"rx_err_lane_0_phy", offsetof(struct sxe2_stats, rx_err_lane_0_phy)},
+	{"rx_err_lane_1_phy", offsetof(struct sxe2_stats, rx_err_lane_1_phy)},
+	{"rx_err_lane_2_phy", offsetof(struct sxe2_stats, rx_err_lane_2_phy)},
+	{"rx_err_lane_3_phy", offsetof(struct sxe2_stats, rx_err_lane_3_phy)},
+	{"rx_illegal_bytes_phy", offsetof(struct sxe2_stats, rx_illegal_bytes)},
+	{"rx_oversize_good_phy", offsetof(struct sxe2_stats, rx_oversize_good)},
+	{"tx_unicast_all_phy", offsetof(struct sxe2_stats, tx_unicast)},
+	{"tx_broadcast_all_phy", offsetof(struct sxe2_stats, tx_broadcast)},
+	{"tx_multicast_all_phy", offsetof(struct sxe2_stats, tx_multicast)},
+	{"tx_vlan_packets_good_phy", offsetof(struct sxe2_stats, tx_vlan_packet_good)},
+	{"tx_64_bytes_phy", offsetof(struct sxe2_stats, tx_size_64)},
+	{"tx_65_to_127_bytes_phy", offsetof(struct sxe2_stats, tx_size_65_127)},
+	{"tx_128_to_255_bytes_phy", offsetof(struct sxe2_stats, tx_size_128_255)},
+	{"tx_256_to_511_bytes_phy", offsetof(struct sxe2_stats, tx_size_256_511)},
+	{"tx_512_to_1023_bytes_phy", offsetof(struct sxe2_stats, tx_size_512_1023)},
+	{"tx_1024_to_1522_bytes_phy", offsetof(struct sxe2_stats, tx_size_1024_1522)},
+	{"tx_1523_to_max_bytes_phy", offsetof(struct sxe2_stats, tx_size_1523_max)},
+	{"tx_underflow_error_phy", offsetof(struct sxe2_stats, tx_underflow_error)},
+	{"rx_bytes_all_phy", offsetof(struct sxe2_stats, rx_byte_good_bad)},
+	{"rx_packets_all_phy", offsetof(struct sxe2_stats, rx_frame_good_bad)},
+	{"rx_unicast_phy", offsetof(struct sxe2_stats, rx_unicast_good)},
+	{"rx_vlan_packets_phy", offsetof(struct sxe2_stats, rx_vlan_packets)},
+
+	{"rx_vport_bytes",             offsetof(struct sxe2_stats, rx_vsi_bytes)},
+	{"rx_vport_unicast_packets",   offsetof(struct sxe2_stats, rx_vsi_unicast_packets)},
+	{"rx_vport_broadcast_packets", offsetof(struct sxe2_stats, rx_vsi_broadcast_packets)},
+	{"rx_vport_multicast_packets", offsetof(struct sxe2_stats, rx_vsi_multicast_packets)},
+	{"rx_sw_unicast_packets",      offsetof(struct sxe2_stats, rx_sw_unicast_packets)},
+	{"rx_sw_broadcast_packets",    offsetof(struct sxe2_stats, rx_sw_broadcast_packets)},
+	{"rx_sw_multicast_packets",    offsetof(struct sxe2_stats, rx_sw_multicast_packets)},
+	{"rx_sw_drop_packets",         offsetof(struct sxe2_stats, rx_sw_drop_packets)},
+	{"rx_sw_drop_bytes",           offsetof(struct sxe2_stats, rx_sw_drop_bytes)},
+
+	{"tx_vport_bytes",             offsetof(struct sxe2_stats, tx_vsi_bytes)},
+	{"tx_vport_unicast_packets",   offsetof(struct sxe2_stats, tx_vsi_unicast_packets)},
+	{"tx_vport_broadcast_packets", offsetof(struct sxe2_stats, tx_vsi_broadcast_packets)},
+	{"tx_vport_multicast_packets", offsetof(struct sxe2_stats, tx_vsi_multicast_packets)},
+};
+
+static struct sxe2_stats_field sxe2_xstats_field_vf[] = {
+	{"rx_vport_bytes",             offsetof(struct sxe2_stats, rx_vsi_bytes)},
+	{"rx_vport_unicast_packets",   offsetof(struct sxe2_stats, rx_vsi_unicast_packets)},
+	{"rx_vport_broadcast_packets", offsetof(struct sxe2_stats, rx_vsi_broadcast_packets)},
+	{"rx_vport_multicast_packets", offsetof(struct sxe2_stats, rx_vsi_multicast_packets)},
+	{"rx_sw_unicast_packets",      offsetof(struct sxe2_stats, rx_sw_unicast_packets)},
+	{"rx_sw_broadcast_packets",    offsetof(struct sxe2_stats, rx_sw_broadcast_packets)},
+	{"rx_sw_multicast_packets",    offsetof(struct sxe2_stats, rx_sw_multicast_packets)},
+	{"rx_sw_drop_packets",         offsetof(struct sxe2_stats, rx_sw_drop_packets)},
+	{"rx_sw_drop_bytes",           offsetof(struct sxe2_stats, rx_sw_drop_bytes)},
+
+	{"tx_vport_bytes",             offsetof(struct sxe2_stats, tx_vsi_bytes)},
+	{"tx_vport_unicast_packets",   offsetof(struct sxe2_stats, tx_vsi_unicast_packets)},
+	{"tx_vport_broadcast_packets", offsetof(struct sxe2_stats, tx_vsi_broadcast_packets)},
+	{"tx_vport_multicast_packets", offsetof(struct sxe2_stats, tx_vsi_multicast_packets)},
+};
+
+static int32_t sxe2_xstat_pf_offset_get(uint32_t id, uint32_t *offset)
+{
+	int32_t ret  = 0;
+	uint32_t size = SXE2_XSTAT_CNT_PF;
+
+	if (id < size) {
+		*offset = sxe2_xstats_field_pf[id].offset;
+	} else {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "invalid id:%u exceed stats size cnt:%u", id, size);
+	}
+	return ret;
+}
+
+static int32_t sxe2_xstat_vf_offset_get(uint32_t id, uint32_t *offset)
+{
+	int32_t ret  = 0;
+	uint32_t size = SXE2_XSTAT_CNT_VF;
+
+	if (id < size) {
+		*offset = sxe2_xstats_field_vf[id].offset;
+	} else {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "invalid id:%u exceed stats size cnt:%u", id, size);
+	}
+	return ret;
+}
+
+static int32_t sxe2_mac_hw_stats_get_update(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	ret = sxe2_drv_get_mac_stats(adapter);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "get mac stats failed, ret:%d.", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_vsi_hw_stats_get_update(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	ret = sxe2_drv_get_vsi_stats(adapter);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "get vsi stats failed, ret:%d.", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_vsi_sw_stats_get_update(struct sxe2_adapter *adapter)
+{
+	int32_t ret  = 0;
+	struct sxe2_vsi          *vsi      = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_stats        *sw_stats = &vsi->vsi_stats.vsi_sw_stats;
+	struct sxe2_rx_queue     *rxq;
+	uint32_t rx_queue_id;
+	memset(sw_stats, 0, sizeof(struct sxe2_stats));
+
+	for (rx_queue_id = 0; rx_queue_id < adapter->dev_info.dev_data->nb_rx_queues;
+		     rx_queue_id++) {
+		rxq = adapter->dev_info.dev_data->rx_queues[rx_queue_id];
+		if (rxq) {
+			sw_stats->ipackets += rxq->sw_stats.pkts;
+			sw_stats->ierrors += rxq->sw_stats.drop_pkts;
+			sw_stats->ibytes += rxq->sw_stats.bytes;
+
+			sw_stats->rx_sw_unicast_packets += rxq->sw_stats.unicast_pkts;
+			sw_stats->rx_sw_broadcast_packets += rxq->sw_stats.broadcast_pkts;
+			sw_stats->rx_sw_multicast_packets += rxq->sw_stats.multicast_pkts;
+			sw_stats->rx_sw_drop_packets += rxq->sw_stats.drop_pkts;
+			sw_stats->rx_sw_drop_bytes += rxq->sw_stats.drop_bytes;
+		}
+	}
+
+	return ret;
+}
+
+static void sxe2_stats_update(struct sxe2_adapter *adapter)
+{
+	struct sxe2_vsi          *vsi      = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_stats        *stats = &vsi->vsi_stats.stats;
+	struct sxe2_stats        *hw_stats = &vsi->vsi_stats.vsi_hw_stats;
+	struct sxe2_stats        *sw_stats = &vsi->vsi_stats.vsi_sw_stats;
+	struct sxe2_stats        *sw_stats_prev = &vsi->vsi_stats.vsi_sw_stats_prev;
+	uint8_t i = 0;
+
+	memset(stats, 0, sizeof(struct sxe2_stats));
+
+	stats->opackets = hw_stats->opackets;
+	stats->obytes   = hw_stats->tx_vsi_bytes;
+	stats->tx_vsi_bytes             = hw_stats->tx_vsi_bytes;
+	stats->tx_vsi_unicast_packets   = hw_stats->tx_vsi_unicast_packets;
+	stats->tx_vsi_broadcast_packets = hw_stats->tx_vsi_broadcast_packets;
+	stats->tx_vsi_multicast_packets = hw_stats->tx_vsi_multicast_packets;
+
+	stats->ierrors = sw_stats->ierrors + sw_stats_prev->ierrors;
+	if (adapter->devargs.sw_stats_en) {
+		stats->ipackets = sw_stats->ipackets + sw_stats_prev->ipackets;
+		stats->ibytes = sw_stats->ibytes + sw_stats_prev->ibytes;
+	} else {
+		stats->ipackets = hw_stats->ipackets;
+		stats->ibytes   = hw_stats->rx_vsi_bytes;
+	}
+	stats->rx_vsi_bytes             = hw_stats->rx_vsi_bytes;
+	stats->rx_vsi_unicast_packets   = hw_stats->rx_vsi_unicast_packets;
+	stats->rx_vsi_broadcast_packets = hw_stats->rx_vsi_broadcast_packets;
+	stats->rx_vsi_multicast_packets = hw_stats->rx_vsi_multicast_packets;
+	stats->rx_sw_unicast_packets = sw_stats->rx_sw_unicast_packets +
+			sw_stats_prev->rx_sw_unicast_packets;
+	stats->rx_sw_broadcast_packets = sw_stats->rx_sw_broadcast_packets +
+			sw_stats_prev->rx_sw_broadcast_packets;
+	stats->rx_sw_multicast_packets = sw_stats->rx_sw_multicast_packets +
+			sw_stats_prev->rx_sw_multicast_packets;
+	stats->rx_sw_drop_packets = sw_stats->rx_sw_drop_packets +
+			sw_stats_prev->rx_sw_drop_packets;
+	stats->rx_sw_drop_bytes = sw_stats->rx_sw_drop_bytes +
+			sw_stats_prev->rx_sw_drop_bytes;
+
+	if (adapter->dev_type != SXE2_DEV_T_VF) {
+		stats->rx_out_of_buffer = hw_stats->rx_out_of_buffer;
+		stats->rx_qblock_drop = hw_stats->rx_qblock_drop;
+		stats->tx_frame_good = hw_stats->tx_frame_good;
+		stats->rx_frame_good = hw_stats->rx_frame_good;
+		stats->rx_crc_errors = hw_stats->rx_crc_errors;
+		stats->tx_bytes_good = hw_stats->tx_bytes_good;
+		stats->rx_bytes_good = hw_stats->rx_bytes_good;
+		stats->tx_multicast_good = hw_stats->tx_multicast_good;
+		stats->tx_broadcast_good = hw_stats->tx_broadcast_good;
+		stats->rx_multicast_good = hw_stats->rx_multicast_good;
+		stats->rx_broadcast_good = hw_stats->rx_broadcast_good;
+		stats->rx_len_errors = hw_stats->rx_len_errors;
+		stats->rx_out_of_range_errors = hw_stats->rx_out_of_range_errors;
+		stats->rx_oversize_pkts_phy = hw_stats->rx_oversize_pkts_phy;
+		stats->rx_symbol_err = hw_stats->rx_symbol_err;
+		stats->rx_pause_frame = hw_stats->rx_pause_frame;
+		stats->tx_pause_frame = hw_stats->tx_pause_frame;
+		stats->rx_discards_phy = hw_stats->rx_discards_phy;
+		stats->rx_discards_ips_phy = hw_stats->rx_discards_ips_phy;
+		stats->tx_dropped_link_down = hw_stats->tx_dropped_link_down;
+		stats->rx_undersize_good = hw_stats->rx_undersize_good;
+		stats->rx_runt_error = hw_stats->rx_runt_error;
+		stats->tx_bytes_good_bad = hw_stats->tx_bytes_good_bad;
+		stats->tx_frame_good_bad = hw_stats->tx_frame_good_bad;
+		stats->rx_jabbers = hw_stats->rx_jabbers;
+		stats->rx_size_64 = hw_stats->rx_size_64;
+		stats->rx_size_65_127 = hw_stats->rx_size_65_127;
+		stats->rx_size_128_255 = hw_stats->rx_size_128_255;
+		stats->rx_size_256_511 = hw_stats->rx_size_256_511;
+		stats->rx_size_512_1023 = hw_stats->rx_size_512_1023;
+		stats->rx_size_1024_1522 = hw_stats->rx_size_1024_1522;
+		stats->rx_size_1523_max = hw_stats->rx_size_1523_max;
+		stats->rx_pcs_symbol_err_phy = hw_stats->rx_pcs_symbol_err_phy;
+		stats->rx_corrected_bits_phy = hw_stats->rx_corrected_bits_phy;
+		stats->rx_err_lane_0_phy = hw_stats->rx_err_lane_0_phy;
+		stats->rx_err_lane_1_phy = hw_stats->rx_err_lane_1_phy;
+		stats->rx_err_lane_2_phy = hw_stats->rx_err_lane_2_phy;
+		stats->rx_err_lane_3_phy = hw_stats->rx_err_lane_3_phy;
+		stats->rx_illegal_bytes = hw_stats->rx_illegal_bytes;
+		stats->rx_oversize_good = hw_stats->rx_oversize_good;
+		stats->tx_unicast = hw_stats->tx_unicast;
+		stats->tx_broadcast = hw_stats->tx_broadcast;
+		stats->tx_multicast = hw_stats->tx_multicast;
+		stats->tx_vlan_packet_good = hw_stats->tx_vlan_packet_good;
+		stats->tx_size_64 = hw_stats->tx_size_64;
+		stats->tx_size_65_127 = hw_stats->tx_size_65_127;
+		stats->tx_size_128_255 = hw_stats->tx_size_128_255;
+		stats->tx_size_256_511 = hw_stats->tx_size_256_511;
+		stats->tx_size_512_1023 = hw_stats->tx_size_512_1023;
+		stats->tx_size_1024_1522 = hw_stats->tx_size_1024_1522;
+		stats->tx_size_1523_max = hw_stats->tx_size_1523_max;
+		stats->tx_underflow_error = hw_stats->tx_underflow_error;
+		stats->rx_byte_good_bad = hw_stats->rx_byte_good_bad;
+		stats->rx_frame_good_bad = hw_stats->rx_frame_good_bad;
+		stats->rx_unicast_good = hw_stats->rx_unicast_good;
+		stats->rx_vlan_packets = hw_stats->rx_vlan_packets;
+		rte_memcpy(stats->rx_prio_buf_discard, hw_stats->rx_prio_buf_discard,
+				sizeof(hw_stats->rx_prio_buf_discard));
+		rte_memcpy(stats->prio_xoff_rx, hw_stats->prio_xoff_rx,
+				sizeof(hw_stats->prio_xoff_rx));
+		rte_memcpy(stats->prio_xon_rx, hw_stats->prio_xon_rx,
+				sizeof(hw_stats->prio_xon_rx));
+		rte_memcpy(stats->prio_xon_tx, hw_stats->prio_xon_tx,
+				sizeof(hw_stats->prio_xon_tx));
+		rte_memcpy(stats->prio_xoff_tx, hw_stats->prio_xoff_tx,
+				sizeof(hw_stats->prio_xoff_tx));
+		rte_memcpy(stats->prio_xon_2_xoff, hw_stats->prio_xon_2_xoff,
+				sizeof(hw_stats->prio_xon_2_xoff));
+
+		stats->imissed = hw_stats->rx_out_of_buffer +
+				hw_stats->rx_qblock_drop;
+		for (i = 0; i < SXE2_MAX_USER_PRIORITY; i++)
+			stats->imissed += hw_stats->rx_prio_buf_discard[i];
+	}
+}
+
+int32_t sxe2_stats_info_get(struct rte_eth_dev *dev,
+			struct rte_eth_stats *stats,
+			struct eth_queue_stats *qstats)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter  = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_vsi     *vsi      = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_stats   *stats_out = &vsi->vsi_stats.stats;
+
+	if (rte_eal_process_type() == RTE_PROC_SECONDARY)
+		return sxe2_mp_req_get_stats(dev, stats, qstats);
+
+	ret = sxe2_vsi_hw_stats_get_update(adapter);
+	if (ret)
+		goto end;
+
+	ret = sxe2_vsi_sw_stats_get_update(adapter);
+	if (ret)
+		goto end;
+
+	ret = sxe2_drv_queue_info_get_update(adapter, qstats);
+	if (ret)
+		goto end;
+
+	sxe2_stats_update(adapter);
+
+	stats->ipackets = stats_out->ipackets;
+	stats->ibytes   = stats_out->ibytes;
+	stats->ierrors  = stats_out->ierrors;
+	stats->imissed  = stats_out->imissed;
+	stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;
+
+	stats->opackets = stats_out->opackets;
+	stats->obytes   = stats_out->obytes;
+
+	ret = 0;
+
+end:
+	return ret;
+}
+
+int32_t sxe2_xstats_info_get(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats, uint32_t usr_cnt)
+{
+	uint32_t i      = 0;
+	uint32_t cnt    = 0;
+	int32_t ret    = 0;
+	uint32_t offset = 0;
+	uint32_t xstats_cnt = 0;
+	struct sxe2_adapter    *adapter   = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_vsi        *vsi       = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_vsi_stats  *xstats_out = &vsi->vsi_stats;
+
+	if (rte_eal_process_type() == RTE_PROC_SECONDARY)
+		return sxe2_mp_req_get_xstats(dev, xstats, usr_cnt);
+
+	if (adapter->dev_type == SXE2_DEV_T_VF)
+		xstats_cnt = SXE2_XSTAT_CNT_VF;
+	else
+		xstats_cnt = SXE2_XSTAT_CNT_PF;
+
+	if (usr_cnt < xstats_cnt) {
+		ret = xstats_cnt;
+		PMD_LOG_ERR(DRV, "user usr_cnt:%u less than stats cnt:%u", usr_cnt, ret);
+		goto end;
+	}
+
+	ret = sxe2_vsi_hw_stats_get_update(adapter);
+	if (ret) {
+		ret = xstats_cnt;
+		goto end;
+	}
+
+	ret = sxe2_vsi_sw_stats_get_update(adapter);
+	if (ret) {
+		ret = xstats_cnt;
+		goto end;
+	}
+
+	if (adapter->dev_type == SXE2_DEV_T_VF) {
+		sxe2_stats_update(adapter);
+		for (i = 0; i < xstats_cnt; i++) {
+			(void)sxe2_xstat_vf_offset_get(i, &offset);
+			xstats[cnt].value = *(uint64_t *)(((int8_t *)(&xstats_out->stats)) +
+							  offset);
+			xstats[cnt].id    = cnt;
+			cnt++;
+		}
+	} else {
+		ret = sxe2_mac_hw_stats_get_update(adapter);
+		if (ret) {
+			ret = xstats_cnt;
+			goto end;
+		}
+
+		sxe2_stats_update(adapter);
+
+		for (i = 0; i < xstats_cnt; i++) {
+			(void)sxe2_xstat_pf_offset_get(i, &offset);
+			xstats[cnt].value = *(uint64_t *)(((int8_t *)(&xstats_out->stats)) +
+							  offset);
+			xstats[cnt].id = cnt;
+			cnt++;
+		}
+	}
+	ret = cnt;
+	PMD_LOG_DEBUG(DRV, "usr_cnt:%u stats cnt:%u stats done", usr_cnt, cnt);
+
+end:
+	return ret;
+}
+
+int32_t sxe2_xstats_names_get(__rte_unused struct rte_eth_dev *dev,
+	struct rte_eth_xstat_name *xstats_names,
+	__rte_unused unsigned int usr_cnt)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_stats_field *field = NULL;
+	uint32_t i   = 0;
+	uint32_t cnt = 0;
+	int32_t ret = -1;
+	uint32_t xstats_cnt = 0;
+
+	if (adapter->dev_type == SXE2_DEV_T_VF) {
+		field = sxe2_xstats_field_vf;
+		xstats_cnt = SXE2_XSTAT_CNT_VF;
+	} else {
+		field = sxe2_xstats_field_pf;
+		xstats_cnt = SXE2_XSTAT_CNT_PF;
+	}
+
+	if (!xstats_names) {
+		ret = xstats_cnt;
+		PMD_LOG_DEBUG(DRV, "xstats field size:%u", ret);
+		goto l_out;
+	}
+
+	if (usr_cnt < xstats_cnt) {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "max:%d usr_cnt:%u invalid (err:%d)", xstats_cnt, usr_cnt, ret);
+		goto l_out;
+	}
+
+	for (i = 0; i < xstats_cnt; i++) {
+		(void)strlcpy(xstats_names[cnt].name, field[i].name,
+			      sizeof(xstats_names[cnt].name));
+		cnt++;
+	}
+
+	ret = cnt;
+
+l_out:
+	return ret;
+}
+
+int32_t sxe2_stats_hw_reset(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter    *adapter   = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_vsi        *vsi       = adapter->vsi_ctxt.main_vsi;
+	struct sxe2_rx_queue   *rxq;
+	uint32_t rx_queue_id;
+
+	ret = sxe2_drv_vsi_stats_reset(adapter);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "reset vsi stats failed, ret:%d.", ret);
+		goto l_end;
+	}
+	if (adapter->dev_type != SXE2_DEV_T_VF) {
+		ret = sxe2_drv_mac_stats_reset(adapter);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "reset mac stats failed, ret:%d.", ret);
+			goto l_end;
+		}
+	}
+
+	memset(&vsi->vsi_stats, 0, sizeof(vsi->vsi_stats));
+	for (rx_queue_id = 0; rx_queue_id < dev->data->nb_rx_queues; rx_queue_id++) {
+		rxq = dev->data->rx_queues[rx_queue_id];
+		if (rxq)
+			memset(&rxq->sw_stats, 0, sizeof(rxq->sw_stats));
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_stats_info_reset(struct rte_eth_dev *dev)
+{
+	int32_t ret;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (rte_eal_process_type() == RTE_PROC_SECONDARY)
+		return sxe2_mp_req_reset_stats(dev);
+
+	if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_Q_MAP) {
+		ret = sxe2_drv_mapping_stats_info_clear(dev);
+		if (ret)
+			goto l_end;
+	}
+
+	ret = sxe2_stats_hw_reset(dev);
+	if (ret)
+		goto l_end;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_stats_init(struct rte_eth_dev *dev)
+{
+	PMD_INIT_FUNC_TRACE();
+	int32_t ret;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	ret = sxe2_queue_stats_map_init(dev);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_stats_hw_reset(dev);
+	if (ret)
+		goto l_end;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
+				  uint16_t queue_id, uint8_t pool_idx, uint8_t is_rx)
+{
+	int32_t ret = -1;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+
+	if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_Q_MAP)) {
+		PMD_LOG_ERR(DRV, "VF does not support queue mapping! ");
+		goto l_end;
+	}
+
+	if (is_rx)
+		ret = sxe2_drv_rxq_mapping_set(eth_dev, queue_id, pool_idx);
+	else
+		ret = sxe2_drv_txq_mapping_set(eth_dev, queue_id, pool_idx);
+
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Queue stats mapping failed ! "
+			"queue_id:%u pool_idx:%u", queue_id, pool_idx);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(DRV, "port %u %s queue_id %d stat map to pool[%u] ",
+		     (uint16_t)(eth_dev->data->port_id), is_rx ? "RX" : "TX",
+		     queue_id, pool_idx);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_queue_stats_map_init(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_Q_MAP) {
+		dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
+
+		ret = sxe2_drv_mapping_reset(dev);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "Queue stats mapping init failed !");
+			goto l_end;
+		}
+	}
+
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_stats.h b/drivers/net/sxe2/sxe2_stats.h
new file mode 100644
index 0000000000..64ac2bb11d
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_stats.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_STATS_H__
+#define __SXE2_STATS_H__
+
+#define SXE2_STATS_FIELD_NAME_SIZE  50
+
+struct sxe2_stats_field {
+	char name[SXE2_STATS_FIELD_NAME_SIZE];
+	uint32_t offset;
+};
+
+struct sxe2_adapter;
+
+int32_t sxe2_stats_info_get(struct rte_eth_dev *dev,
+			struct rte_eth_stats *stats,
+			struct eth_queue_stats *qstats);
+
+int32_t sxe2_xstats_info_get(struct rte_eth_dev *dev,
+	struct rte_eth_xstat *xstats, uint32_t usr_cnt);
+
+int32_t sxe2_xstats_names_get(__rte_unused struct rte_eth_dev *dev,
+			  struct rte_eth_xstat_name *xstats_names,
+			  __rte_unused unsigned int usr_cnt);
+
+int32_t sxe2_stats_hw_reset(struct rte_eth_dev *dev);
+
+int32_t sxe2_stats_info_reset(struct rte_eth_dev *dev);
+
+int32_t sxe2_stats_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
+				  uint16_t queue_id, uint8_t pool_idx, uint8_t is_rx);
+
+int32_t sxe2_queue_stats_map_init(struct rte_eth_dev *dev);
+
+#endif
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 06/20] net/sxe2: support TM hierarchy and shaping
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch implements the traffic management ops for example PMD.
It supports a 4-level hierarchy: port, vsi, queue group and queue.

- Support node add/delete and hierarchy commit.
- Support private shaper and rate limiting on each node.

The hardware requires all nodes to be configured before the hierarchy
is committed to the global registers.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/net/sxe2/meson.build     |    1 +
 drivers/net/sxe2/sxe2_cmd_chnl.c |  163 +++++
 drivers/net/sxe2/sxe2_cmd_chnl.h |    6 +
 drivers/net/sxe2/sxe2_drv_cmd.h  |   26 +
 drivers/net/sxe2/sxe2_ethdev.c   |   82 +++
 drivers/net/sxe2/sxe2_ethdev.h   |    5 +
 drivers/net/sxe2/sxe2_tm.c       | 1151 ++++++++++++++++++++++++++++++
 drivers/net/sxe2/sxe2_tm.h       |   76 ++
 drivers/net/sxe2/sxe2_tx.c       |    1 -
 9 files changed, 1510 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/sxe2/sxe2_tm.c
 create mode 100644 drivers/net/sxe2/sxe2_tm.h

diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index da7a690063..f03ea15356 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -63,4 +63,5 @@ sources += files(
         'sxe2_mac.c',
         'sxe2_filter.c',
         'sxe2_rss.c',
+        'sxe2_tm.c',
 )
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index b997e7b044..19323ffcc4 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -230,6 +230,7 @@ static void sxe2_txq_ctxt_cfg_fill(struct sxe2_tx_queue *txq,
 				   struct sxe2_drv_txq_cfg_req *req,
 				   uint16_t txq_cnt)
 {
+	struct sxe2_adapter *adapter = txq->vsi->adapter;
 	struct sxe2_drv_txq_ctxt *ctxt = req->cfg;
 	uint16_t q_idx = 0;
 
@@ -241,6 +242,8 @@ static void sxe2_txq_ctxt_cfg_fill(struct sxe2_tx_queue *txq,
 		ctxt->depth = txq[q_idx].ring_depth;
 		ctxt->dma_addr = txq[q_idx].base_addr;
 		ctxt->queue_id = txq[q_idx].queue_id;
+
+		ctxt->sched_mode = sxe2_sched_mode_get(adapter);
 	}
 }
 
@@ -310,6 +313,7 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
 	req.q_idx = txq->queue_id;
 
 	req.is_enable  = (uint8_t)enable;
+	req.sched_mode = sxe2_sched_mode_get(adapter);
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_TXQ_DISABLE,
 			&req, sizeof(req), NULL, 0);
 
@@ -714,3 +718,162 @@ int32_t sxe2_drv_ptp_gettime(struct sxe2_adapter *adapter, struct sxe2_rx_queue
 	(void)rxq;
 	return 0;
 }
+
+int32_t sxe2_drv_root_tree_alloc(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_tm_res tm_resp;
+	int32_t ret;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_SCHED_ROOT_TREE_ALLOC,
+				 NULL, 0,
+				 &tm_resp, sizeof(tm_resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "add sched root failed, ret:%d", ret);
+		goto l_end;
+	}
+
+	tm_ctxt->root_teid = tm_resp.teid;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_root_tree_release(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_tm_res tm_res = {0};
+	int32_t ret;
+
+	tm_res.teid = adapter->tm_ctxt.root_teid;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_SCHED_ROOT_TREE_RELEASE,
+				 &tm_res, sizeof(tm_res),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "release sched root failed, ret:%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static void sxe2_drv_tm_node_to_info(struct sxe2_adapter *adapter,
+		struct sxe2_tm_node *node, struct sxe2_tm_info *info)
+{
+	uint32_t rate = 0;
+
+	if (node->shaper_profile->profile.committed.rate == UINT64_MAX)
+		rate = UINT32_MAX;
+	else
+		rate = (uint32_t)(node->shaper_profile->profile.committed.rate * 8 / 1000);
+
+	info->committed = rte_cpu_to_le_32(rate);
+
+	if (node->shaper_profile->profile.peak.rate == UINT64_MAX)
+		rate = UINT32_MAX;
+	else
+		rate = (uint32_t)(node->shaper_profile->profile.peak.rate * 8 / 1000);
+
+	info->peak = rte_cpu_to_le_32(rate);
+
+	info->priority = (adapter->tm_ctxt.prio_max - 1 - node->priority);
+
+	info->weight = rte_cpu_to_le_16(node->hw_weight);
+}
+
+static int32_t sxe2_drv_tm_commit_node(struct sxe2_adapter *adapter,
+		struct sxe2_tm_node *tm_node)
+{
+	struct sxe2_drv_cmd_params cmd = { 0 };
+	struct sxe2_tm_add_mid_msg msg_mid = {0};
+	struct sxe2_tm_add_queue_msg msg_queue = {0};
+	struct sxe2_tm_res res = {0};
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret;
+	uint32_t i;
+
+	if (tm_node->type == SXE2_TM_NODE_TYPE_VSIG) {
+		goto l_add;
+	} else if (tm_node->type == SXE2_TM_NODE_TYPE_MID) {
+		sxe2_drv_tm_node_to_info(adapter, tm_node, &msg_mid.info);
+		msg_mid.parent_teid = rte_cpu_to_le_16(tm_node->parent->teid);
+		msg_mid.adj_lvl = adapter->sched_ctxt.adj_lvl;
+
+		sxe2_drv_cmd_params_fill(adapter, &cmd,
+					 SXE2_DRV_CMD_SCHED_TM_ADD_MID_NODE,
+					 &msg_mid, sizeof(msg_mid),
+					 &res, sizeof(res));
+		ret = sxe2_drv_cmd_exec(cdev, &cmd);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "add tm mid node failed, ret:%d", ret);
+			goto l_end;
+		}
+	} else if (tm_node->type == SXE2_TM_NODE_TYPE_QUEUE) {
+		sxe2_drv_tm_node_to_info(adapter, tm_node, &msg_queue.info);
+		msg_queue.parent_teid = rte_cpu_to_le_16(tm_node->parent->teid);
+		msg_queue.queue_id = rte_cpu_to_le_16(tm_node->id);
+		msg_queue.adj_lvl = adapter->sched_ctxt.adj_lvl;
+
+		sxe2_drv_cmd_params_fill(adapter, &cmd,
+					 SXE2_DRV_CMD_SCHED_TM_ADD_QUEUE_NODE,
+					 &msg_queue, sizeof(msg_queue),
+					 &res, sizeof(res));
+		ret = sxe2_drv_cmd_exec(cdev, &cmd);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "add tm queue failed, ret:%d", ret);
+			goto l_end;
+		}
+	} else {
+		PMD_LOG_ERR(DRV, "commit tm node failed, type:%d", tm_node->type);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	tm_node->teid = rte_le_to_cpu_16(res.teid);
+
+l_add:
+	for (i = 0; i < tm_node->child_cnt; i++) {
+		ret = sxe2_drv_tm_commit_node(adapter, tm_node->children[i]);
+		if (ret)
+			goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter)
+{
+	struct sxe2_drv_cmd_params cmd = { 0 };
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_tm_res tm_res = {0};
+	int32_t ret;
+
+	tm_res.teid = adapter->tm_ctxt.root_teid;
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_SCHED_ROOT_CHILDREN_DELETE,
+				 &tm_res, sizeof(tm_res),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "del tm root failed, ret:%d", ret);
+		goto l_end;
+	}
+
+	ret = sxe2_drv_tm_commit_node(adapter, adapter->tm_ctxt.root);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "commit tm node failed, ret:%d", ret);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(DRV, "commit tm success");
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 2546c65a6c..77e689abcd 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -38,6 +38,12 @@ int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
 
 int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
 
+int32_t sxe2_drv_root_tree_release(struct rte_eth_dev *dev);
+
+int32_t sxe2_drv_root_tree_alloc(struct rte_eth_dev *dev);
+
+int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter);
+
 int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
 
 int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 9998f241f0..67c6885cae 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -349,6 +349,32 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_rss_hf_req {
 	uint8_t rsv1[3];
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_res {
+	uint16_t teid;
+	uint8_t rsv[2];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_info {
+	uint32_t committed;
+	uint32_t peak;
+	uint8_t priority;
+	uint8_t reserve;
+	uint16_t weight;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_add_mid_msg {
+	uint16_t parent_teid;
+	uint8_t adj_lvl;
+	struct sxe2_tm_info info;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_tm_add_queue_msg {
+	uint16_t parent_teid;
+	uint16_t queue_id;
+	uint8_t adj_lvl;
+	struct sxe2_tm_info info;
+} __rte_packed_end;
+
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
 	SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 77a2b5b1dc..f98cf367f1 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -130,6 +130,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.reta_query                 = sxe2_dev_rss_reta_query,
 	.rss_hash_update            = sxe2_dev_rss_hash_update,
 	.rss_hash_conf_get          = sxe2_dev_rss_hash_conf_get,
+
+	.tm_ops_get                 = sxe2_tm_ops_get,
 };
 
 static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -575,6 +577,14 @@ static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
 		adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_FC_STATE;
 }
 
+static void sxe2_sw_sched_hw_cap_set(struct sxe2_adapter *adapter,
+				     struct sxe2_txsch_caps *txsch_caps)
+{
+	adapter->sched_ctxt.tm_layers = txsch_caps->layer_cap;
+	adapter->sched_ctxt.root_max_children = txsch_caps->tm_mid_node_num;
+	adapter->sched_ctxt.prio_max = txsch_caps->prio_num;
+}
+
 static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
 {
 	int32_t ret = -1;
@@ -594,6 +604,8 @@ static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
 
 	sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps);
 
+	sxe2_sw_sched_hw_cap_set(adapter, &dev_caps.txsch_caps);
+
 l_end:
 	return ret;
 }
@@ -930,6 +942,68 @@ void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev)
 	adapter->dev_info.dev_data = NULL;
 }
 
+uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter)
+{
+	uint32_t ret_mode = SXE2_SCHED_MODE_INVALID;
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+
+	if (adapter->devargs.high_performance_mode)
+		ret_mode = SXE2_SCHED_MODE_HIGH_PERFORMANCE;
+	else if (tm_ctxt->committed)
+		ret_mode = SXE2_SCHED_MODE_TM;
+	else
+		ret_mode = SXE2_SCHED_MODE_DEFAULT;
+
+	return ret_mode;
+}
+
+static int32_t sxe2_sched_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	adapter->sched_ctxt.adj_lvl = adapter->devargs.sched_layer_mode;
+
+	if (adapter->devargs.high_performance_mode) {
+		PMD_LOG_DEBUG(DRV, "TM feature will be disabled in high-performance mode.");
+		adapter->cap_flags &= ~(SXE2_DEV_CAPS_OFFLOAD_TM);
+	} else {
+		ret = sxe2_tm_init(dev);
+		if (ret)
+			goto l_end;
+
+		ret = sxe2_drv_root_tree_alloc(dev);
+		if (ret)
+			goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_sched_uinit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	if (adapter->devargs.high_performance_mode == 0) {
+		ret = sxe2_tm_uninit(dev);
+		if (ret) {
+			PMD_LOG_ERR(INIT, "Failed to uninit tm, ret=%d", ret);
+			goto l_end;
+		}
+
+		ret = sxe2_drv_root_tree_release(dev);
+		if (ret) {
+			PMD_LOG_ERR(INIT, "Failed to release root tree, ret=%d", ret);
+			goto l_end;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
 static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 			     struct sxe2_dev_kvargs_info *kvargs __rte_unused)
 {
@@ -985,8 +1059,15 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_rss_err;
 	}
 
+	ret = sxe2_sched_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to init sched, ret=%d", ret);
+		goto init_sched_err;
+	}
+
 	goto l_end;
 
+init_sched_err:
 init_rss_err:
 init_eth_err:
 init_dev_info_err:
@@ -1002,6 +1083,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 	(void)sxe2_dev_stop(dev);
 	(void)sxe2_queues_release(dev);
 	(void)sxe2_rss_disable(dev);
+	(void)sxe2_sched_uinit(dev);
 	sxe2_vsi_uninit(dev);
 	sxe2_dev_pci_map_uinit(dev);
 	sxe2_eth_uinit(dev);
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 3aa3799b79..95594fcbde 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -20,6 +20,7 @@
 #include "sxe2_queue.h"
 #include "sxe2_mac.h"
 #include "sxe2_osal.h"
+#include "sxe2_tm.h"
 #include "sxe2_filter.h"
 
 struct sxe2_link_msg {
@@ -309,6 +310,8 @@ struct sxe2_adapter {
 	struct sxe2_rss_context       rss_ctxt;
 	struct sxe2_link_context      link_ctxt;
 	struct sxe2_ptp_context       ptp_ctxt;
+	struct sxe2_sched_hw_cap      sched_ctxt;
+	struct sxe2_tm_context        tm_ctxt;
 	struct sxe2_devargs           devargs;
 	struct sxe2_switchdev_info    switchdev_info;
 	bool                          rule_started;
@@ -332,6 +335,8 @@ void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter,
 			    enum sxe2_pci_map_resource res_type,
 			    uint16_t idx_in_func);
 
+uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter);
+
 struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
 						    enum sxe2_pci_map_resource res_type);
 
diff --git a/drivers/net/sxe2/sxe2_tm.c b/drivers/net/sxe2/sxe2_tm.c
new file mode 100644
index 0000000000..4c4f793cd5
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_tm.c
@@ -0,0 +1,1151 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_ethdev.h>
+#include <rte_tm_driver.h>
+
+#include "sxe2_tm.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_common_log.h"
+#include "sxe2_cmd_chnl.h"
+
+static uint16_t sxe2_tm_level_node_num_get(uint8_t level)
+{
+	uint16_t node_num = 0;
+
+	switch (level) {
+	case 0:
+		node_num = SXE2_TM_1L_NODE_NUM_MAX;
+		break;
+	case 1:
+		node_num = SXE2_TM_2L_NODE_NUM_MAX;
+		break;
+	case 2:
+		node_num = SXE2_TM_3L_NODE_NUM_MAX;
+	break;
+	case 3:
+		node_num = SXE2_TM_4L_NODE_NUM_MAX;
+		break;
+	}
+	return node_num;
+}
+
+static int32_t sxe2_tm_capabilities_get(struct rte_eth_dev *dev,
+			  struct rte_tm_capabilities *cap,
+			  struct rte_tm_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+	uint32_t i;
+
+	if (!cap || !error) {
+		PMD_LOG_ERR(DRV, "sxe2 get tm cap failed, cap or error is NULL.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	error->type = RTE_TM_ERROR_TYPE_NONE;
+	memset(cap, 0, sizeof(struct rte_tm_capabilities));
+
+	for (i = 0; i < adapter->tm_ctxt.tm_layers; i++)
+		cap->n_nodes_max += sxe2_tm_level_node_num_get(i);
+
+	cap->n_levels_max = adapter->tm_ctxt.tm_layers;
+
+	cap->non_leaf_nodes_identical = 1;
+
+	cap->leaf_nodes_identical = 1;
+
+	cap->shaper_n_max = cap->n_nodes_max;
+
+	cap->shaper_private_n_max = cap->n_nodes_max;
+
+	cap->shaper_private_dual_rate_n_max = cap->n_nodes_max;
+
+	cap->shaper_private_rate_min = 0;
+
+	cap->shaper_private_rate_max = 12500000000ull;
+
+	cap->shaper_private_packet_mode_supported = 0;
+	cap->shaper_private_byte_mode_supported = 1;
+
+	cap->shaper_pkt_length_adjust_min = RTE_TM_ETH_FRAMING_OVERHEAD;
+
+	cap->shaper_pkt_length_adjust_max = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	cap->shaper_shared_n_max = 0;
+	cap->shaper_shared_n_nodes_per_shaper_max = 0;
+	cap->shaper_shared_n_shapers_per_node_max = 0;
+	cap->shaper_shared_dual_rate_n_max = 0;
+	cap->shaper_shared_rate_min = 0;
+	cap->shaper_shared_rate_max = 0;
+	cap->shaper_shared_packet_mode_supported = 0;
+	cap->shaper_shared_byte_mode_supported = 0;
+
+	cap->sched_n_children_max = dev->data->nb_tx_queues;
+
+	cap->sched_sp_n_priorities_max = 7;
+
+	cap->sched_wfq_n_children_per_group_max = 1;
+	cap->sched_wfq_n_groups_max = 0;
+	cap->sched_wfq_weight_max = 0;
+	cap->sched_wfq_packet_mode_supported = 0;
+	cap->sched_wfq_byte_mode_supported = 0;
+
+	cap->cman_wred_packet_mode_supported = 0;
+	cap->cman_wred_byte_mode_supported = 0;
+	cap->cman_head_drop_supported = 0;
+	cap->cman_wred_context_n_max = 0;
+	cap->cman_wred_context_private_n_max = 0;
+	cap->cman_wred_context_shared_n_max = 0;
+	cap->cman_wred_context_shared_n_nodes_per_context_max = 0;
+	cap->cman_wred_context_shared_n_contexts_per_node_max = 0;
+
+	cap->dynamic_update_mask = 0;
+
+	cap->stats_mask = 0;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_level_capabilities_get(struct rte_eth_dev *dev,
+		uint32_t level_id, struct rte_tm_level_capabilities *cap,
+		struct rte_tm_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (!cap || !error) {
+		PMD_LOG_ERR(DRV, "sxe2 get tm cap failed, cap or error is NULL.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	if (level_id >= adapter->tm_ctxt.tm_layers) {
+		ret = -EINVAL;
+		error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
+		error->message = "too deep level";
+		goto l_end;
+	}
+
+	cap->n_nodes_max = sxe2_tm_level_node_num_get(level_id);
+
+	cap->non_leaf_nodes_identical = true;
+
+	cap->leaf_nodes_identical = true;
+
+	if (level_id != adapter->tm_ctxt.tm_layers - 1) {
+		cap->n_nodes_nonleaf_max = cap->n_nodes_max;
+		cap->n_nodes_leaf_max = 0;
+
+		cap->nonleaf.shaper_private_supported = true;
+		cap->nonleaf.shaper_private_dual_rate_supported = true;
+		cap->nonleaf.shaper_private_rate_min = 0;
+
+		cap->nonleaf.shaper_private_rate_max = 12500000000ull;
+		cap->nonleaf.shaper_private_packet_mode_supported = 0;
+		cap->nonleaf.shaper_private_byte_mode_supported = 1;
+
+		cap->nonleaf.shaper_shared_n_max = 0;
+		cap->nonleaf.shaper_shared_packet_mode_supported = 0;
+		cap->nonleaf.shaper_shared_byte_mode_supported = 0;
+
+		cap->nonleaf.sched_n_children_max = SXE2_TM_MAX_CHILDREN_COUNT;
+		cap->nonleaf.sched_sp_n_priorities_max = 7;
+
+		cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
+		cap->nonleaf.sched_wfq_n_groups_max = 0;
+		cap->nonleaf.sched_wfq_weight_max = 0;
+		cap->nonleaf.sched_wfq_packet_mode_supported = 0;
+		cap->nonleaf.sched_wfq_byte_mode_supported = 0;
+
+		cap->nonleaf.stats_mask = 0;
+	} else {
+		cap->n_nodes_nonleaf_max = 0;
+		cap->n_nodes_leaf_max = cap->n_nodes_max;
+
+		cap->leaf.shaper_private_supported = true;
+		cap->leaf.shaper_private_dual_rate_supported = true;
+		cap->leaf.shaper_private_rate_min = 0;
+		cap->leaf.shaper_private_rate_max = 12500000000ull;
+		cap->leaf.shaper_private_packet_mode_supported = 0;
+		cap->leaf.shaper_private_byte_mode_supported = 1;
+
+		cap->leaf.shaper_shared_n_max = 0;
+		cap->leaf.shaper_shared_packet_mode_supported = 0;
+		cap->leaf.shaper_shared_byte_mode_supported = 0;
+
+		cap->leaf.cman_head_drop_supported = false;
+		cap->leaf.cman_wred_context_private_supported = false;
+		cap->leaf.cman_wred_context_shared_n_max = 0;
+
+		cap->leaf.stats_mask = 0;
+	}
+
+l_end:
+	return ret;
+}
+
+static struct sxe2_tm_node *sxe2_tm_find_node(struct sxe2_tm_node *parent, uint32_t id)
+{
+	struct sxe2_tm_node *node = NULL;
+	uint32_t i;
+
+	if (parent == NULL || parent->id == id) {
+		node = parent;
+		goto l_end;
+	}
+
+	for (i = 0; i < parent->child_cnt; i++) {
+		node = sxe2_tm_find_node(parent->children[i], id);
+		if (node)
+			goto l_end;
+	}
+
+l_end:
+	return node;
+}
+
+static int32_t sxe2_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
+				      struct rte_tm_node_capabilities *cap,
+				      struct rte_tm_error *error)
+{
+	int32_t ret = -EINVAL;
+	struct sxe2_tm_node *tm_node;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (!cap || !error) {
+		PMD_LOG_ERR(DRV, "sxe2 get tm cap failed, cap or error is NULL.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	if (node_id == RTE_TM_NODE_ID_NULL) {
+		PMD_LOG_ERR(DRV, "invalid node id");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "invalid node id";
+		goto l_end;
+	}
+
+	tm_node = sxe2_tm_find_node(adapter->tm_ctxt.root, node_id);
+	if (!tm_node) {
+		PMD_LOG_ERR(DRV, "no such node");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "no such node";
+		goto l_end;
+	}
+
+	cap->shaper_private_supported = true;
+	cap->shaper_private_dual_rate_supported = true;
+	cap->shaper_private_rate_min = 0;
+	cap->shaper_private_rate_max = 12500000000ull;
+	cap->shaper_private_packet_mode_supported = 0;
+	cap->shaper_private_byte_mode_supported = 1;
+
+	cap->shaper_shared_n_max = 0;
+	cap->shaper_shared_packet_mode_supported = 0;
+	cap->shaper_shared_byte_mode_supported = 0;
+
+	if (tm_node->level == adapter->tm_ctxt.tm_layers - 1) {
+		cap->leaf.cman_head_drop_supported = false;
+		cap->leaf.cman_wred_context_private_supported = false;
+		cap->leaf.cman_wred_context_shared_n_max = 0;
+	} else {
+		cap->nonleaf.sched_n_children_max = SXE2_TM_MAX_CHILDREN_COUNT;
+		cap->nonleaf.sched_sp_n_priorities_max = 7;
+		cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
+		cap->nonleaf.sched_wfq_n_groups_max = 0;
+		cap->nonleaf.sched_wfq_weight_max = 0;
+		cap->nonleaf.sched_wfq_packet_mode_supported = 0;
+		cap->nonleaf.sched_wfq_byte_mode_supported = 0;
+	}
+	cap->stats_mask = 0;
+
+	ret = 0;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_shaper_profile_param_check(const struct rte_tm_shaper_params *profile,
+					      struct rte_tm_error *error)
+{
+	int32_t ret = 0;
+
+	if (profile->committed.size) {
+		PMD_LOG_ERR(DRV, "committed bucket size not supported.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;
+		error->message = "committed bucket size not supported";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (profile->peak.size) {
+		PMD_LOG_ERR(DRV, "peak bucket size not supported.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;
+		error->message = "peak bucket size not supported";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (profile->pkt_length_adjust) {
+		PMD_LOG_ERR(DRV, "packet length adjustment not supported.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;
+		error->message = "packet length adjustment not supported";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (profile->committed.rate > SXE2_HW_RATE_MAX ||
+		profile->committed.rate < SXE2_HW_RATE_MIN) {
+		PMD_LOG_ERR(DRV, "The committed rate limit value is required to be in "
+			"the range [%" PRIu64 ", %" PRIu64 "].",
+			(uint64_t)SXE2_HW_RATE_MIN, (uint64_t)SXE2_HW_RATE_MAX);
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE;
+		error->message = "invalid rate limit: value out of range.";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (profile->peak.rate > SXE2_HW_RATE_MAX ||
+		profile->peak.rate < SXE2_HW_RATE_MIN) {
+		PMD_LOG_ERR(DRV, "The peak rate limit value is required to be in "
+			"the range [%" PRIu64 ", %" PRIu64 "].",
+			(uint64_t)SXE2_HW_RATE_MIN, (uint64_t)SXE2_HW_RATE_MAX);
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE;
+		error->message = "invalid rate limit: value out of range.";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (profile->committed.rate > profile->peak.rate) {
+		PMD_LOG_ERR(DRV, "committed rate can't be greater than peak rate.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE;
+		error->message = "committed rate can't be greater than peak rate.";
+		ret = -EINVAL;
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+static inline struct sxe2_tm_shaper_profile *
+sxe2_tm_shaper_profile_search(struct rte_eth_dev *dev, uint32_t id)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_shaper_profile_list *shaper_profile_list =
+		&adapter->tm_ctxt.profile_list;
+	struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+
+	TAILQ_FOREACH(shaper_profile, shaper_profile_list, node) {
+		if (id == shaper_profile->id)
+			goto l_end;
+	}
+
+	shaper_profile = NULL;
+
+l_end:
+	return shaper_profile;
+}
+
+static int32_t sxe2_tm_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
+				      const struct rte_tm_shaper_params *profile,
+				      struct rte_tm_error *error)
+{
+	int32_t ret = -EINVAL;
+	struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (!profile || !error) {
+		PMD_LOG_ERR(DRV, "Invalid input: profile:0x%p or error:0x%p is null.",
+			profile, error);
+		if (error) {
+			error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+			error->message = "Invalid input: profile or error is null.";
+		}
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	ret = sxe2_tm_shaper_profile_param_check(profile, error);
+	if (ret)
+		goto l_end;
+
+	shaper_profile = sxe2_tm_shaper_profile_search(dev, shaper_profile_id);
+	if (shaper_profile) {
+		PMD_LOG_ERR(DRV, "profile ID exist.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+		error->message = "profile ID exist";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	shaper_profile = rte_zmalloc("sxe2_tm_shaper_profile",
+							sizeof(struct sxe2_tm_shaper_profile), 0);
+	if (!shaper_profile) {
+		PMD_LOG_ERR(DRV, "Alloc shaper_profile memory failed.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "Alloc shaper_profile memory failed";
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	rte_memcpy(&shaper_profile->profile, profile,
+					sizeof(struct rte_tm_shaper_params));
+	shaper_profile->id = shaper_profile_id;
+
+	TAILQ_INSERT_TAIL(&adapter->tm_ctxt.profile_list, shaper_profile, node);
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_shaper_profile_del(struct rte_eth_dev *dev,
+		uint32_t id, struct rte_tm_error *error)
+{
+	int32_t ret = -EINVAL;
+	struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (!error) {
+		PMD_LOG_ERR(DRV, "Error param is null.");
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	shaper_profile = sxe2_tm_shaper_profile_search(dev, id);
+	if (!shaper_profile) {
+		PMD_LOG_ERR(DRV, "profile ID not exist.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+		error->message = "profile ID not exist";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (shaper_profile->ref_cnt) {
+		PMD_LOG_ERR(DRV, "profile in use.");
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
+		error->message = "profile in use";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	TAILQ_REMOVE(&adapter->tm_ctxt.profile_list, shaper_profile, node);
+	rte_free(shaper_profile);
+
+	ret = 0;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_node_param_check(struct rte_eth_dev *dev,
+			uint32_t parent_node_type,
+			uint32_t node_id, uint32_t priority, uint32_t weight,
+			const struct rte_tm_node_params *params,
+			bool is_leaf, struct rte_tm_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	int32_t ret = -EINVAL;
+
+	if (node_id == RTE_TM_NODE_ID_NULL) {
+		PMD_LOG_ERR(DRV, "Invalid node id.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "invalid node id";
+		goto l_end;
+	}
+
+	if (parent_node_type == SXE2_TM_NODE_TYPE_VSIG &&
+			priority >= tm_ctxt->prio_max) {
+		PMD_LOG_ERR(DRV, "Priority should be less than %u.", tm_ctxt->prio_max);
+		error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
+		error->message = "The priority is too high.";
+		goto l_end;
+	}
+
+	if (priority > SXE2_TM_PRIO_MAX) {
+		PMD_LOG_ERR(DRV, "Priority should be less than %u.", SXE2_TM_PRIO_MAX);
+		error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
+		error->message = "The priority is too high.";
+		goto l_end;
+	}
+
+	if (weight > SXE2_TM_WEIGHT_MAX || weight < SXE2_TM_WEIGHT_MIN) {
+		PMD_LOG_ERR(DRV, "Weight must be between 1 and 200.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_WEIGHT;
+		error->message = "weight must be between 1 and 200";
+		goto l_end;
+	}
+
+	if (params->shared_shaper_id) {
+		PMD_LOG_ERR(DRV, "Shared shaper not supported.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;
+		error->message = "shared shaper not supported";
+		goto l_end;
+	}
+	if (params->n_shared_shapers) {
+		PMD_LOG_ERR(DRV, "Shared shaper not supported..");
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;
+		error->message = "shared shaper not supported";
+		goto l_end;
+	}
+
+	if (!is_leaf) {
+		if (node_id <= dev->data->nb_tx_queues) {
+			PMD_LOG_ERR(DRV, "no leaf node id must bigger than queue id.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+			error->message = "no leaf node id must bigger than queue id.";
+			goto l_end;
+		}
+
+		if (params->nonleaf.wfq_weight_mode) {
+			PMD_LOG_ERR(DRV, "WFQ not supported.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
+			error->message = "WFQ not supported";
+			goto l_end;
+		}
+
+		if (params->nonleaf.n_sp_priorities != 1) {
+			PMD_LOG_ERR(DRV, "SP priority not supported.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;
+			error->message = "SP priority not supported";
+			goto l_end;
+		}
+	} else {
+		if (node_id >= dev->data->nb_tx_queues) {
+			PMD_LOG_ERR(DRV, "leaf node id must be queue id.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+			error->message = "leaf node id must be queue id.";
+			goto l_end;
+		}
+
+		if (params->leaf.cman) {
+			PMD_LOG_ERR(DRV, "Congestion management not supported.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;
+			error->message = "Congestion management not supported";
+			goto l_end;
+		}
+		if (params->leaf.wred.wred_profile_id != RTE_TM_WRED_PROFILE_ID_NONE) {
+			PMD_LOG_ERR(DRV, "WRED not supported.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;
+			error->message = "WRED not supported";
+			goto l_end;
+		}
+		if (params->leaf.wred.shared_wred_context_id) {
+			PMD_LOG_ERR(DRV, "WRED not supported.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;
+			error->message = "WRED not supported";
+			goto l_end;
+		}
+		if (params->leaf.wred.n_shared_wred_contexts) {
+			PMD_LOG_ERR(DRV, "WRED not supported.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;
+			error->message = "WRED not supported";
+			goto l_end;
+		}
+	}
+	ret = 0;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_add_child(struct sxe2_tm_node *parent,
+		struct sxe2_tm_node *child)
+{
+	int32_t ret = -1;
+	uint32_t i;
+	for (i = 0; i < SXE2_TM_MAX_CHILDREN_COUNT; i++) {
+		if (parent->children[i] == NULL) {
+			parent->children[i] = child;
+			child->index_in_parent = i;
+			parent->child_cnt++;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int32_t sxe2_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id, uint32_t parent_node_id,
+			    uint32_t priority, uint32_t weight, uint32_t level_id,
+			    const struct rte_tm_node_params *params,
+			    struct rte_tm_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	struct sxe2_tm_node *tm_node = NULL;
+	struct sxe2_tm_node *parent_node = NULL;
+	int32_t ret = -EINVAL;
+	bool is_leaf;
+
+	if (!params || !error) {
+		PMD_LOG_ERR(DRV, "Invalid input: params:0x%p or error:0x%p is null.",
+			params, error);
+		if (error) {
+			error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+			error->message = "Invalid input: params or error is null.";
+		}
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	shaper_profile = sxe2_tm_shaper_profile_search(dev, params->shaper_profile_id);
+	if (!shaper_profile) {
+		PMD_LOG_ERR(DRV, "Shaper profile does not exist.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
+		error->message = "shaper profile does not exist";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (parent_node_id == RTE_TM_NODE_ID_NULL) {
+		if (level_id != 0) {
+			PMD_LOG_ERR(DRV, "Wrong level, root node (NULL parent) must be at level 0.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+			error->message = "Wrong level, root node (NULL parent) must be at level 0";
+			ret = -EINVAL;
+			goto l_end;
+		}
+
+		if (tm_ctxt->root) {
+			PMD_LOG_ERR(DRV, "Already have a root.");
+			error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
+			error->message = "already have a root";
+			ret = -EINVAL;
+			goto l_end;
+		}
+
+		ret = sxe2_tm_node_param_check(dev, SXE2_TM_NODE_TYPE_INVALID, node_id, priority,
+					       weight, params, false, error);
+		if (ret)
+			goto l_end;
+
+		tm_node = rte_zmalloc("tm_node_root", sizeof(struct sxe2_tm_node), 0);
+		if (!tm_node) {
+			PMD_LOG_ERR(DRV, "Alloc tm_node memory failed.");
+			error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+			error->message = "Alloc tm_node memory failed";
+			ret = -ENOMEM;
+			goto l_end;
+		}
+
+		tm_node->id = node_id;
+		tm_node->level = 0;
+		tm_node->parent = NULL;
+		tm_node->child_cnt = 0;
+		tm_node->weight = weight;
+		tm_node->hw_weight = SXE2_TM_WEIGHT_SUM;
+		tm_node->type = SXE2_TM_NODE_TYPE_VSIG;
+		tm_node->priority = priority;
+		tm_node->shaper_profile = shaper_profile;
+
+		tm_node->teid = tm_ctxt->root_teid;
+
+		shaper_profile->ref_cnt++;
+		tm_ctxt->root = tm_node;
+		ret = 0;
+		goto l_end;
+	}
+
+	parent_node = sxe2_tm_find_node(tm_ctxt->root, parent_node_id);
+	if (!parent_node) {
+		PMD_LOG_ERR(DRV, "Parent not exist.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
+		error->message = "parent not exist";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (parent_node->child_cnt >= SXE2_TM_MAX_CHILDREN_COUNT ||
+		(parent_node->type == SXE2_TM_NODE_TYPE_VSIG &&
+		 parent_node->child_cnt >= tm_ctxt->root_max_children)) {
+		PMD_LOG_ERR(DRV, "Parent node is full.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+		error->message = "parent node is full";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (level_id == RTE_TM_NODE_LEVEL_ID_ANY) {
+		level_id = parent_node->level + 1;
+	} else if (level_id != parent_node->level + 1) {
+		PMD_LOG_ERR(DRV, "Wrong level.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+		error->message = "Wrong level";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (level_id >= tm_ctxt->tm_layers) {
+		PMD_LOG_ERR(DRV, "The maximum number of TM configuration levels is %d",
+				tm_ctxt->tm_layers);
+		error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
+		error->message = "TM level exceeds supported hardware limit";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (level_id + 1 == tm_ctxt->tm_layers)
+		is_leaf = true;
+	else
+		is_leaf = false;
+
+	ret = sxe2_tm_node_param_check(dev, parent_node->type, node_id, priority, weight,
+				       params, is_leaf, error);
+	if (ret)
+		goto l_end;
+
+	if (sxe2_tm_find_node(tm_ctxt->root, node_id)) {
+		PMD_LOG_ERR(DRV, "Node id already used.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "node id already used";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	tm_node = rte_zmalloc("tm_node_no_root", sizeof(struct sxe2_tm_node), 0);
+	if (!tm_node) {
+		PMD_LOG_ERR(DRV, "Alloc tm_node memory failed.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "Alloc tm_node memory failed";
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	if (level_id + 1 != tm_ctxt->tm_layers)
+		tm_node->type = SXE2_TM_NODE_TYPE_MID;
+	else
+		tm_node->type = SXE2_TM_NODE_TYPE_QUEUE;
+	tm_node->id = node_id;
+	tm_node->level = level_id;
+	tm_node->parent = parent_node;
+	tm_node->child_cnt = 0;
+	tm_node->weight = weight;
+	tm_node->priority = priority;
+	tm_node->shaper_profile = shaper_profile;
+	shaper_profile->ref_cnt++;
+
+	ret = sxe2_tm_add_child(parent_node, tm_node);
+	if (ret) {
+		shaper_profile->ref_cnt--;
+		rte_free(tm_node);
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_tree_delete(struct sxe2_tm_node *tm_node)
+{
+	int32_t ret = 0;
+	uint32_t i, j;
+	struct sxe2_tm_node *parent = NULL;
+
+	if (!tm_node)
+		goto l_end;
+
+	parent = tm_node->parent;
+
+	if (tm_node->child_cnt != 0) {
+		for (i = SXE2_TM_MAX_CHILDREN_COUNT; i > 0; i--) {
+			if (tm_node->children[i - 1])
+				ret = sxe2_tm_tree_delete(tm_node->children[i - 1]);
+		}
+	}
+
+	if (tm_node->shaper_profile)
+		tm_node->shaper_profile->ref_cnt--;
+
+	if (tm_node->type != SXE2_TM_NODE_TYPE_VSIG && parent) {
+		for (i = 0; i < parent->child_cnt; i++) {
+			if (parent->children[i] == tm_node)
+				break;
+		}
+		for (j = i; j < parent->child_cnt - 1; j++)
+			parent->children[j] = parent->children[j + 1];
+
+		parent->children[parent->child_cnt - 1] = NULL;
+		parent->child_cnt--;
+	}
+	rte_free(tm_node);
+	tm_node = NULL;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
+		struct rte_tm_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	struct sxe2_tm_node *tm_node = NULL;
+	int32_t ret = -EINVAL;
+
+	if (!error) {
+		PMD_LOG_ERR(DRV, "Invalid input: error is null.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	if (node_id == RTE_TM_NODE_ID_NULL) {
+		PMD_LOG_ERR(DRV, "Invalid node id. node_id = %u", node_id);
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "invalid node id";
+		goto l_end;
+	}
+
+	tm_node = sxe2_tm_find_node(tm_ctxt->root, node_id);
+	if (!tm_node) {
+		PMD_LOG_ERR(DRV, "No such node.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "no such node";
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_tm_tree_delete(tm_node);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Delete node failed.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "Delete node failed";
+		goto l_end;
+	}
+
+	if (tm_node == tm_ctxt->root)
+		tm_ctxt->root = NULL;
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_node_type_get(struct rte_eth_dev *dev, uint32_t node_id,
+		int32_t *is_leaf, struct rte_tm_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	struct sxe2_tm_node *tm_node = NULL;
+	int32_t ret = -EINVAL;
+
+	if (!is_leaf || !error) {
+		PMD_LOG_ERR(DRV, "Invalid input: is_leaf:0x%p or error:0x%p is null.",
+			is_leaf, error);
+		if (error) {
+			error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+			error->message = "Invalid input: is_leaf or error is null";
+		}
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_end;
+	}
+
+	if (node_id == RTE_TM_NODE_ID_NULL) {
+		PMD_LOG_ERR(DRV, "Invalid node id.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "invalid node id";
+		goto l_end;
+	}
+
+	tm_node = sxe2_tm_find_node(tm_ctxt->root, node_id);
+	if (!tm_node) {
+		PMD_LOG_ERR(DRV, "No such node.");
+		error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+		error->message = "no such node";
+		goto l_end;
+	}
+
+	if (tm_node->level + 1 == tm_ctxt->tm_layers)
+		*is_leaf = true;
+	else
+		*is_leaf = false;
+	ret = 0;
+l_end:
+	return ret;
+}
+
+int32_t sxe2_tm_uninit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+	int32_t ret = 0;
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		ret = 0;
+		goto l_end;
+	}
+
+	tm_ctxt->tm_layers = 0;
+	tm_ctxt->root_max_children = 0;
+	tm_ctxt->committed = false;
+
+	(void)sxe2_tm_tree_delete(tm_ctxt->root);
+
+	while ((shaper_profile = TAILQ_FIRST(&tm_ctxt->profile_list))) {
+		TAILQ_REMOVE(&tm_ctxt->profile_list, shaper_profile, node);
+		rte_free(shaper_profile);
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_tm_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_sched_hw_cap *sched_ctxt = &adapter->sched_ctxt;
+	struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt;
+	int32_t ret = 0;
+	struct sxe2_tm_shaper_profile *shaper_profile = NULL;
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0)
+		goto l_end;
+
+	tm_ctxt->tm_layers = sched_ctxt->tm_layers;
+	tm_ctxt->root_max_children = sched_ctxt->root_max_children;
+	tm_ctxt->prio_max = sched_ctxt->prio_max;
+	tm_ctxt->committed = false;
+	TAILQ_INIT(&tm_ctxt->profile_list);
+	tm_ctxt->root = NULL;
+
+	shaper_profile = rte_zmalloc("sxe2_tm_shaper_profile",
+		sizeof(struct sxe2_tm_shaper_profile), 0);
+	if (!shaper_profile) {
+		PMD_LOG_ERR(DRV, "Alloc shaper_profile memory failed.");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	shaper_profile->id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	shaper_profile->ref_cnt = 1;
+	shaper_profile->profile.committed.rate = UINT64_MAX;
+	shaper_profile->profile.peak.rate = UINT64_MAX;
+	TAILQ_INSERT_TAIL(&tm_ctxt->profile_list, shaper_profile, node);
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_chk_all_leaf(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+	uint32_t i = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		if (!sxe2_tm_find_node(adapter->tm_ctxt.root, i)) {
+			ret = -1;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int32_t sxe2_tm_weight_calc(struct sxe2_tm_node *tm_node)
+{
+	int32_t ret = 0;
+	int32_t total_weight = 0;
+	int32_t total_weight2 = 0;
+	uint32_t i = 0;
+	uint32_t j = 0;
+	uint32_t k = 0;
+	uint32_t maxindex = 0;
+	uint32_t maxweight = 0;
+	struct sxe2_tm_node *cacl_node[SXE2_TM_MAX_CHILDREN_COUNT] = {NULL};
+
+	if (!tm_node) {
+		PMD_LOG_ERR(DRV, "Invalid input: tm_node is null.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (tm_node->child_cnt == 0)
+		goto l_end;
+
+	for (j = SXE2_TM_PRIO_MIN; j <= SXE2_TM_PRIO_MAX; j++) {
+		k = 0;
+		total_weight = 0;
+		total_weight2 = 0;
+		maxindex = 0;
+		maxweight = 0;
+
+		for (i = 0; i < tm_node->child_cnt; i++) {
+			if (tm_node->children[i]->priority == j)
+				cacl_node[k++] = tm_node->children[i];
+		}
+		if (k == 0)
+			continue;
+
+		for (i = 0; i < k; i++)
+			total_weight += cacl_node[i]->weight;
+
+		for (i = 0; i < k; i++) {
+			cacl_node[i]->hw_weight = cacl_node[i]->weight *
+				SXE2_TM_WEIGHT_SUM / total_weight;
+			total_weight2 += cacl_node[i]->hw_weight;
+			if (cacl_node[i]->hw_weight > maxweight) {
+				maxweight = cacl_node[i]->hw_weight;
+				maxindex = i;
+			}
+		}
+
+		cacl_node[maxindex]->hw_weight += SXE2_TM_WEIGHT_SUM - total_weight2;
+	}
+
+	for (i = 0; i < tm_node->child_cnt; i++) {
+		ret = sxe2_tm_weight_calc(tm_node->children[i]);
+		if (ret)
+			goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_tm_hierarchy_commit(struct rte_eth_dev *dev,
+				     int32_t clear_on_fail, struct rte_tm_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = -EINVAL;
+
+	if (!error) {
+		PMD_LOG_ERR(DRV, "Invalid input: error is null.");
+		ret = -EINVAL;
+		goto l_clear_on_fail;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) == 0) {
+		PMD_LOG_ERR(DRV, "The TM capability is not supported.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The TM capability is not supported.";
+		ret = ENOTSUP;
+		goto l_clear_on_fail;
+	}
+
+	if (dev->data->dev_started) {
+		PMD_LOG_ERR(DRV, "Device failed to Stop.");
+		error->message = "Device failed to Stop";
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		ret = -EPERM;
+		goto l_clear_on_fail;
+	}
+
+	ret = sxe2_tm_chk_all_leaf(dev);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "All tx queues need config.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "All tx queues need config.";
+		goto l_clear_on_fail;
+	}
+
+	ret = sxe2_tm_weight_calc(adapter->tm_ctxt.root);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "The weight in tree is wrong.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "The weight in tree is wrong.";
+		goto l_clear_on_fail;
+	}
+
+	ret = sxe2_drv_tm_commit(adapter);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Commit tree to fw failed.");
+		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
+		error->message = "Commit tree to fw failed.";
+		goto l_clear_on_fail;
+	}
+
+	adapter->tm_ctxt.committed = true;
+	ret = 0;
+	goto l_end;
+
+l_clear_on_fail:
+	if (clear_on_fail) {
+		(void)sxe2_tm_uninit(dev);
+		(void)sxe2_tm_init(dev);
+	}
+
+l_end:
+	return ret;
+}
+
+static const struct rte_tm_ops sxe2_tm_ops = {
+	.capabilities_get = sxe2_tm_capabilities_get,
+	.level_capabilities_get = sxe2_level_capabilities_get,
+	.node_capabilities_get = sxe2_node_capabilities_get,
+	.shaper_profile_add = sxe2_tm_shaper_profile_add,
+	.shaper_profile_delete = sxe2_tm_shaper_profile_del,
+	.node_add = sxe2_tm_node_add,
+	.node_delete = sxe2_tm_node_delete,
+	.node_type_get = sxe2_tm_node_type_get,
+
+	.hierarchy_commit = sxe2_tm_hierarchy_commit,
+};
+
+int32_t sxe2_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
+{
+	int32_t ret = 0;
+
+	if (!arg) {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "%s failed because arg is NULL", __func__);
+		goto l_end;
+	}
+	*(const void **)arg = &sxe2_tm_ops;
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_tm.h b/drivers/net/sxe2/sxe2_tm.h
new file mode 100644
index 0000000000..c4f8da6a8e
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_tm.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_TM_H__
+#define __SXE2_TM_H__
+#include <ethdev_driver.h>
+#include <rte_flow_driver.h>
+#include "sxe2_osal.h"
+
+#define SXE2_TM_MAX_LEVEL 7
+#define SXE2_TM_1L_NODE_NUM_MAX 1
+#define SXE2_TM_2L_NODE_NUM_MAX 8
+#define SXE2_TM_3L_NODE_NUM_MAX 64
+#define SXE2_TM_4L_NODE_NUM_MAX 256
+
+#define SXE2_TM_MAX_CHILDREN_COUNT 8
+
+#define SXE2_TM_WEIGHT_MAX  (200)
+#define SXE2_TM_WEIGHT_MIN  (1)
+#define SXE2_TM_WEIGHT_SUM  (32768)
+
+#define SXE2_HW_RATE_MIN 62500ull
+#define SXE2_HW_RATE_MAX 12500000000ull
+
+#define SXE2_TM_PRIO_MAX (7)
+#define SXE2_TM_PRIO_MIN (0)
+
+enum sxe2_tm_node_type {
+	SXE2_TM_NODE_TYPE_VSIG = 0,
+	SXE2_TM_NODE_TYPE_MID,
+	SXE2_TM_NODE_TYPE_QUEUE,
+	SXE2_TM_NODE_TYPE_INVALID,
+};
+
+struct sxe2_tm_shaper_profile {
+	TAILQ_ENTRY(sxe2_tm_shaper_profile) node;
+	uint32_t id;
+	uint32_t ref_cnt;
+	struct rte_tm_shaper_params profile;
+};
+
+TAILQ_HEAD(sxe2_shaper_profile_list, sxe2_tm_shaper_profile);
+
+struct sxe2_tm_node {
+	uint16_t id;
+	uint16_t teid;
+	uint32_t level;
+	uint32_t child_cnt;
+	uint32_t type;
+	uint16_t hw_weight;
+	uint16_t weight;
+	uint8_t priority;
+	struct sxe2_tm_node *parent;
+	uint8_t index_in_parent;
+	struct sxe2_tm_node *children[SXE2_TM_MAX_CHILDREN_COUNT];
+	struct sxe2_tm_shaper_profile *shaper_profile;
+};
+
+struct sxe2_tm_context {
+	uint32_t tm_layers;
+	uint16_t root_teid;
+	uint8_t root_max_children;
+	uint8_t prio_max;
+	bool committed;
+	struct sxe2_tm_node *root;
+	struct sxe2_shaper_profile_list profile_list;
+};
+
+int32_t sxe2_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg);
+
+int32_t sxe2_tm_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_tm_uninit(struct rte_eth_dev *dev);
+
+#endif /* __SXE2_TM_H__ */
diff --git a/drivers/net/sxe2/sxe2_tx.c b/drivers/net/sxe2/sxe2_tx.c
index a05beb8c7a..a280edc9c5 100644
--- a/drivers/net/sxe2/sxe2_tx.c
+++ b/drivers/net/sxe2/sxe2_tx.c
@@ -304,7 +304,6 @@ int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev *dev,
 	}
 
 	offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
-
 	txq = sxe2_tx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
 	if (txq == NULL) {
 		PMD_LOG_ERR(TX, "failed to alloc sxe2vf tx queue:%u resource", queue_idx);
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 09/20] drivers: interrupt handling
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch includes:
- MSI-X vector allocation and mapping logic.
- Support for rx_queue_intr_enable and rx_queue_intr_disable ops.
- Interrupt handler to process admin and queue events.
- Integration with EAL interrupt framework.

RX queue interrupts allow applications to use rte_eth_dev_rx_intr_wait()
for power-efficient packet processing.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_ioctl_chnl.c      | 176 +++-
 drivers/common/sxe2/sxe2_ioctl_chnl_func.h |  18 +
 drivers/net/sxe2/meson.build               |   1 +
 drivers/net/sxe2/sxe2_cmd_chnl.c           |  42 +
 drivers/net/sxe2/sxe2_cmd_chnl.h           |   4 +
 drivers/net/sxe2/sxe2_drv_cmd.h            |   8 +
 drivers/net/sxe2/sxe2_ethdev.c             |  93 +-
 drivers/net/sxe2/sxe2_ethdev.h             |   6 +
 drivers/net/sxe2/sxe2_irq.c                | 942 +++++++++++++++++++++
 drivers/net/sxe2/sxe2_irq.h                |  21 +
 drivers/net/sxe2/sxe2vf_regs.h             |  85 ++
 11 files changed, 1393 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/sxe2/sxe2_irq.c
 create mode 100644 drivers/net/sxe2/sxe2vf_regs.h

diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.c b/drivers/common/sxe2/sxe2_ioctl_chnl.c
index 51aea327e5..173d8d57ae 100644
--- a/drivers/common/sxe2/sxe2_ioctl_chnl.c
+++ b/drivers/common/sxe2/sxe2_ioctl_chnl.c
@@ -67,6 +67,7 @@ sxe2_drv_cmd_exec(struct sxe2_common_device *cdev,
 	return ret;
 }
 
+
 RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_open)
 int32_t
 sxe2_drv_dev_open(struct sxe2_common_device *cdev, struct rte_pci_device *pci_dev)
@@ -87,7 +88,7 @@ sxe2_drv_dev_open(struct sxe2_common_device *cdev, struct rte_pci_device *pci_de
 	if (fd < 0) {
 		ret = -EBADF;
 		PMD_LOG_ERR(COM, "Fail to open device:%s, ret=%d, err:%s",
-				drv_name, ret, strerror(errno));
+			    drv_name, ret, strerror(errno));
 		goto l_end;
 	}
 
@@ -159,6 +160,177 @@ sxe2_drv_dev_handshake(struct sxe2_common_device *cdev)
 	return ret;
 }
 
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_rxq_irq_set)
+int32_t
+sxe2_drv_dev_rxq_irq_set(struct sxe2_common_device *cdev,
+		       uint16_t base_irq, int32_t *efd, uint16_t nb_irq)
+{
+	struct sxe2_ioctl_irq_set cmd_params;
+	int32_t ret = 0;
+	int32_t cmd_fd = 0;
+
+	if (cdev->config.kernel_reset) {
+		ret = -EPERM;
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_end;
+	}
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		ret = -EBADF;
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(COM, "Open fd=%d to set rxq irq, base_queue=%d, efds=%p, nb_irq=%d",
+		cmd_fd, base_irq, efd, nb_irq);
+
+	memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_irq_set));
+	cmd_params.base_irq_in_com = base_irq;
+	cmd_params.cnt = nb_irq;
+	cmd_params.event_fd = efd;
+
+	pthread_mutex_lock(&cdev->config.lock);
+	ret = ioctl(cmd_fd, SXE2_COM_CMD_IO_IRQS_REQ, &cmd_params);
+	if (ret < 0) {
+		PMD_LOG_ERR(COM, "Failed to set io irqs, fd=%d, ret=%d, err:%s",
+			    cmd_fd, ret, strerror(errno));
+		pthread_mutex_unlock(&cdev->config.lock);
+		goto l_end;
+	}
+	pthread_mutex_unlock(&cdev->config.lock);
+
+l_end:
+	return ret;
+}
+
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_other_irq_set)
+int32_t
+sxe2_drv_dev_other_irq_set(struct sxe2_common_device *cdev,
+			int32_t efd, uint64_t event)
+{
+	int32_t ret = 0;
+	int32_t cmd_fd = 0;
+	struct sxe2_ioctl_other_evt_set cmd_params;
+
+	if (cdev->config.kernel_reset) {
+		ret = -EPERM;
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_end;
+	}
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		ret = -EBADF;
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(COM, "Open fd=%d to set other irq, efd=%d, event=%"PRIu64"",
+		cmd_fd, efd, event);
+
+	memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_other_evt_set));
+	cmd_params.eventfd = efd;
+	cmd_params.filter_table = event;
+
+	pthread_mutex_lock(&cdev->config.lock);
+	ret = ioctl(cmd_fd, SXE2_COM_CMD_EVT_IRQ_REQ, &cmd_params);
+	if (ret < 0) {
+		PMD_LOG_ERR(COM, "Failed to set others evt, fd=%d, ret=%d, err:%s",
+			   cmd_fd, ret, strerror(errno));
+		ret = -EIO;
+		pthread_mutex_unlock(&cdev->config.lock);
+		goto l_end;
+	}
+	pthread_mutex_unlock(&cdev->config.lock);
+
+l_end:
+	return ret;
+}
+
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_other_irq_get)
+int32_t
+sxe2_drv_dev_other_irq_get(struct sxe2_common_device *cdev, uint64_t *event)
+{
+	int32_t ret = 0;
+	int32_t cmd_fd = 0;
+	struct sxe2_ioctl_other_evt_get cmd_params;
+
+	if (cdev->config.kernel_reset) {
+		ret = -EPERM;
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_end;
+	}
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		ret = -EBADF;
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(COM, "Open fd=%d to get other irq", cmd_fd);
+
+	memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_other_evt_get));
+
+	pthread_mutex_lock(&cdev->config.lock);
+	ret = ioctl(cmd_fd, SXE2_COM_CMD_EVT_CAUSE_GET, &cmd_params);
+	if (ret < 0) {
+		PMD_LOG_ERR(COM, "Failed to set others evt, fd=%d, ret=%d, err:%s",
+			   cmd_fd, ret, strerror(errno));
+		ret = -EIO;
+		pthread_mutex_unlock(&cdev->config.lock);
+		goto l_end;
+	}
+	pthread_mutex_unlock(&cdev->config.lock);
+	*event = cmd_params.evt_cause;
+
+l_end:
+	return ret;
+}
+
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_reset_irq_set)
+int32_t
+sxe2_drv_dev_reset_irq_set(struct sxe2_common_device *cdev, int32_t efd)
+{
+	int32_t ret = 0;
+	int32_t cmd_fd = 0;
+	struct sxe2_ioctl_reset_sub_set cmd_params;
+
+	if (cdev->config.kernel_reset) {
+		ret = -EPERM;
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_end;
+	}
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		ret = -EBADF;
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(COM, "Open fd=%d to set reset irq, efd=%d",
+		cmd_fd, efd);
+
+	memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_reset_sub_set));
+	cmd_params.eventfd = efd;
+
+	pthread_mutex_lock(&cdev->config.lock);
+	ret = ioctl(cmd_fd, SXE2_COM_CMD_RST_IRQ_REQ, &cmd_params);
+	if (ret < 0) {
+		PMD_LOG_ERR(COM, "Failed to set reset irqs, fd=%d, ret=%d, err:%s",
+			   cmd_fd, ret, strerror(errno));
+		ret = -EIO;
+		pthread_mutex_unlock(&cdev->config.lock);
+		goto l_end;
+	}
+	pthread_mutex_unlock(&cdev->config.lock);
+
+l_end:
+	return ret;
+}
+
 RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_mmap)
 void
 *sxe2_drv_dev_mmap(struct sxe2_common_device *cdev, uint8_t bar_idx, uint64_t len, uint64_t offset)
@@ -223,7 +395,7 @@ sxe2_drv_dev_munmap(struct sxe2_common_device *cdev, void *virt, uint64_t len)
 RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_dma_map)
 int32_t
 sxe2_drv_dev_dma_map(struct sxe2_common_device *cdev, uint64_t vaddr,
-			uint64_t iova, uint64_t size)
+		     uint64_t iova, uint64_t size)
 {
 	struct sxe2_ioctl_iommu_dma_map cmd_params;
 	enum rte_iova_mode iova_mode;
diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h
index e5d8cad1e0..368be16d4f 100644
--- a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h
+++ b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h
@@ -29,6 +29,7 @@ int32_t
 sxe2_drv_dev_open(struct sxe2_common_device *cdev,
 		struct rte_pci_device *pci_dev);
 
+
 __rte_internal
 void
 sxe2_drv_dev_close(struct sxe2_common_device *cdev);
@@ -37,6 +38,23 @@ __rte_internal
 int32_t
 sxe2_drv_dev_handshake(struct sxe2_common_device *cdev);
 
+__rte_internal
+int32_t
+sxe2_drv_dev_rxq_irq_set(struct sxe2_common_device *cdev, uint16_t base_irq,
+			 int32_t *efd, uint16_t nb_irq);
+
+__rte_internal
+int32_t
+sxe2_drv_dev_other_irq_set(struct sxe2_common_device *cdev, int32_t efd, uint64_t event);
+
+__rte_internal
+int32_t
+sxe2_drv_dev_other_irq_get(struct sxe2_common_device *cdev, uint64_t *event);
+
+__rte_internal
+int32_t
+sxe2_drv_dev_reset_irq_set(struct sxe2_common_device *cdev, int32_t fd);
+
 __rte_internal
 void
 *sxe2_drv_dev_mmap(struct sxe2_common_device *cdev, uint8_t bar_idx,
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 8c8f16863e..fc4466556b 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -68,4 +68,5 @@ sources += files(
         'sxe2_security.c',
         'sxe2_mp.c',
         'sxe2_stats.c',
+        'sxe2_irq.c',
 )
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index a1fc8a50e3..d1f15084ed 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -348,6 +348,48 @@ int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+int32_t sxe2_drv_rxq_bind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx, uint16_t msix_idx)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_queue_irq_bind_req req = {0};
+	int32_t ret = 0;
+
+	req.msix_idx = msix_idx;
+	req.q_idx = rxq_idx;
+	req.itr_idx = 0;
+	req.bind = true;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_EVT_IRQ_BAND_RXQ,
+				 &req, sizeof(req),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "rxq bind irq failed, ret=%d", ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_rxq_unbind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_queue_irq_bind_req req = {0};
+	int32_t ret = 0;
+
+	req.bind = false;
+	req.q_idx = rxq_idx;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_EVT_IRQ_BAND_RXQ,
+				 &req, sizeof(req),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "rxq unbind irq failed, ret=%d", ret);
+
+	return ret;
+}
+
 int32_t sxe2_drv_get_mac_stats(struct sxe2_adapter *adapter)
 {
 	int32_t ret = 0;
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 80ad10ac00..3eb30078e1 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -118,4 +118,8 @@ int32_t sxe2_drv_rss_hf_clear(struct sxe2_adapter *adapter);
 
 int32_t sxe2_drv_ptp_gettime(struct sxe2_adapter *adapter, struct sxe2_rx_queue *rxq);
 
+int32_t sxe2_drv_rxq_bind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx, uint16_t msix_idx);
+
+int32_t sxe2_drv_rxq_unbind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx);
+
 #endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 7935a28dc1..807edfc4d6 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -556,6 +556,14 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_tx_map_req {
 	uint8_t pool_idx;
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_queue_irq_bind_req {
+	uint16_t q_idx;
+	uint16_t msix_idx;
+	uint8_t itr_idx;
+	uint8_t bind;
+	uint8_t rsv[2];
+} __rte_packed_end;
+
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
 	SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 46c6c993bf..07d67321c9 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -22,6 +22,7 @@
 #include <rte_eal_paging.h>
 
 #include "sxe2_ethdev.h"
+#include "sxe2_irq.h"
 #include "sxe2_drv_cmd.h"
 #include "sxe2_cmd_chnl.h"
 #include "sxe2_tx.h"
@@ -107,6 +108,9 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.rx_queue_release           = sxe2_rx_queue_release,
 	.tx_queue_setup             = sxe2_tx_queue_setup,
 	.tx_queue_release           = sxe2_tx_queue_release,
+	.rx_queue_intr_enable       = sxe2_rx_queue_intr_enable,
+	.rx_queue_intr_disable      = sxe2_rx_queue_intr_disable,
+
 	.rxq_info_get               = sxe2_rx_queue_info_get,
 	.txq_info_get               = sxe2_tx_queue_info_get,
 	.rx_burst_mode_get          = sxe2_rx_burst_mode_get,
@@ -177,6 +181,8 @@ static int32_t sxe2_dev_stop(struct rte_eth_dev *dev)
 	if (adapter->started == 0)
 		goto l_end;
 
+	sxe2_rxq_intr_disable(dev);
+
 	sxe2_txqs_all_stop(dev);
 	sxe2_rxqs_all_stop(dev);
 
@@ -215,6 +221,12 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
 		goto l_end;
 	}
 
+	ret = sxe2_rxq_intr_enable(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to enable rx queue intr");
+		goto l_rxq_intr_err;
+	}
+
 	ret = sxe2_queues_start(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "enable queues failed");
@@ -224,7 +236,10 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
 	dev->data->dev_started = 1;
 	adapter->started = 1;
 	goto l_end;
+
 l_start_queues_err:
+	(void)sxe2_rxq_intr_disable(dev);
+l_rxq_intr_err:
 	(void)sxe2_filter_rule_stop(dev);
 l_end:
 	return ret;
@@ -615,6 +630,8 @@ static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
 
 	sxe2_sw_queue_ctx_hw_cap_set(adapter, &dev_caps.queue_caps);
 
+	sxe2_sw_irq_ctx_hw_cap_set(adapter, &dev_caps.msix_caps);
+
 	sxe2_sw_rss_ctx_hw_cap_set(adapter, &dev_caps.rss_hash_caps);
 
 	sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps);
@@ -636,6 +653,41 @@ static int32_t sxe2_dev_caps_get(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+uint32_t sxe2_pci_map_read_reg(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type, uint16_t idx_in_func)
+{
+	void *reg_addr;
+	uint32_t value;
+
+	reg_addr = sxe2_pci_map_addr_get(adapter, res_type, idx_in_func);
+	if (unlikely(reg_addr == NULL)) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "reg addr:0x%p is error.", reg_addr);
+		value = SXE2_PCI_MAP_INVALID_VAL;
+		goto l_ret;
+	}
+
+	value = SXE2_PCI_REG_READ(reg_addr);
+
+l_ret:
+	return value;
+}
+
+void sxe2_pci_map_write_reg(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type, uint16_t idx_in_func, uint32_t value)
+{
+	void *reg_addr;
+
+	reg_addr = sxe2_pci_map_addr_get(adapter, res_type, idx_in_func);
+	if (unlikely(reg_addr == NULL)) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "reg addr:0x%p is error.", reg_addr);
+		goto l_ret;
+	}
+
+	SXE2_PCI_REG_WRITE_WC(reg_addr, value);
+l_ret:
+	return;
+}
+
 int32_t sxe2_dev_pci_seg_map(struct sxe2_adapter *adapter,
 			     enum sxe2_pci_map_resource res_type,
 			     uint64_t org_len,
@@ -715,6 +767,27 @@ static int32_t sxe2_hw_init(struct rte_eth_dev *dev)
 	return ret;
 }
 
+static int32_t sxe2_sw_init(struct rte_eth_dev *dev)
+{
+	int32_t ret = -1;
+
+	PMD_INIT_FUNC_TRACE();
+
+	ret = sxe2_sw_irq_ctxt_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to sw irq ctxt init, ret=[%d]", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static void sxe2_sw_uninit(struct rte_eth_dev *dev)
+{
+	sxe2_sw_irq_ctxt_uninit(dev);
+}
+
 int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter,
 				 uint32_t res_type,
 				 uint32_t item_cnt,
@@ -1065,6 +1138,18 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_dev_info_err;
 	}
 
+	ret = sxe2_sw_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret);
+		goto init_sw_err;
+	}
+
+	ret = sxe2_intr_init(dev);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to initialize interrupt, ret:%d", ret);
+		goto init_irq_err;
+	}
+
 	ret = sxe2_eth_init(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "Failed to initialize eth parameters, ret=%d", ret);
@@ -1109,6 +1194,10 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 init_rss_err:
 	sxe2_security_uinit(dev);
 init_security_err:
+	sxe2_intr_uninit(dev);
+init_irq_err:
+	sxe2_sw_uninit(dev);
+init_sw_err:
 	sxe2_eth_uinit(dev);
 init_eth_err:
 init_dev_info_err:
@@ -1132,8 +1221,10 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 	(void)sxe2_sched_uinit(dev);
 	sxe2_vsi_uninit(dev);
 	sxe2_security_uinit(dev);
-	sxe2_dev_pci_map_uinit(dev);
+	sxe2_intr_uninit(dev);
+	sxe2_sw_uninit(dev);
 	sxe2_eth_uinit(dev);
+	sxe2_dev_pci_map_uinit(dev);
 
 l_end:
 	return 0;
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index fed8ce37d9..263d407587 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -352,6 +352,12 @@ int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter,
 				 uint32_t item_cnt,
 				 uint32_t item_base);
 
+void sxe2_pci_map_write_reg(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type, uint16_t idx_in_func, uint32_t value);
+
+uint32_t sxe2_pci_map_read_reg(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type, uint16_t idx_in_func);
+
 void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
 
 int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c
new file mode 100644
index 0000000000..fd9cd4b1ff
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_irq.c
@@ -0,0 +1,942 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <stdint.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <ethdev_pci.h>
+#include <ethdev_driver.h>
+#include <rte_alarm.h>
+#include <fcntl.h>
+#include <rte_stdatomic.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_irq.h"
+#include "sxe2_common_log.h"
+#include "sxe2_queue.h"
+#include "sxe2_drv_cmd.h"
+#include "sxe2_ioctl_chnl_func.h"
+#include "sxe2vf_regs.h"
+#include "sxe2_host_regs.h"
+#include "sxe2_cmd_chnl.h"
+
+#define SXE2_INT_EVENT_OICR_ALL (SXE2_PF_INT_OICR_SWINT | \
+					SXE2_PF_INT_OICR_LAN_TX_ERR | \
+					SXE2_PF_INT_OICR_LAN_RX_ERR | \
+					SXE2_PF_INT_OICR_FW)
+
+#define MAX_EVENT_PENDING (16)
+
+struct sxe2_event_element {
+	TAILQ_ENTRY(sxe2_event_element) next;
+	struct rte_eth_dev *dev;
+};
+
+struct sxe2_event_handler {
+	RTE_ATOMIC(uint16_t)ndev;
+	rte_thread_t tid;
+	int32_t fd[2];
+	rte_spinlock_t  lock;
+	TAILQ_HEAD(event_list, sxe2_event_element) pending;
+};
+static struct sxe2_event_handler event_handler = {
+	.fd = {-1, -1},
+};
+
+static RTE_ATOMIC(uint32_t)event_thread_run;
+
+
+static void sxe2_event_irq_common_handler(struct sxe2_adapter *adapter, uint64_t oicr)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[adapter->dev_info.dev_data->port_id];
+
+	if (oicr & RTE_BIT32(SXE2_COM_EC_LINK_CHG)) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "OICR=%" PRIu64, oicr);
+		(void)sxe2_drv_mac_link_status_get(adapter);
+		if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+			rte_eth_dev_callback_process(dev,
+						     RTE_ETH_EVENT_INTR_LSC,
+						     NULL);
+	}
+}
+
+static uint32_t sxe2_event_intr_handle(void *param __rte_unused)
+{
+	struct sxe2_event_handler *handler = &event_handler;
+	struct sxe2_adapter *adapter;
+	struct sxe2_event_element *pos;
+	struct sxe2_event_element *tmp;
+	int32_t ret = 0;
+	uint64_t oicr = 0;
+	TAILQ_HEAD(event_list, sxe2_event_element) pending;
+	int8_t unused[MAX_EVENT_PENDING];
+	ssize_t nr;
+
+	while (rte_atomic_load_explicit(&event_thread_run, rte_memory_order_relaxed)) {
+		nr = read(handler->fd[0], &unused, sizeof(unused));
+		if (nr <= 0)
+			break;
+
+		rte_spinlock_lock(&handler->lock);
+		TAILQ_INIT(&pending);
+		TAILQ_CONCAT(&pending, &handler->pending, next);
+		rte_spinlock_unlock(&handler->lock);
+
+		TAILQ_FOREACH_SAFE(pos, &pending, next, tmp) {
+			TAILQ_REMOVE(&pending, pos, next);
+			adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(pos->dev);
+
+			ret = sxe2_drv_dev_other_irq_get(adapter->cdev, &oicr);
+			sxe2_event_irq_common_handler(adapter, oicr);
+
+			rte_free(pos);
+		}
+	}
+
+	return ret;
+}
+
+static int32_t sxe2_event_intr_handler_init(void)
+{
+	struct sxe2_event_handler *handler = &event_handler;
+	int32_t ret = 0;
+	int err = 0;
+
+	PMD_INIT_FUNC_TRACE();
+	if (rte_atomic_fetch_add_explicit(&handler->ndev, 1, rte_memory_order_acq_rel) >= 1) {
+		ret = 0;
+		PMD_LOG_DEBUG(INIT, "%s: ndev > 1", __func__);
+		goto l_end;
+	}
+
+#if defined(RTE_EXEC_ENV_IS_WINDOWS) && RTE_EXEC_ENV_IS_WINDOWS != 0
+	err = _pipe(handler->fd, MAX_EVENT_PENDING, O_BINARY);
+#else
+	err = pipe(handler->fd);
+#endif
+	if (err != 0) {
+		ret = -ECHILD;
+		rte_atomic_fetch_sub_explicit(&handler->ndev, 1, rte_memory_order_release);
+		PMD_LOG_ERR(INIT, "%s: pipe failed", __func__);
+		goto l_end;
+	}
+
+	rte_atomic_store_explicit(&event_thread_run, 1, rte_memory_order_relaxed);
+
+	TAILQ_INIT(&handler->pending);
+	rte_spinlock_init(&handler->lock);
+
+	if (rte_thread_create_internal_control(&handler->tid, "sxe2-event",
+				sxe2_event_intr_handle, NULL)) {
+		PMD_LOG_ERR(INIT, "%s: thread create failed", __func__);
+		rte_atomic_fetch_sub_explicit(&handler->ndev, 1, rte_memory_order_release);
+		ret = -ECHILD;
+		goto l_end;
+	}
+	ret = 0;
+l_end:
+	return ret;
+}
+
+static void sxe2_event_intr_handler_uinit(void)
+{
+	struct sxe2_event_handler *handler = &event_handler;
+	struct sxe2_event_element *pos;
+	struct sxe2_event_element *tmp;
+	ssize_t nw = 0;
+	int8_t notify_byte = 0;
+
+	PMD_INIT_FUNC_TRACE();
+	if (rte_atomic_fetch_sub_explicit(&handler->ndev, 1, rte_memory_order_acq_rel) > 1) {
+		PMD_LOG_DEBUG(INIT, "event handler uinit, ndev > 0");
+		return;
+	}
+
+	rte_atomic_store_explicit(&event_thread_run, 0, rte_memory_order_relaxed);
+	nw = write(handler->fd[1], &notify_byte, 1);
+	RTE_SET_USED(nw);
+
+	(void)rte_thread_join(handler->tid, NULL);
+
+	if (handler->fd[0] != -1) {
+		close(handler->fd[0]);
+		handler->fd[0] = -1;
+	}
+	if (handler->fd[1] != -1) {
+		close(handler->fd[1]);
+		handler->fd[1] = -1;
+	}
+
+	rte_spinlock_lock(&handler->lock);
+	TAILQ_FOREACH_SAFE(pos, &handler->pending, next, tmp) {
+		TAILQ_REMOVE(&handler->pending, pos, next);
+		rte_free(pos);
+	}
+	rte_spinlock_unlock(&handler->lock);
+}
+
+static void sxe2_event_intr_post(struct rte_eth_dev *dev)
+{
+	struct sxe2_event_handler *handler = &event_handler;
+	struct sxe2_event_element *elem = rte_malloc(NULL, sizeof(struct sxe2_event_element), 0);
+	int8_t notify_byte = 0;
+	ssize_t nw = 0;
+
+	if (!elem)
+		goto l_end;
+
+	elem->dev = dev;
+
+	rte_spinlock_lock(&handler->lock);
+	TAILQ_INSERT_TAIL(&handler->pending, elem, next);
+	rte_spinlock_unlock(&handler->lock);
+
+	nw = write(handler->fd[1], &notify_byte, 1);
+	RTE_SET_USED(nw);
+
+l_end:
+	return;
+}
+
+static void sxe2_interrupt_handler_other(void *arg)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)arg;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t eventfd = adapter->irq_ctxt.other_event_fd;
+	int32_t ret = 0;
+	uint64_t buf = 0;
+
+	ret = read(eventfd, &buf, sizeof(buf));
+	if (ret != sizeof(buf)) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "read eventfd[%d] failed, ret:%d, errno:%d.",
+				eventfd, ret, errno);
+	}
+
+	sxe2_event_intr_post(dev);
+}
+
+static void sxe2_interrupt_handler_reset(void *arg)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)arg;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t resetfd = adapter->irq_ctxt.reset_event_fd;
+	int32_t ret = 0;
+	uint64_t buf = 0;
+
+	ret = read(resetfd, &buf, sizeof(buf));
+	if (ret != sizeof(buf)) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "read resetfd[%d] failed, ret:%d, errno:%d.",
+				resetfd, ret, errno);
+	}
+
+	sxe2_drv_cmd_close(adapter->cdev);
+
+	rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RMV, NULL);
+}
+
+int32_t sxe2_sw_irq_ctxt_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	int32_t ret = 0;
+
+	irq_ctxt->rxq_avail_cnt = irq_ctxt->max_cnt_hw;
+	irq_ctxt->rxq_base_idx_in_pf = irq_ctxt->base_idx_in_func;
+	irq_ctxt->reset_event_fd = -1;
+	irq_ctxt->other_event_fd = -1;
+
+	return ret;
+}
+
+void sxe2_sw_irq_ctxt_uninit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	memset(&adapter->irq_ctxt, 0, sizeof(adapter->irq_ctxt));
+	adapter->irq_ctxt.reset_event_fd = -1;
+	adapter->irq_ctxt.other_event_fd = -1;
+}
+
+void sxe2_sw_irq_ctx_hw_cap_set(struct sxe2_adapter *adapter,
+				struct sxe2_drv_msix_caps *msix_caps)
+{
+	adapter->irq_ctxt.max_cnt_hw = msix_caps->msix_vectors_cnt;
+	adapter->irq_ctxt.base_idx_in_func = msix_caps->base_idx_in_func;
+}
+
+static int32_t sxe2_intr_handler_cfg(struct rte_intr_handle *handle,
+		int32_t fd, rte_intr_callback_fn cb, void *cb_arg)
+{
+	int32_t ret = 0;
+
+	ret = rte_intr_fd_set(handle, fd);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to set intr_handle->fd, error %i (%s)",
+			errno, strerror(errno));
+		goto err;
+	}
+
+	ret = rte_intr_type_set(handle, RTE_INTR_HANDLE_EXT);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to set intr_handle->type, error %i (%s)",
+			errno, strerror(errno));
+		goto err;
+	}
+
+	ret = rte_intr_callback_register(handle, cb, cb_arg);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize register intr callback, ret=%d", ret);
+		goto err;
+	}
+err:
+	return ret;
+}
+
+static struct rte_intr_handle *
+sxe2_intr_handler_create(int32_t fd, rte_intr_callback_fn cb, void *cb_arg)
+{
+	struct rte_intr_handle *tmp_intr_handle = NULL;
+	int32_t ret = 0;
+
+	tmp_intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+	if (!tmp_intr_handle) {
+		PMD_LOG_ERR(INIT, "Failed to alloc memory for intr_handler, error %i (%s)",
+			errno, strerror(errno));
+		goto err;
+	}
+
+	ret = rte_intr_fd_set(tmp_intr_handle, fd);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to set intr_handle->fd, error %i (%s)",
+				errno, strerror(errno));
+		goto err;
+	}
+
+	ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to set intr_handle->type, error %i (%s)",
+				errno, strerror(errno));
+		goto err;
+	}
+
+	ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize register intr callback, ret=%d", ret);
+		goto err;
+	}
+
+	return tmp_intr_handle;
+err:
+	rte_intr_instance_free(tmp_intr_handle);
+	return NULL;
+}
+
+static void sxe2_intr_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	if (!intr_handle)
+		return;
+
+	if (rte_intr_fd_get(intr_handle) >= 0)
+		(void)rte_intr_callback_unregister(intr_handle, cb, cb_arg);
+	rte_intr_instance_free(intr_handle);
+}
+
+static int32_t sxe2_event_intr_fd_create(void)
+{
+	int32_t fd = 0;
+
+	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+	if (fd < 0) {
+		PMD_LOG_ERR(INIT, "Can't setup eventfd, error %i (%s)",
+			errno, strerror(errno));
+		goto err;
+	}
+
+	return fd;
+err:
+	return -EBADF;
+}
+
+static void sxe2_event_intr_fd_destroy(int32_t fd)
+{
+	if (fd >= 0)
+		close(fd);
+}
+
+static int32_t sxe2_other_intr_register(struct rte_eth_dev *dev, int32_t fd)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+	uint64_t event = RTE_BIT32(SXE2_COM_EC_LINK_CHG) |
+				RTE_BIT32(SXE2_COM_SW_MODE_LEGACY) |
+				RTE_BIT32(SXE2_COM_SW_MODE_SWITCHDEV) |
+				RTE_BIT32(SXE2_COM_FC_ST_CHANGE);
+
+	ret = sxe2_drv_dev_other_irq_set(adapter->cdev, fd, event);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set other irq, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static void sxe2_other_intr_unregister(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	ret = sxe2_drv_dev_other_irq_set(adapter->cdev, -1, 0);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set other irq, ret=%d", ret);
+}
+
+static int32_t sxe2_reset_intr_register(struct rte_eth_dev *dev, int32_t fd)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	ret = sxe2_drv_dev_reset_irq_set(adapter->cdev, fd);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set reset irq, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static void sxe2_reset_intr_unregister(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	ret = sxe2_drv_dev_reset_irq_set(adapter->cdev, -1);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set reset irq, ret=%d", ret);
+}
+
+int32_t sxe2_intr_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_pci_device *pci_dev = SXE2_DEV_TO_PCI(dev);
+	struct rte_intr_handle *reset_handle = NULL;
+	int32_t ofd = -1;
+	int32_t rfd = -1;
+	int32_t ret = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	ofd = sxe2_event_intr_fd_create();
+	if (ofd < 0) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create event intr fd");
+		ret = -EBADF;
+		goto l_end;
+	}
+
+	ret = sxe2_intr_handler_cfg(pci_dev->intr_handle,
+			ofd, sxe2_interrupt_handler_other, dev);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create intr handler");
+		goto l_err_create_other_handler;
+	}
+
+	ret = sxe2_event_intr_handler_init();
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Event handler init failed, ret=%d", ret);
+		goto l_err_event_intr_handler_init;
+	}
+
+	ret = sxe2_other_intr_register(dev, ofd);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to register other intr, ret=%d", ret);
+		goto l_err_register_other_intr;
+	}
+	adapter->irq_ctxt.other_event_fd = ofd;
+
+	rfd = sxe2_event_intr_fd_create();
+	if (rfd < 0) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create event intr fd");
+		ret = -EBADF;
+		goto l_err_create_reset_fd;
+	}
+
+	reset_handle = sxe2_intr_handler_create(rfd, sxe2_interrupt_handler_reset, dev);
+	if (!reset_handle) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to create intr handler");
+		ret = -ENOMEM;
+		goto l_err_create_reset_handler;
+	}
+	adapter->irq_ctxt.reset_handle = reset_handle;
+
+	ret = sxe2_reset_intr_register(dev, rfd);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to register reset intr, ret=%d", ret);
+		goto l_err_register_reset_intr;
+	}
+	adapter->irq_ctxt.reset_event_fd = rfd;
+
+	goto l_end;
+l_err_register_reset_intr:
+	sxe2_intr_handler_destroy(reset_handle, sxe2_interrupt_handler_reset, dev);
+	adapter->irq_ctxt.reset_handle = NULL;
+l_err_create_reset_handler:
+	sxe2_event_intr_fd_destroy(rfd);
+l_err_create_reset_fd:
+	sxe2_other_intr_unregister(dev);
+	adapter->irq_ctxt.other_event_fd = -1;
+l_err_register_other_intr:
+	sxe2_event_intr_handler_uinit();
+l_err_event_intr_handler_init:
+	sxe2_intr_handler_destroy(pci_dev->intr_handle,
+			sxe2_interrupt_handler_other, dev);
+	pci_dev->intr_handle = NULL;
+l_err_create_other_handler:
+	sxe2_event_intr_fd_destroy(ofd);
+l_end:
+	return ret;
+}
+
+void sxe2_intr_uninit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_pci_device *pci_dev = SXE2_DEV_TO_PCI(dev);
+
+	sxe2_reset_intr_unregister(dev);
+	sxe2_intr_handler_destroy(adapter->irq_ctxt.reset_handle,
+				sxe2_interrupt_handler_reset, dev);
+	sxe2_event_intr_fd_destroy(adapter->irq_ctxt.reset_event_fd);
+	sxe2_other_intr_unregister(dev);
+	sxe2_event_intr_handler_uinit();
+	sxe2_intr_handler_destroy(pci_dev->intr_handle,
+				sxe2_interrupt_handler_other, dev);
+	sxe2_event_intr_fd_destroy(adapter->irq_ctxt.other_event_fd);
+
+	adapter->irq_ctxt.other_event_fd = -1;
+	adapter->irq_ctxt.reset_event_fd = -1;
+	pci_dev->intr_handle = NULL;
+	adapter->irq_ctxt.reset_handle = NULL;
+}
+
+static int32_t sxe2_rxq_intr_efd_alloc(struct rte_eth_dev *dev, int32_t *efd)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+	int32_t fd = 0;
+
+	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+	if (fd < 0) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Can't setup eventfd, error %i (%s)",
+			errno, strerror(errno));
+		ret = -EBADF;
+		goto l_end;
+	}
+
+	*efd = fd;
+
+l_end:
+	return ret;
+}
+
+static void sxe2_rxq_intr_efd_free(int32_t efd)
+{
+	close(efd);
+}
+
+static void sxe2_pci_hw_int_itr_set(struct sxe2_adapter *adapter, uint16_t msix_idx, uint16_t itr)
+{
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_ITR, msix_idx, itr);
+}
+
+static void sxe2_pci_hw_irq_disable(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	uint32_t value = (SXE2_ITR_IDX_NONE << SXE2_VF_DYN_CTL_ITR_IDX_S);
+
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx, value);
+}
+
+static void sxe2_pci_hw_irq_enable(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	uint32_t value = SXE2_VF_DYN_CTL_INTENABLE |
+		SXE2_VF_DYN_CTL_CLEARPBA |
+			(SXE2_ITR_IDX_NONE << SXE2_VF_DYN_CTL_ITR_IDX_S);
+
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx, value);
+}
+
+static uint32_t sxe2_pci_hw_irq_dyn_ctl_read(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	return sxe2_pci_map_read_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx);
+}
+
+static void sxe2_pci_hw_msix_disable(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX,
+			irq_idx, SXE2VF_BAR4_MSIX_DISABLE);
+}
+
+static void sxe2_pci_hw_msix_enable(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX,
+			irq_idx, SXE2VF_BAR4_MSIX_ENABLE);
+}
+
+static void sxe2_pci_hw_irq_trigger(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx,
+			(SXE2VF_ITR_IDX_NONE << SXE2VF_DYN_CTL_ITR_IDX_SHIFT) |
+			SXE2VF_DYN_CTL_SWINT_TRIG | SXE2VF_DYN_CTL_INTENABLE_MSK);
+}
+
+static void sxe2_pci_hw_irq_clear_pba(struct sxe2_adapter *adapter, uint16_t irq_idx)
+{
+	sxe2_pci_map_write_reg(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_idx,
+		(SXE2VF_ITR_IDX_NONE << SXE2VF_DYN_CTL_ITR_IDX_SHIFT) |
+		SXE2VF_DYN_CTL_CLEARPBA | SXE2VF_DYN_CTL_INTENABLE_MSK);
+}
+
+static void sxe2_rxq_msix_cfg_unmap(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	uint16_t rxq_cnt = adapter->q_ctxt.qp_cnt_assign;
+	uint16_t i = 0;
+
+	for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++)
+		sxe2_pci_hw_irq_disable(adapter, irq_ctxt->rxq_msix_idx[i]);
+
+	for (i = 0; i < rxq_cnt; i++)
+		(void)sxe2_drv_rxq_unbind_irq(adapter, i);
+}
+
+static int32_t sxe2_rxq_msix_cfg_map(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	int32_t ret = 0;
+	uint32_t val;
+	uint16_t rxq_cnt = dev->data->nb_rx_queues;
+	uint16_t i = 0;
+	uint8_t rx_low_latency = adapter->devargs.rx_low_latency;
+
+	for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) {
+		sxe2_pci_hw_irq_disable(adapter, irq_ctxt->rxq_msix_idx[i]);
+		if (rx_low_latency) {
+			sxe2_pci_hw_int_itr_set(adapter, irq_ctxt->rxq_msix_idx[i],
+					SXE2_ITR_INTERVAL_LOW);
+		} else {
+			sxe2_pci_hw_int_itr_set(adapter, irq_ctxt->rxq_msix_idx[i],
+					SXE2_ITR_INTERVAL_NORMAL);
+		}
+	}
+
+	for (i = 0; i < rxq_cnt; i++) {
+		ret = sxe2_drv_rxq_bind_irq(adapter, i, irq_ctxt->rxq_msix_idx[i]);
+		if (ret != 0) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "RXQ[%u] bind IRQ[%u] failed.",
+				i, irq_ctxt->rxq_msix_idx[i]);
+			goto l_end;
+		}
+	}
+
+	for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++)
+		sxe2_pci_hw_irq_enable(adapter, irq_ctxt->rxq_msix_idx[i]);
+
+	for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) {
+		val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, i);
+		if ((val & SXE2VF_DYN_CTL_INTENABLE) == 0)
+			continue;
+
+		sxe2_pci_hw_msix_disable(adapter, i);
+		sxe2_pci_hw_irq_trigger(adapter, i);
+		val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, i);
+		sxe2_pci_hw_irq_clear_pba(adapter, i);
+		val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, i);
+		sxe2_pci_hw_msix_enable(adapter, i);
+	}
+
+l_end:
+	if (ret != 0)
+		sxe2_rxq_msix_cfg_unmap(dev);
+	return ret;
+}
+
+static int32_t sxe2_rxq_map_msix_intr(struct rte_eth_dev *dev,
+		uint16_t msix_base __rte_unused, uint16_t nb_msix,
+		uint16_t base_queue, uint16_t nb_queue)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	uint32_t *msix_tbl = NULL;
+	int32_t ret = 0;
+	uint16_t i;
+
+	if (!nb_queue || !nb_msix || nb_queue < nb_msix) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Queue num[%u] or msix num[%u] is invalid.",
+				nb_queue, nb_msix);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	msix_tbl = rte_zmalloc(NULL, sizeof(uint32_t) * nb_queue, 0);
+	if (!msix_tbl) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to alloc msix_tbl memory.");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	for (i = 0; i < nb_queue; i++) {
+		msix_tbl[i] = i % nb_msix;
+		PMD_DEV_LOG_INFO(adapter, INIT, "Queue %u is binding to vect %u",
+				base_queue + i, msix_tbl[i]);
+	}
+
+	irq_ctxt->rxq_irq_cnt = nb_msix;
+	irq_ctxt->rxq_msix_idx = msix_tbl;
+
+l_end:
+	return ret;
+}
+
+static void sxe2_rxq_unmap_msix_intr(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+
+	rte_free(irq_ctxt->rxq_msix_idx);
+	irq_ctxt->rxq_msix_idx = NULL;
+	irq_ctxt->rxq_irq_cnt = 0;
+}
+
+static int32_t sxe2_rxq_intr_register(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
+	int32_t *efd_tbl = NULL;
+	uint16_t rxq_cnt = dev->data->nb_rx_queues;
+	uint16_t nb_msix = irq_ctxt->rxq_irq_cnt;
+	uint16_t i;
+	int32_t ret = 0;
+
+	if (rte_intr_type_set(intr_handle, RTE_INTR_HANDLE_EXT)) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set intr_handle->type, error %i (%s)",
+				errno, strerror(errno));
+		ret = -EPERM;
+		goto l_end;
+	}
+
+	efd_tbl = rte_zmalloc(NULL, sizeof(int32_t) * nb_msix, 0);
+	if (!efd_tbl) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to alloc efd_tbl memory.");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	for (i = 0; i < nb_msix; i++) {
+		ret = sxe2_rxq_intr_efd_alloc(dev, &efd_tbl[i]);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Failed to alloc efd_tbl, ret=%d", ret);
+			goto l_free_efd_tbl;
+		}
+	}
+
+	if (rte_intr_vec_list_alloc(intr_handle, "sxe2 rxq int", rxq_cnt)) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to allocate %d rx_queues intr_vec",
+				rxq_cnt);
+		ret = -ENOMEM;
+		goto l_free_efd_tbl;
+	}
+
+	for	(i = 0; i < rxq_cnt; i++) {
+		ret = rte_intr_vec_list_index_set(intr_handle, i,
+				irq_ctxt->rxq_msix_idx[i] + RTE_INTR_VEC_RXTX_OFFSET);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set msix_tbl, ret=%d", ret);
+			goto l_free_efd_tbl;
+		}
+	}
+
+	for (i = 0; i < irq_ctxt->rxq_irq_cnt; i++) {
+		ret = rte_intr_efds_index_set(intr_handle, i, efd_tbl[i]);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set efd_tbl, ret=%d", ret);
+			goto l_free_efd_tbl;
+		}
+	}
+
+	if (rte_intr_nb_efd_set(intr_handle, rxq_cnt)) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Set intr nb efd failed, error %i (%s)",
+			errno, strerror(errno));
+		ret = -EPERM;
+		goto l_free_efd_tbl;
+	}
+
+	ret = sxe2_drv_dev_rxq_irq_set(adapter->cdev, 0, efd_tbl, nb_msix);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set rxq irq, ret=%d", ret);
+		goto l_free_efd_tbl;
+	}
+	irq_ctxt->rxq_event_fd = efd_tbl;
+
+	goto l_end;
+
+l_free_efd_tbl:
+	if (efd_tbl) {
+		for (i = 0; i < nb_msix; i++)
+			if (efd_tbl[i] >= 0)
+				sxe2_rxq_intr_efd_free(efd_tbl[i]);
+		rte_free(efd_tbl);
+	}
+	irq_ctxt->rxq_event_fd = NULL;
+
+	rte_intr_vec_list_free(intr_handle);
+l_end:
+	return ret;
+}
+
+static void sxe2_rxq_intr_unregister(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
+	int32_t efd = -1;
+	uint16_t msix_cnt = irq_ctxt->rxq_irq_cnt;
+	uint16_t i;
+
+	if (irq_ctxt->rxq_event_fd) {
+		for (i = 0; i < msix_cnt; i++) {
+			(void)sxe2_drv_dev_rxq_irq_set(adapter->cdev, i, &efd, 1);
+			sxe2_rxq_intr_efd_free(irq_ctxt->rxq_event_fd[i]);
+		}
+	}
+	rte_free(irq_ctxt->rxq_event_fd);
+	irq_ctxt->rxq_event_fd = NULL;
+
+	rte_intr_vec_list_free(intr_handle);
+
+	rte_intr_nb_efd_set(intr_handle, 0);
+	rte_intr_max_intr_set(intr_handle, 0);
+}
+
+int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	uint16_t msix_vect = adapter->irq_ctxt.rxq_base_idx_in_pf;
+	uint16_t msix_cnt = adapter->irq_ctxt.rxq_avail_cnt;
+	uint16_t rxq_cnt = dev->data->nb_rx_queues;
+	uint16_t rxq_base = adapter->q_ctxt.base_idx_in_pf;
+	int32_t ret = 0;
+
+	if (!rxq_cnt)
+		goto l_end;
+
+	msix_cnt = RTE_MIN(msix_cnt, rxq_cnt);
+
+	ret = sxe2_rxq_map_msix_intr(dev, msix_vect, msix_cnt, rxq_base, rxq_cnt);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to rxq[%d] map msix[%d] intr, cnt=%d, ret=%d",
+					rxq_base, msix_vect, rxq_cnt, ret);
+		goto l_end;
+	}
+
+	if (dev->data->dev_conf.intr_conf.rxq) {
+		ret = sxe2_rxq_intr_register(dev);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Failed to register rxq[%d] intr, ret=%d",
+					rxq_base, ret);
+			goto l_err_unmap;
+		}
+	}
+
+	ret = sxe2_rxq_msix_cfg_map(dev);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to rxq[%d] map msix[%d] intr, ret=%d",
+					rxq_base, msix_vect, ret);
+		goto l_err_unregister;
+	}
+
+	goto l_end;
+l_err_unregister:
+	if (dev->data->dev_conf.intr_conf.rxq)
+		sxe2_rxq_intr_unregister(dev);
+l_err_unmap:
+	sxe2_rxq_unmap_msix_intr(dev);
+l_end:
+	return ret;
+}
+
+void sxe2_rxq_intr_disable(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+
+	if (!irq_ctxt->rxq_irq_cnt)
+		goto l_end;
+
+	sxe2_rxq_msix_cfg_unmap(dev);
+
+	if (dev->data->dev_conf.intr_conf.rxq)
+		sxe2_rxq_intr_unregister(dev);
+
+	sxe2_rxq_unmap_msix_intr(dev);
+
+l_end:
+	return;
+}
+
+int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_irq_context *irq_ctxt = &adapter->irq_ctxt;
+	uint64_t buf;
+	uint16_t irq_idx = irq_ctxt->rxq_msix_idx[queue_id];
+	size_t read_ret;
+
+	read_ret = read(irq_ctxt->rxq_event_fd[irq_idx], &buf, sizeof(buf));
+	(void)read_ret;
+	sxe2_pci_hw_irq_enable(adapter, irq_idx);
+	return 0;
+}
+
+int32_t sxe2_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+	struct sxe2_adapter *adapter =
+		SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	uint32_t val;
+	int32_t ret = 0;
+	uint16_t irq_idx = adapter->irq_ctxt.rxq_msix_idx[queue_id];
+
+	val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, irq_idx);
+	if ((val & SXE2VF_DYN_CTL_INTENABLE) == 0) {
+		PMD_DEV_LOG_DEBUG(adapter, INIT, "rxq [%d] interrupt is disabled.", queue_id);
+		goto l_end;
+	}
+
+	sxe2_pci_hw_msix_disable(adapter, irq_idx);
+	sxe2_pci_hw_irq_trigger(adapter, irq_idx);
+	val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, irq_idx);
+	sxe2_pci_hw_irq_clear_pba(adapter, irq_idx);
+	val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, irq_idx);
+	sxe2_pci_hw_msix_enable(adapter, irq_idx);
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_irq.h b/drivers/net/sxe2/sxe2_irq.h
index 4ca2118b92..31216240e6 100644
--- a/drivers/net/sxe2/sxe2_irq.h
+++ b/drivers/net/sxe2/sxe2_irq.h
@@ -45,4 +45,25 @@ struct sxe2_irq_context {
 	int32_t *rxq_event_fd;
 };
 
+uint32_t sxe2_drv_dev_other_cause_get(struct sxe2_adapter *adapter);
+
+int32_t sxe2_intr_init(struct rte_eth_dev *dev);
+
+void sxe2_intr_uninit(struct rte_eth_dev *dev);
+
+int32_t sxe2_sw_irq_ctxt_init(struct rte_eth_dev *dev);
+
+void sxe2_sw_irq_ctxt_uninit(struct rte_eth_dev *dev);
+
+void sxe2_sw_irq_ctx_hw_cap_set(struct sxe2_adapter *adapter,
+		struct sxe2_drv_msix_caps *msix_caps);
+
+int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev);
+
+void sxe2_rxq_intr_disable(struct rte_eth_dev *dev);
+
+int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+
+int32_t sxe2_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);
+
 #endif /* SXE2_IRQ_H */
diff --git a/drivers/net/sxe2/sxe2vf_regs.h b/drivers/net/sxe2/sxe2vf_regs.h
new file mode 100644
index 0000000000..854f1d3ae8
--- /dev/null
+++ b/drivers/net/sxe2/sxe2vf_regs.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2VF_REGS_H__
+#define __SXE2VF_REGS_H__
+
+#define SXE2VF_MBX_Q_LEN_M      0x3FF
+#define SXE2VF_MBX_Q_LEN_VFE_M  RTE_BIT32(28)
+
+#define SXE2VF_MBX_Q_LEN_OVFL_M RTE_BIT32(29)
+#define SXE2VF_MBX_Q_LEN_CRIT_M RTE_BIT32(30)
+#define SXE2VF_MBX_Q_LEN_ENA_M  RTE_BIT32(31)
+
+#define SXE2VF_MBX_RQ_HEAD      (0x00008000)
+#define SXE2VF_MBX_RQ_TAIL      (0x00008400)
+#define SXE2VF_MBX_RQ_LEN       (0x00007C00)
+#define SXE2VF_MBX_RQ_BAH       (0x00007800)
+#define SXE2VF_MBX_RQ_BAL       (0x00007400)
+
+#define SXE2VF_MBX_TQ_HEAD      (0x00006C00)
+#define SXE2VF_MBX_TQ_TAIL      (0x00007000)
+#define SXE2VF_MBX_TQ_LEN       (0x00006800)
+#define SXE2VF_MBX_TQ_BAH       (0x00006400)
+#define SXE2VF_MBX_TQ_BAL       (0x00006000)
+
+#define SXE2VF_RXQ_TAIL(_QRX)                 (0x2000 + ((_QRX) * 4))
+#define SXE2VF_TXQ_TAIL(_QRX)                 (0x1000 + ((_QRX) * 4))
+
+#define SXE2VF_INT_BASE 0x00002800
+
+#define SXE2VF_DYN_CTL0 (SXE2VF_INT_BASE + 0x0)
+
+#define SXE2VF_DYN_CTL(_idx) (SXE2VF_INT_BASE + 0x4 + ((_idx) * 4))
+#define SXE2VF_VF_DYN_CTL(_idx) (SXE2VF_INT_BASE + ((_idx) * 4))
+
+#define SXE2VF_BAR4_MSIX_BASE 0
+#define SXE2VF_BAR4_MSIX_CTL(_idx) (SXE2VF_BAR4_MSIX_BASE + 0xC + ((_idx) * 0x10))
+#define SXE2VF_BAR4_MSIX_ENABLE 0
+#define SXE2VF_BAR4_MSIX_DISABLE 1
+
+#define SXE2VF_DYN_CTL_INTENABLE RTE_BIT32(0)
+#define SXE2VF_DYN_CTL_CLEARPBA   RTE_BIT32(1)
+#define SXE2VF_DYN_CTL_SWINT_TRIG RTE_BIT32(2)
+#define SXE2VF_DYN_CTL_SW_ITR_IDX_ENABLE RTE_BIT32(24)
+
+#define SXE2VF_DYN_CTL_INTENABLE_MSK \
+	RTE_BIT32(31)
+
+#define SXE2VF_DYN_CTL_ITR_IDX_SHIFT 3
+
+enum sxe2vf_itr_idx {
+	SXE2VF_ITR_IDX_0 = 0,
+	SXE2VF_ITR_IDX_1,
+	SXE2VF_ITR_IDX_2,
+	SXE2VF_ITR_IDX_NONE,
+};
+
+#define SXE2VF_INT_ITR0   (0x00002800 + 65 * 0x4)
+#define SXE2VF_INT_ITR(_i, _irq_idx) (SXE2VF_INT_ITR0 + \
+			0x4 + (_i) * 0x104 + ((_irq_idx) * 4))
+#define SXE2VF_VF_INT_ITR(_itr_idx, _irq_idx) (0x00002800 + \
+			(0x104 * (_itr_idx)) + ((_irq_idx) * 4))
+#define SXE2VF_PFG_INT_CTL_ITR_GRAN_0    (2)
+
+#define SXE2VF_PCIE_SYS_READY              0x38c
+#define SXE2VF_PCIE_SYS_READY_CORER_ASSERT RTE_BIT32(0)
+#define SXE2VF_PCIE_SYS_READY_STOP_DROP_DONE RTE_BIT32(2)
+#define SXE2VF_PCIE_SYS_READY_R5        RTE_BIT32(3)
+#define SXE2VF_PCIE_SYS_READY_STOP_DROP RTE_BIT32(16)
+
+#define SXE2VF_PCIE_DEV_CTRL_DEV_STATUS               0x78
+#define SXE2VF_PCIE_DEV_CTRL_DEV_STATUS_TRANS_PENDING RTE_BIT32(21)
+
+#define SXE2VF_VF_VRC_VFGEN_RSTAT             (0x5800)
+#define SXE2VF_VF_VRC_VFGEN_VFRSTAT           GENMASK(1, 0)
+#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_VFR       (0)
+#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_COMPLETE  (RTE_BIT32(0))
+#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_VF_ACTIVE (RTE_BIT32(1))
+
+#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_FORVF_VFR (1)
+#define SXE2VF_VF_VRC_VFGEN_VFRSTAT_FORVF_MASK \
+	(RTE_BIT32(10))
+
+#endif /* SXE2VF_VF_INT_ITR */
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 05/20] drivers: support RSS feature
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Add support for Receive Side Scaling (RSS) to distribute incoming
traffic across multiple receive queues.

- Implement rss_hash_update and rss_hash_conf_get.
- Implement reta_update and reta_query.
- Support RSS hash configuration for IPv4, IPv6, TCP and UDP.
- Default hash key is initialized during port start.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_flow_public.h | 633 +++++++++++++++++++++++++
 drivers/net/sxe2/meson.build           |   1 +
 drivers/net/sxe2/sxe2_cmd_chnl.c       | 173 +++++++
 drivers/net/sxe2/sxe2_cmd_chnl.h       |  16 +
 drivers/net/sxe2/sxe2_drv_cmd.h        |  29 ++
 drivers/net/sxe2/sxe2_ethdev.c         |  37 ++
 drivers/net/sxe2/sxe2_ethdev.h         |   8 +
 drivers/net/sxe2/sxe2_flow_define.h    | 143 ++++++
 drivers/net/sxe2/sxe2_queue.c          |  11 +
 drivers/net/sxe2/sxe2_rss.c            | 584 +++++++++++++++++++++++
 drivers/net/sxe2/sxe2_rss.h            |  81 ++++
 drivers/net/sxe2/sxe2_txrx.h           |   4 +
 drivers/net/sxe2/sxe2_txrx_poll.c      |  85 +++-
 13 files changed, 1804 insertions(+), 1 deletion(-)
 create mode 100644 drivers/common/sxe2/sxe2_flow_public.h
 create mode 100644 drivers/net/sxe2/sxe2_flow_define.h
 create mode 100644 drivers/net/sxe2/sxe2_rss.c
 create mode 100644 drivers/net/sxe2/sxe2_rss.h

diff --git a/drivers/common/sxe2/sxe2_flow_public.h b/drivers/common/sxe2/sxe2_flow_public.h
new file mode 100644
index 0000000000..32ab2a9713
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_flow_public.h
@@ -0,0 +1,633 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_FLOW_PUBLIC_H__
+#define __SXE2_FLOW_PUBLIC_H__
+#include "sxe2_osal.h"
+
+enum sxe2_flow_type {
+	SXE2_FLOW_TYPE_NONE                               = 0,
+	SXE2_FLOW_MAC_PAY                                 = 1,
+	SXE2_FLOW_MAC_IPV4_FRAG_PAY                       = 22,
+	SXE2_FLOW_MAC_IPV4_PAY                            = 23,
+	SXE2_FLOW_MAC_IPV4_UDP_PAY                        = 24,
+	SXE2_FLOW_MAC_IPV4_TCP_PAY                        = 26,
+	SXE2_FLOW_MAC_IPV4_SCTP_PAY                       = 27,
+	SXE2_FLOW_MAC_IPV4_IPV4_FRAG_PAY                  = 29,
+	SXE2_FLOW_MAC_IPV4_IPV4_PAY                       = 30,
+	SXE2_FLOW_MAC_IPV4_IPV4_UDP_PAY                   = 31,
+	SXE2_FLOW_MAC_IPV4_IPV4_TCP_PAY                   = 33,
+	SXE2_FLOW_MAC_IPV4_IPV4_SCTP_PAY                  = 34,
+	SXE2_FLOW_MAC_IPV4_IPV6_FRAG_PAY                  = 36,
+	SXE2_FLOW_MAC_IPV4_IPV6_PAY                       = 37,
+	SXE2_FLOW_MAC_IPV4_IPV6_UDP_PAY                   = 38,
+	SXE2_FLOW_MAC_IPV4_IPV6_TCP_PAY                   = 40,
+	SXE2_FLOW_MAC_IPV4_IPV6_SCTP_PAY                  = 41,
+	SXE2_FLOW_MAC_IPV4_GRE_PAY                        = 43,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV4_FRAG_PAY              = 44,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV4_PAY                   = 45,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV4_UDP_PAY               = 46,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV4_TCP_PAY               = 48,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV4_SCTP_PAY              = 49,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV6_FRAG_PAY              = 51,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV6_PAY                   = 52,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV6_UDP_PAY               = 53,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV6_TCP_PAY               = 55,
+	SXE2_FLOW_MAC_IPV4_GRE_IPV6_SCTP_PAY              = 56,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_PAY                    = 58,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_FRAG_PAY          = 59,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_PAY               = 60,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_UDP_PAY           = 61,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_TCP_PAY           = 63,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_SCTP_PAY          = 64,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_FRAG_PAY          = 66,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_PAY               = 67,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_UDP_PAY           = 68,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_TCP_PAY           = 70,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_SCTP_PAY          = 71,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_PAY               = 73,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_FRAG_PAY     = 74,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_PAY          = 75,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_UDP_PAY      = 76,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_TCP_PAY      = 78,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_SCTP_PAY     = 79,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_FRAG_PAY     = 81,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_PAY          = 82,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_UDP_PAY      = 83,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_TCP_PAY      = 85,
+	SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_SCTP_PAY     = 86,
+	SXE2_FLOW_MAC_IPV6_FRAG_PAY                       = 88,
+	SXE2_FLOW_MAC_IPV6_PAY                            = 89,
+	SXE2_FLOW_MAC_IPV6_UDP_PAY                        = 90,
+	SXE2_FLOW_MAC_IPV6_TCP_PAY                        = 92,
+	SXE2_FLOW_MAC_IPV6_SCTP_PAY                       = 93,
+	SXE2_FLOW_MAC_IPV6_IPV4_FRAG_PAY                  = 95,
+	SXE2_FLOW_MAC_IPV6_IPV4_PAY                       = 96,
+	SXE2_FLOW_MAC_IPV6_IPV4_UDP_PAY                   = 97,
+	SXE2_FLOW_MAC_IPV6_IPV4_TCP_PAY                   = 99,
+	SXE2_FLOW_MAC_IPV6_IPV4_SCTP_PAY                  = 100,
+	SXE2_FLOW_MAC_IPV6_IPV6_FRAG_PAY                  = 102,
+	SXE2_FLOW_MAC_IPV6_IPV6_PAY                       = 103,
+	SXE2_FLOW_MAC_IPV6_IPV6_UDP_PAY                   = 104,
+	SXE2_FLOW_MAC_IPV6_IPV6_TCP_PAY                   = 106,
+	SXE2_FLOW_MAC_IPV6_IPV6_SCTP_PAY                  = 107,
+	SXE2_FLOW_MAC_IPV6_GRE_PAY                        = 109,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV4_FRAG_PAY              = 110,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV4_PAY                   = 111,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV4_UDP_PAY               = 112,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV4_TCP_PAY               = 114,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV4_SCTP_PAY              = 115,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV6_FRAG_PAY              = 117,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV6_PAY                   = 118,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV6_UDP_PAY               = 119,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV6_TCP_PAY               = 121,
+	SXE2_FLOW_MAC_IPV6_GRE_IPV6_SCTP_PAY              = 122,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_PAY                    = 124,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_FRAG_PAY          = 125,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_PAY               = 126,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_UDP_PAY           = 127,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_TCP_PAY           = 129,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_SCTP_PAY          = 130,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_FRAG_PAY          = 132,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_PAY               = 133,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_UDP_PAY           = 134,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_TCP_PAY           = 136,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_SCTP_PAY          = 137,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_PAY               = 139,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_FRAG_PAY     = 140,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_PAY          = 141,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_UDP_PAY      = 142,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_TCP_PAY      = 144,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_SCTP_PAY     = 145,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_FRAG_PAY     = 147,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_PAY          = 148,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_UDP_PAY      = 149,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_TCP_PAY      = 151,
+	SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_SCTP_PAY     = 152,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_PAY                   = 329,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_PAY                   = 330,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_FRAG_PAY         = 331,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_PAY              = 332,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_UDP_PAY          = 333,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_TCP_PAY          = 334,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_SCTP_PAY         = 335,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_FRAG_PAY         = 336,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_PAY              = 337,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_UDP_PAY          = 338,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_TCP_PAY          = 339,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_SCTP_PAY         = 340,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_FRAG_PAY         = 341,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_PAY              = 342,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_UDP_PAY          = 343,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_TCP_PAY          = 344,
+	SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_SCTP_PAY         = 345,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_FRAG_PAY         = 346,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_PAY              = 347,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_UDP_PAY          = 348,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_TCP_PAY          = 349,
+	SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_SCTP_PAY         = 350,
+	SXE2_FLOW_MAC_IPV6_MAC_PAY                        = 820,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV4_FRAG_PAY              = 821,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV4_PAY                   = 822,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV4_UDP_PAY               = 823,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV4_TCP_PAY               = 824,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV4_SCTP_PAY              = 825,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV6_FRAG_PAY              = 827,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV6_PAY                   = 828,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV6_UDP_PAY               = 829,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV6_TCP_PAY               = 830,
+	SXE2_FLOW_MAC_IPV6_MAC_IPV6_SCTP_PAY              = 831,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_PAY                   = 835,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_FRAG_PAY         = 836,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_PAY              = 837,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_UDP_PAY          = 838,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_TCP_PAY          = 839,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_SCTP_PAY         = 840,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_FRAG_PAY         = 842,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_PAY              = 843,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_UDP_PAY          = 844,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_TCP_PAY          = 845,
+	SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_SCTP_PAY         = 846,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_PAY                  = 878,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_FRAG_PAY        = 877,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_PAY             = 876,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_UDP_PAY         = 879,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_TCP_PAY         = 880,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_SCTP_PAY        = 875,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_FRAG_PAY        = 871,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_PAY             = 870,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_UDP_PAY         = 872,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_TCP_PAY         = 873,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_SCTP_PAY        = 869,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_PAY                  = 891,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_FRAG_PAY        = 890,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_PAY             = 889,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_UDP_PAY         = 892,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_TCP_PAY         = 893,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_SCTP_PAY        = 888,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_FRAG_PAY        = 884,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_PAY             = 883,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_UDP_PAY         = 885,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_TCP_PAY         = 886,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_SCTP_PAY        = 882,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_PAY                    = 904,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_FRAG_PAY          = 903,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_PAY               = 902,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_UDP_PAY           = 905,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_TCP_PAY           = 906,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_SCTP_PAY          = 901,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_FRAG_PAY          = 897,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_PAY               = 896,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_UDP_PAY           = 898,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_TCP_PAY           = 899,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_SCTP_PAY          = 895,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_PAY                    = 917,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_FRAG_PAY          = 916,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_PAY               = 915,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_UDP_PAY           = 918,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_TCP_PAY           = 919,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_SCTP_PAY          = 914,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_FRAG_PAY          = 910,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_PAY               = 909,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_UDP_PAY           = 911,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_TCP_PAY           = 912,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_SCTP_PAY          = 908,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_PAY         = 930,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY = 929,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_PAY    = 928,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY = 931,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY = 932,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY = 927,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY = 923,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_PAY    = 922,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY = 924,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY = 925,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY = 921,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_PAY         = 943,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY = 942,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_PAY    = 941,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY = 944,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY = 945,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY = 940,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY = 936,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_PAY    = 935,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY = 937,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY = 938,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY = 934,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_PAY           = 956,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY = 955,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_PAY      = 954,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY  = 957,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY  = 958,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY = 953,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY = 949,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_PAY      = 948,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY  = 950,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY  = 951,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY = 947,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_PAY           = 969,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY = 968,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_PAY      = 967,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY  = 970,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY  = 971,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY = 966,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY = 962,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_PAY      = 961,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY  = 963,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY  = 964,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY = 960,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_PAY              = 982,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_FRAG_PAY    = 981,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_PAY         = 980,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_UDP_PAY     = 983,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_TCP_PAY     = 984,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_SCTP_PAY    = 979,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_FRAG_PAY    = 975,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_PAY         = 974,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_UDP_PAY     = 976,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_TCP_PAY     = 977,
+	SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_SCTP_PAY    = 973,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_PAY              = 995,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_FRAG_PAY    = 994,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_PAY         = 993,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_UDP_PAY     = 996,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_TCP_PAY     = 997,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_SCTP_PAY    = 992,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_FRAG_PAY    = 988,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_PAY         = 987,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_UDP_PAY     = 989,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_TCP_PAY     = 990,
+	SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_SCTP_PAY    = 986,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_PAY                = 1008,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_FRAG_PAY      = 1007,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_PAY           = 1006,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_UDP_PAY       = 1009,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_TCP_PAY       = 1010,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_SCTP_PAY      = 1005,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_FRAG_PAY      = 1001,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_PAY           = 1000,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_UDP_PAY       = 1002,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_TCP_PAY       = 1003,
+	SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_SCTP_PAY      = 999,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_PAY                = 1021,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_FRAG_PAY      = 1020,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_PAY           = 1019,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_UDP_PAY       = 1022,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_TCP_PAY       = 1023,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_SCTP_PAY      = 1018,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_FRAG_PAY      = 1014,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_PAY           = 1013,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_UDP_PAY       = 1015,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_TCP_PAY       = 1016,
+	SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_SCTP_PAY      = 1012,
+	SXE2_FLOW_TYPE_MAX                                = 2048,
+};
+
+enum sxe2_rss_cfg_hdr_type {
+	SXE2_RSS_OUTER_HEADERS,
+	SXE2_RSS_INNER_HEADERS,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_GRE,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_GRE,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GRE,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GRE,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_VXLAN,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_VXLAN,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GENEVE,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GENEVE,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GTPU,
+
+	SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GTPU,
+	SXE2_RSS_ANY_HEADERS
+};
+
+enum sxe2_flow_hdr {
+	SXE2_FLOW_HDR_ETH = 0,
+	SXE2_FLOW_HDR_VLAN,
+	SXE2_FLOW_HDR_QINQ,
+	SXE2_FLOW_HDR_IPV4,
+	SXE2_FLOW_HDR_IPV6,
+	SXE2_FLOW_HDR_ICMP = 5,
+	SXE2_FLOW_HDR_TCP,
+	SXE2_FLOW_HDR_UDP,
+	SXE2_FLOW_HDR_SCTP,
+	SXE2_FLOW_HDR_GRE,
+	SXE2_FLOW_HDR_VXLAN = 10,
+	SXE2_FLOW_HDR_GENEVE,
+	SXE2_FLOW_HDR_GTPU,
+
+	SXE2_FLOW_HDR_IPV_FRAG,
+
+	SXE2_FLOW_HDR_IPV_OTHER,
+
+	SXE2_FLOW_HDR_ETH_NON_IP = 15,
+	SXE2_FLOW_HDR_MAX = 128,
+};
+
+enum sxe2_flow_fld_id {
+	SXE2_FLOW_FLD_ID_ETH_DA = 0,
+	SXE2_FLOW_FLD_ID_ETH_SA,
+	SXE2_FLOW_FLD_ID_S_TCI,
+	SXE2_FLOW_FLD_ID_C_TCI,
+	SXE2_FLOW_FLD_ID_S_TPID,
+	SXE2_FLOW_FLD_ID_C_TPID = 5,
+	SXE2_FLOW_FLD_ID_S_VID,
+	SXE2_FLOW_FLD_ID_C_VID,
+	SXE2_FLOW_FLD_ID_ETH_TYPE,
+
+	SXE2_FLOW_FLD_ID_IPV4_TOS,
+	SXE2_FLOW_FLD_ID_IPV6_DSCP = 10,
+	SXE2_FLOW_FLD_ID_IPV4_TTL,
+	SXE2_FLOW_FLD_ID_IPV4_PROT,
+	SXE2_FLOW_FLD_ID_IPV6_TTL,
+	SXE2_FLOW_FLD_ID_IPV6_PROT,
+	SXE2_FLOW_FLD_ID_IPV4_SA = 15,
+	SXE2_FLOW_FLD_ID_IPV4_DA,
+	SXE2_FLOW_FLD_ID_IPV6_SA,
+	SXE2_FLOW_FLD_ID_IPV6_DA,
+	SXE2_FLOW_FLD_ID_IPV4_CHKSUM,
+	SXE2_FLOW_FLD_ID_IPV4_ID = 20,
+	SXE2_FLOW_FLD_ID_IPV6_ID,
+	SXE2_FLOW_FLD_ID_IPV6_PRE32_SA,
+	SXE2_FLOW_FLD_ID_IPV6_PRE32_DA,
+	SXE2_FLOW_FLD_ID_IPV6_PRE48_SA,
+	SXE2_FLOW_FLD_ID_IPV6_PRE48_DA = 25,
+	SXE2_FLOW_FLD_ID_IPV6_PRE64_SA,
+	SXE2_FLOW_FLD_ID_IPV6_PRE64_DA,
+
+	SXE2_FLOW_FLD_ID_TCP_SRC_PORT,
+	SXE2_FLOW_FLD_ID_TCP_DST_PORT,
+	SXE2_FLOW_FLD_ID_UDP_SRC_PORT = 30,
+	SXE2_FLOW_FLD_ID_UDP_DST_PORT,
+	SXE2_FLOW_FLD_ID_SCTP_SRC_PORT,
+	SXE2_FLOW_FLD_ID_SCTP_DST_PORT,
+	SXE2_FLOW_FLD_ID_TCP_FLAGS,
+	SXE2_FLOW_FLD_ID_TCP_CHKSUM = 35,
+	SXE2_FLOW_FLD_ID_UDP_CHKSUM,
+	SXE2_FLOW_FLD_ID_SCTP_CHKSUM,
+
+	SXE2_FLOW_FLD_ID_VXLAN_VNI,
+
+	SXE2_FLOW_FLD_ID_GENEVE_VNI,
+
+	SXE2_FLOW_FLD_ID_GTPU_TEID = 40,
+
+	SXE2_FLOW_FLD_ID_NVGRE_TNI,
+
+	SXE2_FLOW_FLD_ID_MAX = 128,
+};
+
+struct sxe2_ether_hdr {
+	uint8_t dst_addr[SXE2_ETH_ALEN];
+	uint8_t src_addr[SXE2_ETH_ALEN];
+	uint16_t  ether_type;
+};
+
+struct sxe2_vlan_hdr {
+	uint16_t  type;
+	uint16_t  vlan;
+};
+
+struct sxe2_ipv4_hdr {
+	uint8_t ver_ihl;
+	uint8_t tos;
+	uint16_t  tot_len;
+	uint16_t  id;
+	uint16_t  frag_off;
+	uint8_t ttl;
+	uint8_t protocol;
+	uint16_t  check;
+	uint32_t saddr;
+	uint32_t daddr;
+};
+#define SXE2_IPV6_ADDR_LENGTH        (16)
+#define SXE2_IPV6_TC_SHIFT (20)
+#define SXE2_IPV6_TC_MASK  (0xFF)
+
+struct sxe2_ipv6_hdr {
+	uint32_t pri_ver_flow;
+	uint16_t  payload_len;
+	uint8_t nexthdr;
+	uint8_t hop_limit;
+	union {
+		uint8_t saddr[16];
+		uint16_t	saddr16[8];
+		uint32_t	saddr32[4];
+	};
+	union {
+		uint8_t daddr[16];
+		uint16_t	daddr16[8];
+		uint32_t	daddr32[4];
+	};
+};
+
+struct sxe2_tcp_hdr {
+	uint16_t  source;
+	uint16_t  dest;
+	uint32_t seq;
+	uint32_t ack_seq;
+	uint16_t  flag;
+	uint16_t  window;
+	uint16_t  check;
+	uint16_t  urg_ptr;
+};
+
+struct sxe2_udp_hdr {
+	uint16_t  source;
+	uint16_t  dest;
+	uint16_t  len;
+	uint16_t  check;
+};
+
+struct sxe2_sctp_hdr {
+	uint16_t src_port;
+	uint16_t dst_port;
+};
+
+struct sxe2_nvgre_hdr {
+	uint16_t flags;
+	uint16_t protocol;
+	uint32_t tni;
+};
+struct sxe2_geneve_hdr {
+	uint16_t flags;
+	uint16_t protocol;
+	uint32_t vni;
+};
+struct sxe2_gtpu_hdr {
+	uint8_t flag;
+	uint8_t msg_type;
+	uint16_t msg_len;
+	uint32_t teid;
+};
+struct sxe2_vxlan_hdr {
+	uint8_t flag;
+	uint8_t resvd0;
+	uint8_t resvd1;
+	uint8_t protocol;
+	uint32_t vni;
+};
+
+enum sxe2_flow_act_type {
+	SXE2_FLOW_ACTION_DROP = 0,
+	SXE2_FLOW_ACTION_TC_REDIRECT,
+	SXE2_FLOW_ACTION_TO_VSI,
+	SXE2_FLOW_ACTION_TO_VSI_LIST,
+	SXE2_FLOW_ACTION_PASSTHRU,
+	SXE2_FLOW_ACTION_QUEUE,
+	SXE2_FLOW_ACTION_Q_REGION,
+	SXE2_FLOW_ACTION_MARK,
+	SXE2_FLOW_ACTION_COUNT,
+	SXE2_FLOW_ACTION_RSS,
+	SXE2_FLOW_ACTION_MAX = 32,
+};
+
+enum sxe2_rss_hash_key_func {
+	SXE2_RSS_HASH_FUNC_TOEPLITZ     = 0,
+	SXE2_RSS_HASH_FUNC_SYM_TOEPLITZ = 1,
+	SXE2_RSS_HASH_FUNC_XOR          = 2,
+	SXE2_RSS_HASH_FUNC_JEKINS       = 3
+};
+
+struct sxe2_flow_action_rss {
+	DECLARE_BITMAP(hdr_out, SXE2_FLOW_HDR_MAX);
+	DECLARE_BITMAP(hdr_in, SXE2_FLOW_HDR_MAX);
+	DECLARE_BITMAP(fld, SXE2_FLOW_FLD_ID_MAX);
+	uint8_t is_inner;
+	uint8_t func;
+	uint8_t hdr_type;
+};
+
+struct sxe2_flow_action_queue {
+	uint16_t vsi_index;
+	uint16_t q_index;
+};
+
+struct sxe2_flow_action_queue_region {
+	uint16_t vsi_index;
+	uint16_t q_index;
+	uint8_t region;
+};
+
+struct sxe2_flow_action_passthru {
+	uint16_t vsi_index;
+};
+
+struct sxe2_flow_action_mark {
+	uint32_t mark_id;
+};
+
+#define SXE2_VSI_MAX (2048)
+struct sxe2_flow_action_vsi {
+	uint16_t vsi_index;
+};
+
+struct sxe2_flow_action_vsi_list {
+	DECLARE_BITMAP(vsi_list_map, SXE2_VSI_MAX);
+	uint16_t vsi_cnt;
+};
+
+enum sxe2_fnav_stat_ctrl_type {
+	SXE2_FNAV_STAT_ENA_NONE = 0,
+	SXE2_FNAV_STAT_ENA_PKTS,
+	SXE2_FNAV_STAT_ENA_BYTES,
+	SXE2_FNAV_STAT_ENA_ALL,
+};
+
+struct sxe2_flow_action_count {
+	uint32_t user_id;
+	uint32_t driver_id;
+	uint32_t stat_index;
+	uint32_t stat_ctrl;
+};
+
+enum sxe2_flow_engine_type {
+	SXE2_FLOW_ENGINE_ACL,
+	SXE2_FLOW_ENGINE_SWITCH,
+	SXE2_FLOW_ENGINE_FNAV,
+	SXE2_FLOW_ENGINE_RSS,
+	SXE2_FLOW_ENGINE_MAX,
+};
+
+struct sxe2_flow_item {
+	struct sxe2_ether_hdr eth;
+	struct sxe2_vlan_hdr vlan;
+	struct sxe2_vlan_hdr qinq;
+	struct sxe2_ipv4_hdr ipv4;
+	struct sxe2_ipv6_hdr ipv6;
+	struct sxe2_udp_hdr udp;
+	struct sxe2_tcp_hdr tcp;
+	struct sxe2_sctp_hdr sctp;
+	struct sxe2_gtpu_hdr gtpu;
+	struct sxe2_vxlan_hdr vxlan;
+	struct sxe2_nvgre_hdr nvgre;
+	struct sxe2_geneve_hdr geneve;
+};
+
+enum sxe2_flow_sw_direct_type {
+	SXE2_FLOW_SW_DIRECT_TX,
+	SXE2_FLOW_SW_DIRECT_RX,
+	SXE2_FLOW_SW_DIRECT_MAX,
+};
+enum sxe2_flow_sw_pattern_type {
+	SXE2_FLOW_SW_PATTERN_ONLY,
+	SXE2_FLOW_SW_PATTERN_LAST,
+	SXE2_FLOW_SW_PATTERN_FIRST,
+	SXE2_FLOW_SW_PATTERN_MAX,
+};
+
+enum sxe2_flow_tunnel_type {
+	SXE2_FLOW_TUNNEL_TYPE_NONE,
+	SXE2_FLOW_TUNNEL_TYPE_PARENT,
+	SXE2_FLOW_TUNNEL_TYPE_VXLAN,
+	SXE2_FLOW_TUNNEL_TYPE_GTPU,
+	SXE2_FLOW_TUNNEL_TYPE_GENEVE,
+	SXE2_FLOW_TUNNEL_TYPE_GRE,
+	SXE2_FLOW_TUNNEL_TYPE_IPIP,
+};
+
+struct sxe2_flow_meta {
+	uint8_t switch_pattern_dup_allow;
+	uint8_t switch_src_direct;
+	uint16_t flow_src_vsi;
+	uint16_t flow_rule_vsi;
+	uint32_t flow_prio;
+	uint16_t flow_type;
+	uint8_t tunnel_type;
+	uint8_t rsv;
+};
+
+struct sxe2_flow_pattern {
+	DECLARE_BITMAP(hdrs, SXE2_FLOW_HDR_MAX);
+	DECLARE_BITMAP(map_spec, SXE2_FLOW_FLD_ID_MAX);
+	DECLARE_BITMAP(map_mask, SXE2_FLOW_FLD_ID_MAX);
+	struct sxe2_flow_item item_spec;
+	struct sxe2_flow_item item_mask;
+	uint64_t rss_type_allow;
+};
+
+struct sxe2_flow_action {
+	DECLARE_BITMAP(act_types, SXE2_FLOW_ACTION_MAX);
+	struct sxe2_flow_action_rss rss;
+	struct sxe2_flow_action_queue queue;
+	struct sxe2_flow_action_queue_region q_region;
+	struct sxe2_flow_action_passthru passthru;
+	struct sxe2_flow_action_vsi vsi;
+	struct sxe2_flow_action_vsi_list vsi_list;
+	struct sxe2_flow_action_mark mark;
+	struct sxe2_flow_action_count count;
+};
+#endif /* __SXE2_FLOW_PUBLIC_H__ */
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index b661e3cbf4..da7a690063 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -62,4 +62,5 @@ sources += files(
         'sxe2_txrx_vec.c',
         'sxe2_mac.c',
         'sxe2_filter.c',
+        'sxe2_rss.c',
 )
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 1fa9ad718e..b997e7b044 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -541,3 +541,176 @@ int32_t sxe2_drv_vlan_filter_switch(struct sxe2_adapter *adapter, bool on)
 
 	return ret;
 }
+
+int32_t sxe2_drv_rss_key_set(struct sxe2_adapter *adapter, uint8_t *key, uint16_t key_size)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_rss_key_req *req = NULL;
+	int32_t ret = 0;
+	uint16_t buf_size = sizeof(*req) + key_size;
+
+	req = rte_zmalloc("drv_cmd_rss_key", buf_size, 0);
+	if (!req) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to alloc rss key");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	req->vsi_id = rte_cpu_to_le_16(adapter->vsi_ctxt.dpdk_vsi_id);
+	req->key_size = rte_cpu_to_le_16(key_size);
+	rte_memcpy(req->key, key, key_size);
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_KEY_SET,
+		req, buf_size, NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cmd set rss key, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	if (req) {
+		rte_free(req);
+		req = NULL;
+	}
+	return ret;
+}
+
+int32_t sxe2_drv_rss_lut_set(struct sxe2_adapter *adapter, uint8_t *lut, uint16_t lut_size)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_rss_lut_req *req = NULL;
+	int32_t ret = 0;
+	uint16_t buf_size = sizeof(struct sxe2_rss_lut_req) + lut_size;
+
+	req = rte_zmalloc("drv_cmd_rss_lut", buf_size, 0);
+	if (!req) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to alloc rss lut");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	req->vsi_id = rte_cpu_to_le_16(adapter->vsi_ctxt.dpdk_vsi_id);
+	req->lut_size = rte_cpu_to_le_16(lut_size);
+	rte_memcpy(req->lut, lut, lut_size);
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_LUT_SET,
+		req, buf_size, NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cmd set rss lut, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	if (req) {
+		rte_free(req);
+		req = NULL;
+	}
+	return ret;
+}
+
+int32_t sxe2_drv_rss_hash_ctrl_func(struct sxe2_adapter *adapter, enum sxe2_rss_hash_key_func func)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_rss_func_req req = {0};
+	int32_t ret = 0;
+
+	req.vsi_id = rte_cpu_to_le_16(adapter->vsi_ctxt.dpdk_vsi_id);
+	req.func = func;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_FUNC_SET,
+		&req, sizeof(req), NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cmd set rss func, ret=%d", ret);
+	return ret;
+}
+
+static void sxe2_drv_flow_bitmap_fill(uint32_t *bitmap, uint16_t *list)
+{
+	uint16_t index = 0;
+	uint16_t i = 0;
+	uint16_t map_size = sizeof(*bitmap) * SXE2_BITS_PER_BYTE;
+
+	while (list[i] != SXE2_FLOW_END) {
+		index = list[i] / map_size;
+		bitmap[index] |= (1UL << (list[i] % map_size));
+		i++;
+	}
+}
+
+int32_t sxe2_drv_rss_hf_add(struct sxe2_adapter *adapter,
+			struct sxe2_rss_hf_config *rss_conf)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_rss_hf_req req = {0};
+	int32_t ret = 0;
+
+	req.vsi_id = rte_cpu_to_le_16(adapter->vsi_ctxt.dpdk_vsi_id);
+	req.symm = rss_conf->symm;
+	req.hdr_type = rte_cpu_to_le_32(SXE2_RSS_OUTER_HEADERS);
+	sxe2_drv_flow_bitmap_fill(req.headers, rss_conf->hdrs);
+	sxe2_drv_flow_bitmap_fill(req.hash_flds, rss_conf->flds);
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_HF_ADD,
+		&req, sizeof(req), NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cmd add rss hf, ret=%d", ret);
+	return ret;
+}
+
+int32_t sxe2_drv_rss_hf_del(struct sxe2_adapter *adapter,
+				struct sxe2_rss_hf_config *rss_conf)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_rss_hf_req req = {0};
+	int32_t ret = 0;
+
+	req.vsi_id = rte_cpu_to_le_16(adapter->vsi_ctxt.dpdk_vsi_id);
+	req.symm = rss_conf->symm;
+	req.hdr_type = rte_cpu_to_le_32(SXE2_RSS_OUTER_HEADERS);
+	sxe2_drv_flow_bitmap_fill(req.headers, rss_conf->hdrs);
+	sxe2_drv_flow_bitmap_fill(req.hash_flds, rss_conf->flds);
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_HF_DEL,
+		&req, sizeof(req), NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cmd del rss hf, ret=%d", ret);
+	return ret;
+}
+
+int32_t sxe2_drv_rss_hf_clear(struct sxe2_adapter *adapter)
+{
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	int32_t ret = 0;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RSS_HF_CLEAR,
+		NULL, 0, NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cmd clear rss hf, ret=%d", ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_ptp_gettime(struct sxe2_adapter *adapter, struct sxe2_rx_queue *rxq)
+{
+	(void)adapter;
+	(void)rxq;
+	return 0;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index c93bc2b0c9..2546c65a6c 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -53,4 +53,20 @@ int32_t sxe2_drv_vlan_insert_strip_cfg(struct sxe2_adapter *adapter);
 
 int32_t sxe2_drv_vlan_filter_switch(struct sxe2_adapter *adapter, bool on);
 
+int32_t sxe2_drv_rss_key_set(struct sxe2_adapter *adapter, uint8_t *key, uint16_t key_size);
+
+int32_t sxe2_drv_rss_lut_set(struct sxe2_adapter *adapter, uint8_t *lut, uint16_t lut_size);
+
+int32_t sxe2_drv_rss_hash_ctrl_func(struct sxe2_adapter *adapter, enum sxe2_rss_hash_key_func func);
+
+int32_t sxe2_drv_rss_hf_add(struct sxe2_adapter *adapter,
+			struct sxe2_rss_hf_config *rss_conf);
+
+int32_t sxe2_drv_rss_hf_del(struct sxe2_adapter *adapter,
+				struct sxe2_rss_hf_config *rss_conf);
+
+int32_t sxe2_drv_rss_hf_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_ptp_gettime(struct sxe2_adapter *adapter, struct sxe2_rx_queue *rxq);
+
 #endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index d69d650148..9998f241f0 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -6,6 +6,7 @@
 #define SXE2_DRV_CMD_H
 
 #include "sxe2_osal.h"
+#include "sxe2_flow_public.h"
 
 #define SXE2_DRV_CMD_MODULE_S        (16)
 #define SXE2_MK_DRV_CMD(module, cmd) (((module) << SXE2_DRV_CMD_MODULE_S) | ((cmd) & 0xFFFF))
@@ -320,6 +321,34 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_vlan_filter_switch_req {
 	uint8_t rsv;
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_rss_key_req {
+	uint16_t vsi_id;
+	uint16_t key_size;
+	uint8_t key[];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_rss_lut_req {
+	uint16_t vsi_id;
+	uint16_t lut_size;
+	uint8_t lut[];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_rss_func_req {
+	uint16_t vsi_id;
+	uint8_t func;
+	uint8_t rsv[1];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_rss_hf_req {
+	uint16_t vsi_id;
+	uint8_t rsv[2];
+	uint32_t headers[BITS_TO_U32(SXE2_FLOW_HDR_MAX)];
+	uint32_t hash_flds[BITS_TO_U32(SXE2_FLOW_FLD_ID_MAX)];
+	uint32_t hdr_type;
+	uint8_t symm;
+	uint8_t rsv1[3];
+} __rte_packed_end;
+
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
 	SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 4ffe32d353..77a2b5b1dc 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -125,6 +125,11 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 
 	.vlan_filter_set            = sxe2_dev_vlan_filter_set,
 	.vlan_offload_set           = sxe2_dev_vlan_offload_set,
+
+	.reta_update                = sxe2_dev_rss_reta_update,
+	.reta_query                 = sxe2_dev_rss_reta_query,
+	.rss_hash_update            = sxe2_dev_rss_hash_update,
+	.rss_hash_conf_get          = sxe2_dev_rss_hash_conf_get,
 };
 
 static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -141,6 +146,12 @@ static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
 		goto end;
 	}
 
+	ret = sxe2_rss_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to init rss, ret=%d", ret);
+		goto end;
+	}
+
 end:
 	return ret;
 }
@@ -281,6 +292,22 @@ static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
 		RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO |
 		RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
 
+
+	if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_PTP)
+		dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
+
+	if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) {
+		dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
+		dev_info->flow_type_rss_offloads  |= SXE2_RSS_HF_SUPPORT_ALL;
+		dev_info->reta_size = adapter->rss_ctxt.rss_lut_size;
+		dev_info->hash_key_size = adapter->rss_ctxt.rss_key_size;
+		dev_info->rss_algo_capa =
+			RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_DEFAULT) |
+			RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_TOEPLITZ) |
+			RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) |
+			RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_SIMPLE_XOR);
+	}
+
 	dev_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_thresh = {
 			.pthresh = SXE2_DEFAULT_RX_PTHRESH,
@@ -563,6 +590,8 @@ static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
 
 	sxe2_sw_queue_ctx_hw_cap_set(adapter, &dev_caps.queue_caps);
 
+	sxe2_sw_rss_ctx_hw_cap_set(adapter, &dev_caps.rss_hash_caps);
+
 	sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps);
 
 l_end:
@@ -950,8 +979,15 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_eth_err;
 	}
 
+	ret = sxe2_rss_disable(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to disable rss, ret=%d", ret);
+		goto init_rss_err;
+	}
+
 	goto l_end;
 
+init_rss_err:
 init_eth_err:
 init_dev_info_err:
 	sxe2_vsi_uninit(dev);
@@ -965,6 +1001,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 {
 	(void)sxe2_dev_stop(dev);
 	(void)sxe2_queues_release(dev);
+	(void)sxe2_rss_disable(dev);
 	sxe2_vsi_uninit(dev);
 	sxe2_dev_pci_map_uinit(dev);
 	sxe2_eth_uinit(dev);
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index fa3c69d360..3aa3799b79 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -15,6 +15,7 @@
 
 #include "sxe2_common.h"
 #include "sxe2_vsi.h"
+#include "sxe2_rss.h"
 #include "sxe2_irq.h"
 #include "sxe2_queue.h"
 #include "sxe2_mac.h"
@@ -122,6 +123,11 @@ enum {
 	SXE2_FLAGS_NBITS
 };
 
+struct sxe2_ptp_context {
+	uint64_t mbuf_rx_ts_flag;
+	int32_t mbuf_rx_ts_offset;
+};
+
 struct sxe2_devargs {
 	uint8_t flow_dup_pattern_mode;
 	uint8_t func_flow_direct_en;
@@ -300,7 +306,9 @@ struct sxe2_adapter {
 	struct sxe2_queue_context     q_ctxt;
 	struct sxe2_vsi_context       vsi_ctxt;
 	struct sxe2_filter_context    filter_ctxt;
+	struct sxe2_rss_context       rss_ctxt;
 	struct sxe2_link_context      link_ctxt;
+	struct sxe2_ptp_context       ptp_ctxt;
 	struct sxe2_devargs           devargs;
 	struct sxe2_switchdev_info    switchdev_info;
 	bool                          rule_started;
diff --git a/drivers/net/sxe2/sxe2_flow_define.h b/drivers/net/sxe2/sxe2_flow_define.h
new file mode 100644
index 0000000000..d2f6000efa
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_define.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_FLOW_DEFINE_H__
+#define __SXE2_FLOW_DEFINE_H__
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_flow_driver.h>
+
+#include "sxe2_osal.h"
+#include "sxe2_flow_public.h"
+
+#define SXE2_FLOW_ETH_TYPE_MIN        (1500)
+
+enum sxe2_expansion {
+	SXE2_EXPANSION_ERROR = 0,
+	SXE2_EXPANSION_OUTER_ETH,
+	SXE2_EXPANSION_OUTER_VLAN,
+	SXE2_EXPANSION_OUTER_QINQ,
+	SXE2_EXPANSION_OUTER_IPV4,
+	SXE2_EXPANSION_OUTER_IPV4_FRAG_EXT,
+	SXE2_EXPANSION_OUTER_IPV6,
+	SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT,
+	SXE2_EXPANSION_OUTER_UDP,
+	SXE2_EXPANSION_OUTER_TCP,
+	SXE2_EXPANSION_OUTER_SCTP,
+
+	SXE2_EXPANSION_VXLAN,
+	SXE2_EXPANSION_VXLAN_GPE,
+	SXE2_EXPANSION_GRE,
+	SXE2_EXPANSION_NVGRE,
+	SXE2_EXPANSION_GENEVE,
+	SXE2_EXPANSION_GTPU,
+	SXE2_EXPANSION_IPIP,
+	SXE2_EXPANSION_OUTER_END,
+
+	SXE2_EXPANSION_ETH,
+	SXE2_EXPANSION_VLAN,
+	SXE2_EXPANSION_IPV4,
+	SXE2_EXPANSION_IPV4_FRAG_EXT,
+	SXE2_EXPANSION_IPV6,
+	SXE2_EXPANSION_IPV6_FRAG_EXT,
+	SXE2_EXPANSION_UDP,
+	SXE2_EXPANSION_TCP,
+	SXE2_EXPANSION_SCTP,
+
+	SXE2_EXPANSION_END,
+	SXE2_EXPANSION_MAX,
+};
+
+enum sxe2_flow_udp_tunnel_protocol {
+	SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN,
+	SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+	SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE,
+	SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U,
+	SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE,
+	SXE2_FLOW_UDP_TUNNEL_MAX,
+};
+
+enum {
+	SXE2_FLOW_ETH_TYPE_IPV4 = 0x0800,
+	SXE2_FLOW_ETH_TYPE_IPV6 = 0x86DD,
+	SXE2_FLOW_IP_PROTOCOL_GRE = 0x2F,
+	SXE2_FLOW_IP_PROTOCOL_IPV4 = 0x04,
+	SXE2_FLOW_IP_PROTOCOL_IPV6 = 0x29,
+	SXE2_FLOW_IP_PROTOCOL_ETH = 0x3B,
+	SXE2_FLOW_IP_PROTOCOL_UDP = 0x11,
+	SXE2_FLOW_IP_PROTOCOL_TCP = 0x06,
+	SXE2_FLOW_IP_PROTOCOL_SCTP = 0x84,
+};
+
+union sxe2_flow_item_raw {
+	struct sxe2_flow_item item;
+	uint8_t raw[sizeof(struct sxe2_flow_item)];
+};
+
+struct sxe2_flow {
+	TAILQ_ENTRY(sxe2_flow) next;
+	enum sxe2_flow_engine_type engine_type;
+	struct sxe2_flow_pattern pattern_outer;
+	struct sxe2_flow_pattern pattern_inner;
+	uint8_t has_mask;
+	uint8_t has_spec;
+	uint8_t has_hdr;
+	struct sxe2_flow_meta meta;
+	struct sxe2_flow_action action;
+	uint32_t flow_id;
+	int32_t create_err;
+	DECLARE_BITMAP(flow_type, SXE2_EXPANSION_MAX);
+};
+
+TAILQ_HEAD(sxe2_flow_list_t, sxe2_flow);
+
+struct rte_flow {
+	TAILQ_ENTRY(rte_flow) next;
+	struct sxe2_flow_list_t sxe2_flow_list;
+};
+TAILQ_HEAD(rte_flow_list_t, rte_flow);
+
+struct sxe2_fnav_cid_mgr {
+	TAILQ_ENTRY(sxe2_fnav_cid_mgr) next;
+	uint16_t stat_index;
+	uint32_t user_id;
+	uint32_t driver_id;
+	uint32_t count_type;
+	uint64_t hits;
+	uint64_t bytes;
+};
+TAILQ_HEAD(sxe2_fnav_cid_mgr_list_t, sxe2_fnav_cid_mgr);
+
+struct sxe2_fnav_count_resource {
+	uint32_t count_type;
+	uint32_t global_index;
+	struct sxe2_fnav_cid_mgr_list_t fnav_cid_mgr_list;
+};
+
+struct sxe2_flow_context {
+	struct rte_flow_list_t rte_flow_list;
+	rte_spinlock_t flow_list_lock;
+	struct sxe2_fnav_count_resource hw_res;
+	uint32_t fnav_inited;
+};
+#define SXE2_INVALID_RSS_ATTR	\
+			(RTE_ETH_RSS_L3_PRE40 | RTE_ETH_RSS_L3_PRE56 | RTE_ETH_RSS_L3_PRE96)
+#define SXE2_VALID_RSS_IPV4_L4	 \
+			(RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV4_TCP | \
+			 RTE_ETH_RSS_NONFRAG_IPV4_SCTP)
+
+#define SXE2_VALID_RSS_IPV6_L4	\
+			(RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_NONFRAG_IPV6_TCP | \
+			 RTE_ETH_RSS_NONFRAG_IPV6_SCTP)
+#define SXE2_VALID_RSS_IPV4	\
+			(RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4  | \
+			 RTE_ETH_RSS_NONFRAG_IPV4_OTHER | SXE2_VALID_RSS_IPV4_L4)
+#define SXE2_VALID_RSS_IPV6	\
+			(RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | \
+			 RTE_ETH_RSS_NONFRAG_IPV6_OTHER | SXE2_VALID_RSS_IPV6_L4)
+
+#define SXE2_VALID_RSS_L3	(SXE2_VALID_RSS_IPV4 | SXE2_VALID_RSS_IPV6)
+#define SXE2_VALID_RSS_L4	(SXE2_VALID_RSS_IPV4_L4 | SXE2_VALID_RSS_IPV6_L4)
+
+#endif /* __SXE2_FLOW_DEFINE_H__ */
diff --git a/drivers/net/sxe2/sxe2_queue.c b/drivers/net/sxe2/sxe2_queue.c
index 1786d6ea4f..220cab6fce 100644
--- a/drivers/net/sxe2/sxe2_queue.c
+++ b/drivers/net/sxe2/sxe2_queue.c
@@ -17,6 +17,7 @@ void sxe2_sw_queue_ctx_hw_cap_set(struct sxe2_adapter *adapter,
 
 int32_t sxe2_queues_init(struct rte_eth_dev *dev)
 {
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
 	int32_t ret = 0;
 	uint16_t buf_size;
 	uint16_t frame_size;
@@ -36,6 +37,16 @@ int32_t sxe2_queues_init(struct rte_eth_dev *dev)
 			dev->data->scattered_rx = 1;
 	}
 
+	adapter->ptp_ctxt.mbuf_rx_ts_offset = -1;
+	adapter->ptp_ctxt.mbuf_rx_ts_flag = 0;
+	if (dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) {
+		ret = rte_mbuf_dyn_rx_timestamp_register
+			(&adapter->ptp_ctxt.mbuf_rx_ts_offset,
+			 (uint64_t *)&adapter->ptp_ctxt.mbuf_rx_ts_flag);
+		if (ret)
+			PMD_LOG_ERR(INIT, "Failed to enable timestamp offloads, ret=%d", ret);
+	}
+
 	return ret;
 }
 
diff --git a/drivers/net/sxe2/sxe2_rss.c b/drivers/net/sxe2/sxe2_rss.c
new file mode 100644
index 0000000000..1d56613043
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_rss.c
@@ -0,0 +1,584 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_rss.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_cmd_chnl.h"
+
+void sxe2_sw_rss_ctx_hw_cap_set(struct sxe2_adapter *adapter,
+		struct sxe2_drv_rss_hash_caps *rss_caps)
+{
+	adapter->rss_ctxt.rss_key_size = rss_caps->hash_key_size;
+	adapter->rss_ctxt.rss_lut_size = rss_caps->lut_key_size;
+}
+
+int32_t sxe2_rss_hash_key_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_rss_conf *rss_conf = &dev->data->dev_conf.rx_adv_conf.rss_conf;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = 0;
+	uint16_t i = 0;
+
+	if (rss_ctxt->rss_key == NULL) {
+		rss_ctxt->rss_key = (uint8_t *)rte_zmalloc("rss_key", rss_ctxt->rss_key_size, 0);
+		if (rss_ctxt->rss_key == NULL) {
+			PMD_LOG_ERR(INIT, "Failed to allocate rss key");
+			ret = -ENOMEM;
+			goto l_end;
+		}
+	}
+
+	if (!rss_conf->rss_key) {
+		for (i = 0; i < rss_ctxt->rss_key_size; i++)
+			rss_ctxt->rss_key[i] = (uint8_t)rte_rand();
+	} else {
+		rte_memcpy(rss_ctxt->rss_key, rss_conf->rss_key,
+			   RTE_MIN(rss_conf->rss_key_len, rss_ctxt->rss_key_size));
+	}
+
+	ret = sxe2_drv_rss_key_set(adapter, rss_ctxt->rss_key,
+				   rss_ctxt->rss_key_size);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set rss key, ret:%d", ret);
+		rte_free(rss_ctxt->rss_key);
+		rss_ctxt->rss_key = NULL;
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+void sxe2_rss_hash_key_uninit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+
+	if (rss_ctxt->rss_key) {
+		rte_free(rss_ctxt->rss_key);
+		rss_ctxt->rss_key = NULL;
+	}
+}
+
+int32_t sxe2_rss_lut_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = 0;
+	uint16_t i;
+
+	if (rss_ctxt->rss_lut == NULL) {
+		rss_ctxt->rss_lut = (uint8_t *)rte_zmalloc("rss_lut", rss_ctxt->rss_lut_size, 0);
+		if (rss_ctxt->rss_lut == NULL) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Failed to allocate rss lut");
+			ret = -ENOMEM;
+			goto l_end;
+		}
+	}
+
+	for (i = 0; i < rss_ctxt->rss_lut_size; i++)
+		rss_ctxt->rss_lut[i] = (uint8_t)(i % dev->data->nb_rx_queues);
+
+	ret = sxe2_drv_rss_lut_set(adapter, rss_ctxt->rss_lut, rss_ctxt->rss_lut_size);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set rss lut, ret:%d", ret);
+		rte_free(rss_ctxt->rss_lut);
+		rss_ctxt->rss_lut = NULL;
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+void sxe2_rss_lut_uninit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+
+	if (rss_ctxt->rss_lut) {
+		rte_free(rss_ctxt->rss_lut);
+		rss_ctxt->rss_lut = NULL;
+	}
+}
+
+static struct sxe2_rss_hf_config sxe2_rss_default_hf_config[] = {
+	{
+		.rss_hf = RTE_ETH_RSS_L2_PAYLOAD,
+		.hdrs = {SXE2_FLOW_HDR_ETH,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_ETH_TYPE,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_IPV4,
+		.hdrs = {SXE2_FLOW_HDR_IPV4,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV4_SA,
+				 SXE2_FLOW_FLD_ID_IPV4_DA,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_IPV6,
+		.hdrs = {SXE2_FLOW_HDR_IPV6,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV6_SA,
+				 SXE2_FLOW_FLD_ID_IPV6_DA,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_FRAG_IPV4,
+		.hdrs = {SXE2_FLOW_HDR_IPV4,
+				 SXE2_FLOW_HDR_IPV_FRAG,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV4_SA,
+				 SXE2_FLOW_FLD_ID_IPV4_DA,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_FRAG_IPV6,
+		.hdrs = {SXE2_FLOW_HDR_IPV6,
+				 SXE2_FLOW_HDR_IPV_FRAG,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV6_SA,
+				 SXE2_FLOW_FLD_ID_IPV6_DA,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV4_OTHER,
+		.hdrs = {SXE2_FLOW_HDR_IPV4,
+				 SXE2_FLOW_HDR_IPV_OTHER,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV4_SA,
+				 SXE2_FLOW_FLD_ID_IPV4_DA,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV6_OTHER,
+		.hdrs = {SXE2_FLOW_HDR_IPV6,
+				 SXE2_FLOW_HDR_IPV_OTHER,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV6_SA,
+				 SXE2_FLOW_FLD_ID_IPV6_DA,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV4_UDP,
+		.hdrs = {SXE2_FLOW_HDR_IPV4,
+				 SXE2_FLOW_HDR_UDP,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV4_SA,
+				 SXE2_FLOW_FLD_ID_IPV4_DA,
+				 SXE2_FLOW_FLD_ID_UDP_SRC_PORT,
+				 SXE2_FLOW_FLD_ID_UDP_DST_PORT,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV6_UDP,
+		.hdrs = {SXE2_FLOW_HDR_IPV6,
+				 SXE2_FLOW_HDR_UDP,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV6_SA,
+				 SXE2_FLOW_FLD_ID_IPV6_DA,
+				 SXE2_FLOW_FLD_ID_UDP_SRC_PORT,
+				 SXE2_FLOW_FLD_ID_UDP_DST_PORT,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV4_TCP,
+		.hdrs = {SXE2_FLOW_HDR_IPV4,
+				 SXE2_FLOW_HDR_TCP,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV4_SA,
+				 SXE2_FLOW_FLD_ID_IPV4_DA,
+				 SXE2_FLOW_FLD_ID_TCP_SRC_PORT,
+				 SXE2_FLOW_FLD_ID_TCP_DST_PORT,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV6_TCP,
+		.hdrs = {SXE2_FLOW_HDR_IPV6,
+				 SXE2_FLOW_HDR_TCP,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV6_SA,
+				 SXE2_FLOW_FLD_ID_IPV6_DA,
+				 SXE2_FLOW_FLD_ID_TCP_SRC_PORT,
+				 SXE2_FLOW_FLD_ID_TCP_DST_PORT,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV4_SCTP,
+		.hdrs = {SXE2_FLOW_HDR_IPV4,
+				 SXE2_FLOW_HDR_SCTP,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV4_SA,
+				 SXE2_FLOW_FLD_ID_IPV4_DA,
+				 SXE2_FLOW_FLD_ID_SCTP_SRC_PORT,
+				 SXE2_FLOW_FLD_ID_SCTP_DST_PORT,
+				 SXE2_FLOW_END},
+	},
+	{
+		.rss_hf = RTE_ETH_RSS_NONFRAG_IPV6_SCTP,
+		.hdrs = {SXE2_FLOW_HDR_IPV6,
+				 SXE2_FLOW_HDR_SCTP,
+				 SXE2_FLOW_END},
+		.flds = {SXE2_FLOW_FLD_ID_IPV6_SA,
+				 SXE2_FLOW_FLD_ID_IPV6_DA,
+				 SXE2_FLOW_FLD_ID_SCTP_SRC_PORT,
+				 SXE2_FLOW_FLD_ID_SCTP_DST_PORT,
+				 SXE2_FLOW_END},
+	},
+};
+
+int32_t sxe2_rss_hf_type_set(struct rte_eth_dev *dev, uint64_t rss_hf)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = 0;
+	uint32_t i;
+	uint8_t symm = 0;
+
+	if (0 == (rss_hf & SXE2_RSS_HF_SUPPORT_ALL) && rss_hf != 0) {
+		PMD_DEV_LOG_ERR(adapter, DRV,
+			"Failed to set unsupported rss_hf:0x%016" PRIx64,
+			rss_hf);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	for (i = 0; i < RTE_DIM(sxe2_rss_default_hf_config); i++) {
+		if (rss_ctxt->rss_hf & sxe2_rss_default_hf_config[i].rss_hf) {
+			sxe2_rss_default_hf_config[i].symm = rss_ctxt->symm;
+			ret = sxe2_drv_rss_hf_del(adapter, &sxe2_rss_default_hf_config[i]);
+			if (ret) {
+				PMD_DEV_LOG_ERR(adapter, INIT,
+					"Failed to del rss hf cfg[%d], ret:%d", i, ret);
+				goto l_end;
+			}
+		}
+	}
+
+	if (rss_ctxt->hash_func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
+		symm = 1;
+
+	for (i = 0; i < RTE_DIM(sxe2_rss_default_hf_config); i++) {
+		if (rss_hf & sxe2_rss_default_hf_config[i].rss_hf) {
+			sxe2_rss_default_hf_config[i].symm = symm;
+			ret = sxe2_drv_rss_hf_add(adapter, &sxe2_rss_default_hf_config[i]);
+			if (ret) {
+				PMD_DEV_LOG_ERR(adapter, INIT,
+					"Failed to add rss hf cfg[%d], ret:%d", i, ret);
+				goto l_end;
+			}
+		}
+	}
+
+	rss_ctxt->rss_hf = rss_hf & SXE2_RSS_HF_SUPPORT_ALL;
+	rss_ctxt->symm = symm;
+l_end:
+	return ret;
+}
+
+int32_t sxe2_rss_hash_function_set(struct rte_eth_dev *dev, enum rte_eth_hash_function func)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	enum sxe2_rss_hash_key_func hash_func = SXE2_RSS_HASH_FUNC_SYM_TOEPLITZ;
+	int32_t ret = 0;
+
+	switch (func) {
+	case RTE_ETH_HASH_FUNCTION_DEFAULT:
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+	case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ:
+		hash_func = SXE2_RSS_HASH_FUNC_SYM_TOEPLITZ;
+		break;
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		hash_func = SXE2_RSS_HASH_FUNC_XOR;
+		break;
+	default:
+		PMD_DEV_LOG_ERR(adapter, DRV, "RSS hash function[%d] not support.", func);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_drv_rss_hash_ctrl_func(adapter, hash_func);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set rss hash function, ret=[%d]", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_rss_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_eth_rss_conf *rss_conf = &dev->data->dev_conf.rx_adv_conf.rss_conf;
+	enum rte_eth_hash_function rss_func = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ;
+	int32_t ret = 0;
+
+	adapter->rss_ctxt.inited = false;
+
+	if (dev->data->nb_rx_queues <= 1) {
+		PMD_DEV_LOG_DEBUG(adapter, INIT, "No need to init rss, rx queues %d.",
+				dev->data->nb_rx_queues);
+		goto l_end;
+	}
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) == 0) {
+		PMD_DEV_LOG_WARN(adapter, INIT, "RSS not supported");
+		goto l_end;
+	}
+
+	ret = sxe2_rss_hash_key_init(dev);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to init rss key");
+		goto l_end;
+	}
+
+	ret = sxe2_rss_lut_init(dev);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to init rss lut");
+		goto l_err_key;
+	}
+
+	rss_func = rss_conf->algorithm;
+	ret = sxe2_rss_hash_function_set(dev, rss_func);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to init rss hash function");
+		goto l_err_lut;
+	}
+	ret = sxe2_rss_hf_type_set(dev, rss_conf->rss_hf);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to set rss hf type");
+		goto l_err_lut;
+	}
+	adapter->rss_ctxt.inited = true;
+	goto l_end;
+
+l_err_lut:
+	sxe2_rss_lut_uninit(dev);
+l_err_key:
+	sxe2_rss_hash_key_uninit(dev);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_rss_disable(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	if ((adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) == 0)
+		goto l_end;
+
+	ret = sxe2_drv_rss_hf_clear(adapter);
+	if (ret)
+		PMD_LOG_ERR(INIT, "Failed to clear rss hf");
+
+	sxe2_rss_hash_key_uninit(dev);
+
+	sxe2_rss_lut_uninit(dev);
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_dev_rss_reta_update(struct rte_eth_dev *dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf,
+		uint16_t reta_size)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	uint8_t *lut_tmp = NULL;
+	int32_t ret = 0;
+	uint16_t i;
+	uint16_t shift;
+	uint16_t idx;
+
+	if (!adapter->rss_ctxt.inited) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "RSS not inited.");
+		ret = -ENOTSUP;
+		goto l_end;
+	}
+
+	if (reta_size != rss_ctxt->rss_lut_size) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "The size of hash lookup table configured "
+				"(%d) doesn't match the number of hardware can "
+			"support (%d)", reta_size, rss_ctxt->rss_lut_size);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	lut_tmp = rte_zmalloc("rss_lut_temp", reta_size, 0);
+	if (!lut_tmp) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "No memory can be allocated");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	rte_memcpy(lut_tmp, rss_ctxt->rss_lut, reta_size);
+
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_ETH_RETA_GROUP_SIZE;
+		shift = i % RTE_ETH_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			lut_tmp[i] = reta_conf[idx].reta[shift];
+	}
+
+	ret = sxe2_drv_rss_lut_set(adapter, lut_tmp, reta_size);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set rss lut");
+		goto l_end;
+	}
+
+	rte_memcpy(rss_ctxt->rss_lut, lut_tmp, reta_size);
+
+l_end:
+	if (lut_tmp)
+		rte_free(lut_tmp);
+	return ret;
+}
+
+int32_t sxe2_dev_rss_reta_query(struct rte_eth_dev *dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf,
+		uint16_t reta_size)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = 0;
+	uint16_t i;
+	uint16_t shift;
+	uint16_t idx;
+
+	if (!adapter->rss_ctxt.inited) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "RSS not inited.");
+		ret = -ENOTSUP;
+		goto l_end;
+	}
+
+	if (reta_size != rss_ctxt->rss_lut_size) {
+		PMD_LOG_ERR(INIT, "The size of hash lookup table configured "
+			"(%d) doesn't match the number of hardware can "
+			"support (%d)", reta_size, rss_ctxt->rss_lut_size);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_ETH_RETA_GROUP_SIZE;
+		shift = i % RTE_ETH_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			reta_conf[idx].reta[shift] = rss_ctxt->rss_lut[i];
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_rss_hash_key_update(struct rte_eth_dev *dev,
+		struct rte_eth_rss_conf *rss_conf)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = 0;
+	uint16_t i;
+
+	if (rss_conf->rss_key_len == 0 || rss_conf->rss_key == NULL)
+		goto l_end;
+
+	if (rss_conf->rss_key_len != rss_ctxt->rss_key_size) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "The size of hash key configured "
+			"(%d) doesn't match the size of hardware can "
+			"support (%d)", rss_conf->rss_key_len,
+			rss_ctxt->rss_key_size);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	for (i = 0; i < rss_conf->rss_key_len; i++) {
+		if (rss_conf->rss_key[i] != rss_ctxt->rss_key[i])
+			break;
+	}
+	if (i == rss_conf->rss_key_len)
+		goto l_end;
+
+	ret = sxe2_drv_rss_key_set(adapter, rss_conf->rss_key,
+				   rss_conf->rss_key_len);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set rss key");
+		goto l_end;
+	}
+
+	rte_memcpy(rss_ctxt->rss_key, rss_conf->rss_key, rss_conf->rss_key_len);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_dev_rss_hash_update(struct rte_eth_dev *dev,
+		struct rte_eth_rss_conf *rss_conf)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = -1;
+
+	if (!adapter->rss_ctxt.inited) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "RSS not inited.");
+		ret = -ENOTSUP;
+		goto l_end;
+	}
+
+	ret = sxe2_rss_hash_key_update(dev, rss_conf);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set rss hash key");
+		goto l_end;
+	}
+
+	if (rss_conf->algorithm != rss_ctxt->hash_func) {
+		ret = sxe2_rss_hash_function_set(dev, rss_conf->algorithm);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set rss hash function");
+			goto l_end;
+		}
+		rss_ctxt->hash_func = rss_conf->algorithm;
+	}
+
+	if ((rss_conf->rss_hf & SXE2_RSS_HF_SUPPORT_ALL)
+			!= rss_ctxt->rss_hf) {
+		ret = sxe2_rss_hf_type_set(dev, rss_conf->rss_hf);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set rss hf type");
+			goto l_end;
+		}
+	}
+	ret = 0;
+l_end:
+	return ret;
+}
+
+int32_t sxe2_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+		struct rte_eth_rss_conf *rss_conf)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_rss_context *rss_ctxt = &adapter->rss_ctxt;
+	int32_t ret = 0;
+
+	if (adapter->rss_ctxt.inited == 0) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "RSS not inited.");
+		ret = -ENOTSUP;
+		goto l_end;
+	}
+
+	if (rss_conf->rss_key) {
+		rss_conf->rss_key_len = rss_ctxt->rss_key_size;
+		rte_memcpy(rss_conf->rss_key, rss_ctxt->rss_key, rss_ctxt->rss_key_size);
+	}
+	rss_conf->rss_hf = rss_ctxt->rss_hf;
+	rss_conf->algorithm = rss_ctxt->hash_func;
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_rss.h b/drivers/net/sxe2/sxe2_rss.h
new file mode 100644
index 0000000000..2a454ac1b3
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_rss.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_RSS_H__
+#define __SXE2_RSS_H__
+#include <ethdev_driver.h>
+#include "sxe2_osal.h"
+#include "sxe2_drv_cmd.h"
+#include "sxe2_flow_define.h"
+
+#define SXE2_FLOW_END (0xFFFF)
+
+struct sxe2_rss_context {
+	enum rte_eth_hash_function hash_func;
+	uint16_t rss_key_size;
+	uint16_t rss_lut_size;
+	uint8_t  *rss_key;
+	uint8_t  *rss_lut;
+	uint64_t rss_hf;
+	uint8_t symm;
+	bool inited;
+};
+
+struct sxe2_rss_hf_config {
+	uint64_t rss_hf;
+	uint16_t hdrs[SXE2_FLOW_HDR_MAX];
+	uint16_t flds[SXE2_FLOW_FLD_ID_MAX];
+	uint8_t symm;
+};
+
+#define SXE2_RSS_HF_SUPPORT_ALL ( \
+	RTE_ETH_RSS_IPV4 | \
+	RTE_ETH_RSS_FRAG_IPV4 | \
+	RTE_ETH_RSS_NONFRAG_IPV4_TCP | \
+	RTE_ETH_RSS_NONFRAG_IPV4_UDP | \
+	RTE_ETH_RSS_NONFRAG_IPV4_SCTP | \
+	RTE_ETH_RSS_NONFRAG_IPV4_OTHER | \
+	RTE_ETH_RSS_IPV6 | \
+	RTE_ETH_RSS_FRAG_IPV6 | \
+	RTE_ETH_RSS_NONFRAG_IPV6_TCP | \
+	RTE_ETH_RSS_NONFRAG_IPV6_UDP | \
+	RTE_ETH_RSS_NONFRAG_IPV6_SCTP | \
+	RTE_ETH_RSS_NONFRAG_IPV6_OTHER | \
+	RTE_ETH_RSS_L2_PAYLOAD)
+
+struct sxe2_adapter;
+
+void sxe2_sw_rss_ctx_hw_cap_set(struct sxe2_adapter *adapter,
+		struct sxe2_drv_rss_hash_caps *rss_caps);
+
+int32_t sxe2_rss_hash_key_init(struct rte_eth_dev *dev);
+
+void sxe2_rss_hash_key_uninit(struct rte_eth_dev *dev);
+
+int32_t sxe2_rss_lut_init(struct rte_eth_dev *dev);
+
+void sxe2_rss_lut_uninit(struct rte_eth_dev *dev);
+
+int32_t sxe2_rss_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_rss_hash_function_set(struct rte_eth_dev *dev, enum rte_eth_hash_function func);
+
+int32_t sxe2_rss_hf_type_set(struct rte_eth_dev *dev, uint64_t rss_hf);
+
+int32_t sxe2_rss_disable(struct rte_eth_dev *dev);
+
+int32_t sxe2_dev_rss_reta_update(struct rte_eth_dev *dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf,
+		uint16_t reta_size);
+
+int32_t sxe2_dev_rss_reta_query(struct rte_eth_dev *dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf,
+		uint16_t reta_size);
+
+int32_t sxe2_dev_rss_hash_update(struct rte_eth_dev *dev,
+		struct rte_eth_rss_conf *rss_conf);
+
+int32_t sxe2_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+		struct rte_eth_rss_conf *rss_conf);
+#endif /* __SXE2_RSS_H__ */
diff --git a/drivers/net/sxe2/sxe2_txrx.h b/drivers/net/sxe2/sxe2_txrx.h
index 6f6ff3e3d1..2ff5fee7c7 100644
--- a/drivers/net/sxe2/sxe2_txrx.h
+++ b/drivers/net/sxe2/sxe2_txrx.h
@@ -23,4 +23,8 @@ int32_t sxe2_tx_burst_mode_get(struct rte_eth_dev *dev,
 int32_t sxe2_rx_burst_mode_get(struct rte_eth_dev *dev,
 			__rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode);
 
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+int32_t sxe2_rx_update_ptp_time(struct sxe2_rx_queue *rxq);
+#endif
+
 #endif /* SXE2_TXRX_H */
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index 21d5c38725..3c6fe37404 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -17,6 +17,7 @@
 #include "sxe2_queue.h"
 #include "sxe2_ethdev.h"
 #include "sxe2_common_log.h"
+#include "sxe2_cmd_chnl.h"
 
 static __rte_always_inline int32_t
 sxe2_tx_bufs_free(struct sxe2_tx_queue *txq)
@@ -282,6 +283,30 @@ sxe2_tx_desc_checksum_fill(uint64_t offloads, uint32_t *desc_cmd, uint32_t *desc
 	return;
 }
 
+static __rte_always_inline void sxe2_desc_tso_fill(struct rte_mbuf *tx_pkt,
+						   uint64_t *desc_type_cmd_tso_mss,
+						   union sxe2_tx_offload_info ol_info)
+{
+	uint32_t hdr_len;
+	uint32_t tso_len;
+
+	if (!ol_info.l4_len) {
+		PMD_LOG_DEBUG(TX, "TSO ERROR: L4 length is 0");
+		goto l_end;
+	}
+	hdr_len = ol_info.l2_len + ol_info.l3_len + ol_info.l4_len;
+	if (tx_pkt->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK)
+		hdr_len += ol_info.outer_l2_len + ol_info.outer_l3_len;
+
+	tso_len = tx_pkt->pkt_len - hdr_len;
+	*desc_type_cmd_tso_mss |=
+			((uint64_t)SXE2_TX_CTXT_DESC_CMD_TSO << SXE2_TX_CTXT_DESC_CMD_SHIFT) |
+			((uint64_t)tso_len << SXE2_TX_CTXT_DESC_TSO_LEN_SHIFT) |
+			((uint64_t)tx_pkt->tso_segsz << SXE2_TX_CTXT_DESC_MSS_SHIFT);
+l_end:
+	return;
+}
+
 static __rte_always_inline uint64_t
 sxe2_tx_data_desc_build_cobt(uint32_t cmd, uint32_t offset, uint16_t buf_size, uint16_t l2tag)
 {
@@ -395,6 +420,11 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
 				rte_pktmbuf_free_seg(buffer->mbuf);
 				buffer->mbuf = NULL;
 			}
+			if (offloads & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
+				sxe2_desc_tso_fill(tx_pkt,
+					&desc_type_cmd_tso_mss, ol_info);
+			else if (offloads & RTE_MBUF_F_TX_IEEE1588_TMST)
+				desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_CMD_TSYN_MASK;
 
 			if (offloads & RTE_MBUF_F_TX_QINQ) {
 				desc_l2tag2 = tx_pkt->vlan_tci_outer;
@@ -707,6 +737,57 @@ sxe2_rx_desc_filter_para_fill(struct sxe2_rx_queue *rxq __rte_unused,
 #endif
 }
 
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+int32_t sxe2_rx_update_ptp_time(struct sxe2_rx_queue *rxq)
+{
+	struct sxe2_adapter *adapter;
+	uint64_t cur_time_ms;
+	int32_t ret = 0;
+	cur_time_ms = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000);
+
+	if (likely((cur_time_ms - rxq->update_time) < SXE2_RX_PKTS_TS_TIMEOUT_VAL))
+		goto l_end;
+	rxq->update_time = cur_time_ms;
+	adapter = rxq->vsi->adapter;
+	rxq->ts_need_update = true;
+	ret = sxe2_drv_ptp_gettime(adapter, rxq);
+	if (rxq->desc_ts < rxq->ts_low)
+		rxq->ts_need_update = false;
+
+	PMD_LOG_INFO(RX, "rxq update time ret=%d, cur time=%" PRIu64 ", rxqh=%" PRIu64 ", rxql=%d",
+		     ret, cur_time_ms, rxq->ts_high, rxq->ts_low);
+l_end:
+	return ret;
+}
+
+static inline void sxe2_rx_desc_ptp_para_fill(struct sxe2_rx_queue *rxq,
+					      struct rte_mbuf *mbuf,
+					      union sxe2_rx_desc *desc)
+{
+	struct sxe2_adapter *adapter = rxq->vsi->adapter;
+	uint64_t ts_ns;
+
+	if (adapter->ptp_ctxt.mbuf_rx_ts_flag != 0 &&
+	    (rxq->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) &&
+	    SXE2_RX_DESC_RXDID_VAL_GET(desc->wb.rxdid_src) == SXE2_RX_DESC_RXDID_1588) {
+		rxq->desc_ts = rte_le_to_cpu_32(desc->wb_ts.ts_h);
+		(void)sxe2_rx_update_ptp_time(rxq);
+		if (rxq->ts_need_update && rxq->desc_ts < rxq->ts_low)
+			rxq->ts_high += 1;
+
+		rxq->ts_need_update = true;
+		rxq->ts_low = rxq->desc_ts;
+		rxq->update_time = rte_get_timer_cycles() /
+			(rte_get_timer_hz() / 1000);
+		ts_ns = rxq->ts_high * NSEC_PER_SEC + rxq->ts_low;
+		*RTE_MBUF_DYNFIELD(mbuf, adapter->ptp_ctxt.mbuf_rx_ts_offset, uint64_t *) = ts_ns;
+		mbuf->ol_flags |= adapter->ptp_ctxt.mbuf_rx_ts_flag;
+		PMD_LOG_INFO(RX, "receive ptp pkt,ts_s=%" PRIu64 ", ts_ns=%d", rxq->ts_high,
+			     rxq->ts_low);
+	}
+}
+#endif
+
 static __rte_always_inline void
 sxe2_rx_mbuf_common_fields_fill(struct sxe2_rx_queue *rxq, struct rte_mbuf *mbuf,
 		union sxe2_rx_desc *rxd)
@@ -718,10 +799,12 @@ sxe2_rx_mbuf_common_fields_fill(struct sxe2_rx_queue *rxq, struct rte_mbuf *mbuf
 
 	mbuf->ol_flags = 0;
 	mbuf->packet_type = ptype_tbl[SXE2_RX_DESC_PTYPE_VAL_GET(qword1)];
-
 	pkt_flags = sxe2_rx_desc_error_para(rxq, rxd);
 	sxe2_rx_desc_vlan_para_fill(mbuf, rxd);
 	sxe2_rx_desc_filter_para_fill(rxq, mbuf, rxd);
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+	sxe2_rx_desc_ptp_para_fill(rxq, mbuf, rxd);
+#endif
 
 	mbuf->ol_flags |= pkt_flags;
 }
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 02/20] net/sxe2: add AVX2 vector data path for Rx and Tx
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Added AVX256 vectorized versions of Rx and Tx data path functions to
improve packet processing performance.

The vector path uses AVX2 SIMD instructions to process multiple
descriptors per loop, significantly reducing the per-packet overhead.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>

net/sxe2: support AVX512 vectorized path for Rx and Tx
---
 drivers/net/sxe2/meson.build          |   9 +
 drivers/net/sxe2/sxe2_txrx.c          |  38 +-
 drivers/net/sxe2/sxe2_txrx_vec.h      |  12 +-
 drivers/net/sxe2/sxe2_txrx_vec_avx2.c | 776 ++++++++++++++++++++++++++
 4 files changed, 830 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx2.c

diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 7bd0d8120c..c225dd7cd8 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -39,6 +39,15 @@ if arch_subdir == 'x86'
                         c_args: avx512_args)
                 objs += sxe2_avx512_lib.extract_objects('sxe2_txrx_vec_avx512.c')
         endif
+        sxe2_avx2_lib = static_library('sxe2_avx2_lib',
+                'sxe2_txrx_vec_avx2.c',
+                dependencies: [static_rte_ethdev,
+                        static_rte_kvargs, static_rte_hash,
+                        static_rte_security, static_rte_cryptodev,
+                        static_rte_bus_pci],
+                include_directories: includes,
+                c_args: [cflags, '-mavx2'])
+        objs += sxe2_avx2_lib.extract_objects('sxe2_txrx_vec_avx2.c')
 endif
 
 sources += files(
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index aa1c474088..eaf95259a5 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -167,8 +167,14 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
 				PMD_LOG_INFO(TX, "AVX512 is not supported in build env.");
 #endif
 			}
-			if ((tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) == 0)
-				tx_mode_flags |= SXE2_TX_MODE_VEC_SSE;
+			if (((tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) == 0) &&
+			    ((rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2) == 1) ||
+			    (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) == 1)) &&
+			    (rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256))
+				tx_mode_flags |= SXE2_TX_MODE_VEC_AVX2;
+
+			if ((0 == (tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK)))
+				tx_mode_flags |=  SXE2_TX_MODE_VEC_SSE;
 #endif
 			if (tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) {
 				ret = sxe2_tx_queues_vec_prepare(dev);
@@ -197,6 +203,13 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
 				dev->tx_pkt_burst = sxe2_tx_pkts_vec_avx512_simple;
 			}
 #endif
+		} else if (tx_mode_flags & SXE2_TX_MODE_VEC_AVX2) {
+			if (tx_mode_flags & SXE2_TX_MODE_VEC_OFFLOAD) {
+				dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
+				dev->tx_pkt_burst = sxe2_tx_pkts_vec_avx2;
+			} else {
+				dev->tx_pkt_burst = sxe2_tx_pkts_vec_avx2_simple;
+			}
 		} else {
 			if (tx_mode_flags & SXE2_TX_MODE_VEC_OFFLOAD) {
 				dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
@@ -231,6 +244,10 @@ static const struct {
 	{ sxe2_tx_pkts_vec_avx512_simple,
 	      "Vector AVX512 Simple" },
 #endif
+	{ sxe2_tx_pkts_vec_avx2,
+	      "Vector AVX2" },
+	{ sxe2_tx_pkts_vec_avx2_simple,
+	      "Vector AVX2 Simple" },
 	{ sxe2_tx_pkts_vec_sse,
 	      "Vector SSE" },
 	{ sxe2_tx_pkts_vec_sse_simple,
@@ -330,7 +347,13 @@ void sxe2_rx_mode_func_set(struct rte_eth_dev *dev)
 				PMD_LOG_INFO(RX, "AVX512 support detected but not enabled");
 #endif
 			}
-			if ((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) == 0 &&
+			if (((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) == 0) &&
+				((rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2) == 1) ||
+				(rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) == 1)) &&
+				(rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256))
+				rx_mode_flags |= SXE2_RX_MODE_VEC_AVX2;
+
+			if (((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) == 0) &&
 				rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
 				rx_mode_flags |= SXE2_RX_MODE_VEC_SSE;
 #endif
@@ -354,6 +377,11 @@ void sxe2_rx_mode_func_set(struct rte_eth_dev *dev)
 			else
 				dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_avx512;
 #endif
+		} else if (rx_mode_flags & SXE2_RX_MODE_VEC_AVX2) {
+			if (rx_mode_flags & SXE2_RX_MODE_VEC_OFFLOAD)
+				dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_avx2_offload;
+			else
+				dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_avx2;
 		} else {
 			dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_sse_offload;
 		}
@@ -381,6 +409,10 @@ static const struct {
 	{ sxe2_rx_pkts_scattered_vec_avx512_offload,
 	      "Offload Vector AVX512 Scattered" },
 #endif
+	{ sxe2_rx_pkts_scattered_vec_avx2,
+	      "Vector AVX2 Scattered" },
+	{ sxe2_rx_pkts_scattered_vec_avx2_offload,
+	      "Offload Vector AVX2 Scattered" },
 	{ sxe2_rx_pkts_scattered_vec_sse_offload,
 	      "Vector SSE Scattered" },
 #endif
diff --git a/drivers/net/sxe2/sxe2_txrx_vec.h b/drivers/net/sxe2/sxe2_txrx_vec.h
index af7c8d12b2..369777606f 100644
--- a/drivers/net/sxe2/sxe2_txrx_vec.h
+++ b/drivers/net/sxe2/sxe2_txrx_vec.h
@@ -11,19 +11,21 @@
 #define SXE2_RX_MODE_VEC_SIMPLE    RTE_BIT32(0)
 #define SXE2_RX_MODE_VEC_OFFLOAD   RTE_BIT32(1)
 #define SXE2_RX_MODE_VEC_SSE       RTE_BIT32(2)
+#define SXE2_RX_MODE_VEC_AVX2      RTE_BIT32(3)
 #define SXE2_RX_MODE_VEC_AVX512    RTE_BIT32(4)
 #define SXE2_RX_MODE_BATCH_ALLOC   RTE_BIT32(10)
 #define SXE2_RX_MODE_VEC_SET_MASK	(SXE2_RX_MODE_VEC_SIMPLE | \
 			SXE2_RX_MODE_VEC_OFFLOAD | SXE2_RX_MODE_VEC_SSE | \
-			SXE2_RX_MODE_VEC_AVX512)
+			SXE2_RX_MODE_VEC_AVX2 | SXE2_RX_MODE_VEC_AVX512)
 #define SXE2_TX_MODE_VEC_SIMPLE   RTE_BIT32(0)
 #define SXE2_TX_MODE_VEC_OFFLOAD  RTE_BIT32(1)
 #define SXE2_TX_MODE_VEC_SSE      RTE_BIT32(2)
+#define SXE2_TX_MODE_VEC_AVX2     RTE_BIT32(3)
 #define SXE2_TX_MODE_VEC_AVX512   RTE_BIT32(4)
 #define SXE2_TX_MODE_SIMPLE_BATCH RTE_BIT32(10)
 #define SXE2_TX_MODE_VEC_SET_MASK	(SXE2_TX_MODE_VEC_SIMPLE | \
 			SXE2_TX_MODE_VEC_OFFLOAD | SXE2_TX_MODE_VEC_SSE | \
-			SXE2_TX_MODE_VEC_AVX512)
+			SXE2_TX_MODE_VEC_AVX2 | SXE2_TX_MODE_VEC_AVX512)
 #define SXE2_TX_VEC_NO_SUPPORT_OFFLOAD (		  \
 			RTE_ETH_TX_OFFLOAD_MULTI_SEGS |		  \
 			RTE_ETH_TX_OFFLOAD_QINQ_INSERT |	  \
@@ -68,6 +70,12 @@ uint16_t sxe2_rx_pkts_scattered_vec_avx512(void *rx_queue,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t sxe2_rx_pkts_scattered_vec_avx512_offload(void *rx_queue,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_avx2_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_rx_pkts_scattered_vec_avx2(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_rx_pkts_scattered_vec_avx2_offload(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 #endif
 int32_t __rte_cold sxe2_tx_vec_support_check(struct rte_eth_dev *dev, uint32_t *vec_flags);
 int32_t __rte_cold sxe2_tx_queues_vec_prepare(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_txrx_vec_avx2.c b/drivers/net/sxe2/sxe2_txrx_vec_avx2.c
new file mode 100644
index 0000000000..72b09850b6
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_vec_avx2.c
@@ -0,0 +1,776 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_vect.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_common_log.h"
+#include "sxe2_queue.h"
+#include "sxe2_txrx_vec.h"
+#include "sxe2_txrx_vec_common.h"
+#include "sxe2_vsi.h"
+
+static inline void
+sxe2_tx_desc_fill_one_avx2(volatile union sxe2_tx_data_desc *desc, struct rte_mbuf *pkt,
+			   uint64_t desc_cmd, bool with_offloads)
+{
+	__m128i data_desc;
+	uint64_t desc_qw1;
+	uint32_t desc_offset;
+
+	desc_qw1 = (SXE2_TX_DESC_DTYPE_DATA |
+		   ((uint64_t)desc_cmd) << SXE2_TX_DATA_DESC_CMD_SHIFT |
+		   ((uint64_t)pkt->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+
+	desc_offset = SXE2_TX_DATA_DESC_MACLEN_VAL(pkt->l2_len);
+	desc_qw1 |= ((uint64_t)desc_offset) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+	if (with_offloads)
+		sxe2_tx_desc_fill_offloads(pkt, &desc_qw1);
+
+	data_desc = _mm_set_epi64x(desc_qw1, rte_pktmbuf_iova(pkt));
+	_mm_store_si128(RTE_CAST_PTR(__m128i *, desc), data_desc);
+}
+
+static __rte_always_inline void
+sxe2_tx_desc_fill_avx2(volatile union sxe2_tx_data_desc *desc, struct rte_mbuf **pkts,
+		       uint16_t pkts_num, uint64_t desc_cmd, bool with_offloads)
+{
+	__m256i desc_group0;
+	__m256i desc_group1;
+	uint64_t desc0_qw1;
+	uint64_t desc1_qw1;
+	uint64_t desc2_qw1;
+	uint64_t desc3_qw1;
+
+	const uint64_t desc_qw1_com = (SXE2_TX_DESC_DTYPE_DATA |
+					((uint64_t)desc_cmd) << SXE2_TX_DATA_DESC_CMD_SHIFT);
+	uint32_t desc_offset[4] = {0};
+
+	if (((uint64_t)desc & 0x1F) != 0 && pkts_num != 0) {
+		sxe2_tx_desc_fill_one_avx2(desc, *pkts, desc_cmd, with_offloads);
+		pkts_num--;
+		desc++;
+		pkts++;
+	}
+
+	while (pkts_num > 3) {
+		desc3_qw1 = (desc_qw1_com |
+					((uint64_t)pkts[3]->data_len)
+					<< SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+
+		desc_offset[3] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[3]->l2_len);
+		desc3_qw1 |= ((uint64_t)desc_offset[3]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[3], &desc3_qw1);
+
+		desc2_qw1 = (desc_qw1_com |
+					((uint64_t)pkts[2]->data_len)
+					<< SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+		desc_offset[2] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[2]->l2_len);
+		desc2_qw1 |= ((uint64_t)desc_offset[2]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[2], &desc2_qw1);
+
+		desc1_qw1 = (desc_qw1_com |
+					((uint64_t)pkts[1]->data_len)
+					<< SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+		desc_offset[1] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[1]->l2_len);
+		desc1_qw1 |= ((uint64_t)desc_offset[1]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[1], &desc1_qw1);
+
+		desc0_qw1 = (desc_qw1_com |
+					((uint64_t)pkts[0]->data_len)
+					<< SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+		desc_offset[0] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[0]->l2_len);
+		desc0_qw1 |= ((uint64_t)desc_offset[0]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[0], &desc0_qw1);
+
+		desc_group1 = _mm256_set_epi64x(desc3_qw1, rte_pktmbuf_iova(pkts[3]),
+					desc2_qw1, rte_pktmbuf_iova(pkts[2]));
+
+		desc_group0 = _mm256_set_epi64x(desc1_qw1, rte_pktmbuf_iova(pkts[1]),
+					desc0_qw1, rte_pktmbuf_iova(pkts[0]));
+
+		_mm256_store_si256(RTE_CAST_PTR(__m256i *, desc + 2), desc_group1);
+		_mm256_store_si256(RTE_CAST_PTR(__m256i *, desc), desc_group0);
+
+		pkts_num -= 4;
+		desc     += 4;
+		pkts     += 4;
+	}
+
+	while (pkts_num) {
+		sxe2_tx_desc_fill_one_avx2(desc, *pkts, desc_cmd, with_offloads);
+		pkts_num--;
+		desc++;
+		pkts++;
+	}
+}
+
+static __rte_always_inline uint16_t
+sxe2_tx_pkts_vec_avx2_batch(struct sxe2_tx_queue *txq, struct rte_mbuf **tx_pkts,
+			    uint16_t nb_pkts, bool with_offloads)
+{
+	volatile union sxe2_tx_data_desc *desc;
+	struct sxe2_tx_buffer *buffer;
+	uint16_t next_use;
+	uint16_t res_num;
+	uint16_t tx_num;
+
+	if (txq->desc_free_num < txq->free_thresh)
+		(void)sxe2_tx_bufs_free_vec(txq);
+
+	nb_pkts = RTE_MIN(txq->desc_free_num, nb_pkts);
+	if (unlikely(nb_pkts == 0)) {
+		PMD_LOG_DEBUG(TX, "Tx pkts avx2 batch: may not enough free desc, "
+				"free_desc=%u, need_tx_pkts=%u",
+				txq->desc_free_num, nb_pkts);
+		goto l_end;
+	}
+	tx_num = nb_pkts;
+
+	next_use = txq->next_use;
+	desc     = &txq->desc_ring[next_use];
+	buffer   = &txq->buffer_ring[next_use];
+
+	txq->desc_free_num -= nb_pkts;
+
+	res_num = txq->ring_depth - txq->next_use;
+
+	if (tx_num >= res_num) {
+		sxe2_tx_pkts_mbuf_fill(buffer, tx_pkts, res_num);
+
+		sxe2_tx_desc_fill_avx2(desc, tx_pkts, res_num,
+				SXE2_TX_DATA_DESC_CMD_EOP, with_offloads);
+		tx_pkts += (res_num - 1);
+		desc    += (res_num - 1);
+
+		sxe2_tx_desc_fill_one_avx2(desc, *tx_pkts++,
+				(SXE2_TX_DATA_DESC_CMD_EOP | SXE2_TX_DATA_DESC_CMD_RS),
+				with_offloads);
+
+		tx_num -= res_num;
+
+		next_use     = 0;
+		txq->next_rs = txq->rs_thresh - 1;
+		desc         = &txq->desc_ring[next_use];
+		buffer       = &txq->buffer_ring[next_use];
+	}
+
+	sxe2_tx_pkts_mbuf_fill(buffer, tx_pkts, tx_num);
+
+	sxe2_tx_desc_fill_avx2(desc, tx_pkts, tx_num,
+			SXE2_TX_DATA_DESC_CMD_EOP, with_offloads);
+
+	next_use += tx_num;
+	if (next_use > txq->next_rs) {
+		txq->desc_ring[txq->next_rs].read.type_cmd_off_bsz_l2t |=
+			rte_cpu_to_le_64(SXE2_TX_DATA_DESC_CMD_RS_MASK);
+
+		txq->next_rs += txq->rs_thresh;
+	}
+	txq->next_use = next_use;
+	SXE2_PCI_REG_WRITE_WC(txq->tdt_reg_addr, next_use);
+	PMD_LOG_DEBUG(TX, "port_id=%u queue_id=%u next_use=%u send_pkts=%u",
+			txq->port_id, txq->queue_id, next_use, nb_pkts);
+l_end:
+	return nb_pkts;
+}
+
+static __rte_always_inline uint16_t
+sxe2_tx_pkts_vec_avx2_common(struct sxe2_tx_queue *txq, struct rte_mbuf **tx_pkts,
+			     uint16_t nb_pkts, bool with_offloads)
+{
+	uint16_t tx_done_num = 0;
+	uint16_t tx_once_num;
+	uint16_t tx_need_num;
+
+	while (nb_pkts) {
+		tx_need_num = RTE_MIN(nb_pkts, txq->rs_thresh);
+		tx_once_num = sxe2_tx_pkts_vec_avx2_batch(txq,
+					tx_pkts + tx_done_num, tx_need_num, with_offloads);
+
+		nb_pkts     -= tx_once_num;
+		tx_done_num += tx_once_num;
+
+		if (tx_once_num < tx_need_num)
+			break;
+	}
+	return tx_done_num;
+}
+
+uint16_t sxe2_tx_pkts_vec_avx2_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_tx_pkts_vec_avx2_common(tx_queue, tx_pkts, nb_pkts, false);
+}
+
+uint16_t sxe2_tx_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_tx_pkts_vec_avx2_common(tx_queue, tx_pkts, nb_pkts, true);
+}
+
+static inline void sxe2_rx_queue_rearm_avx2(struct sxe2_rx_queue *rxq)
+{
+	volatile union sxe2_rx_desc *desc;
+	struct rte_mbuf **buffer;
+	struct rte_mbuf *mbuf0, *mbuf1;
+	__m128i dma_addr0, dma_addr1;
+	__m128i virt_addr0, virt_addr1;
+	__m128i hdr_room = _mm_set_epi64x(RTE_PKTMBUF_HEADROOM, RTE_PKTMBUF_HEADROOM);
+	int32_t ret;
+	uint16_t i;
+	uint16_t new_tail;
+
+	buffer = &rxq->buffer_ring[rxq->realloc_start];
+	desc   = &rxq->desc_ring[rxq->realloc_start];
+
+	ret = rte_mempool_get_bulk(rxq->mb_pool, (void *)buffer, SXE2_RX_REARM_THRESH_VEC);
+	if (ret != 0) {
+		if ((rxq->realloc_num + SXE2_RX_REARM_THRESH_VEC) >= rxq->ring_depth) {
+			dma_addr0 = _mm_setzero_si128();
+			for (i = 0; i < SXE2_RX_NUM_PER_LOOP_AVX; ++i) {
+				buffer[i] = &rxq->fake_mbuf;
+				_mm_store_si128(RTE_CAST_PTR(__m128i *, &desc[i].read), dma_addr0);
+			}
+		}
+
+		rxq->vsi->adapter->dev_info.dev_data->rx_mbuf_alloc_failed +=
+				SXE2_RX_REARM_THRESH_VEC;
+		return;
+	}
+
+	for (i = 0; i < SXE2_RX_REARM_THRESH_VEC; i += 2, buffer += 2) {
+		mbuf0 = buffer[0];
+		mbuf1 = buffer[1];
+#if RTE_IOVA_IN_MBUF
+
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, buf_iova) !=
+				 offsetof(struct rte_mbuf, buf_addr) + 8);
+#endif
+		virt_addr0 = _mm_loadu_si128((__m128i *)&mbuf0->buf_addr);
+		virt_addr1 = _mm_loadu_si128((__m128i *)&mbuf1->buf_addr);
+
+#if RTE_IOVA_IN_MBUF
+
+		dma_addr0 = _mm_unpackhi_epi64(virt_addr0, virt_addr0);
+		dma_addr1 = _mm_unpackhi_epi64(virt_addr1, virt_addr1);
+#else
+
+		dma_addr0 = _mm_unpacklo_epi64(virt_addr0, virt_addr0);
+		dma_addr1 = _mm_unpacklo_epi64(virt_addr1, virt_addr1);
+#endif
+
+		dma_addr0 = _mm_add_epi64(dma_addr0, hdr_room);
+		dma_addr1 = _mm_add_epi64(dma_addr1, hdr_room);
+
+		_mm_store_si128(RTE_CAST_PTR(__m128i *, &desc++->read), dma_addr0);
+		_mm_store_si128(RTE_CAST_PTR(__m128i *, &desc++->read), dma_addr1);
+	}
+
+	rxq->realloc_start += SXE2_RX_REARM_THRESH_VEC;
+	if (rxq->realloc_start >= rxq->ring_depth)
+		rxq->realloc_start = 0;
+	rxq->realloc_num -= SXE2_RX_REARM_THRESH_VEC;
+
+	new_tail = (rxq->realloc_start == 0) ?
+		(rxq->ring_depth - 1) : (rxq->realloc_start - 1);
+	SXE2_PCI_REG_WRITE_WC(rxq->rdt_reg_addr, new_tail);
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_common_vec_avx2(struct sxe2_rx_queue *rxq,
+			     struct rte_mbuf **rx_pkts, uint16_t nb_pkts, uint8_t *split_rxe_flags,
+			     uint8_t *umbcast_flags, bool do_offload)
+{
+	const uint32_t *ptype_tbl = rxq->vsi->adapter->ptype_tbl;
+	const __m256i mbuf_init   = _mm256_set_epi64x(0, 0, 0, rxq->mbuf_init_value);
+	struct rte_mbuf **buffer;
+	volatile union sxe2_rx_desc *desc;
+	__m256i mbufs6_7, mbufs4_5, mbufs2_3, mbufs0_1;
+	uint32_t bit_num;
+	uint16_t done_num;
+	uint16_t i = 0;
+	uint16_t j = 0;
+
+	buffer   = &rxq->buffer_ring[rxq->processing_idx];
+	desc     = &rxq->desc_ring[rxq->processing_idx];
+	done_num = 0;
+
+	rte_prefetch0(desc);
+
+	nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, SXE2_RX_NUM_PER_LOOP_AVX);
+
+	if (rxq->realloc_num > SXE2_RX_REARM_THRESH_VEC)
+		sxe2_rx_queue_rearm_avx2(rxq);
+
+	if (0 == (rte_le_to_cpu_64(desc->wb.status_err_ptype_len) &
+				SXE2_RX_DESC_STATUS_DD_MASK))
+		goto l_end;
+
+	const __m256i crc_adjust =
+		_mm256_set_epi16(0, 0, 0, -rxq->crc_len,
+				 0, -rxq->crc_len, 0,
+				 0, 0, 0, 0,
+				 -rxq->crc_len, 0, -rxq->crc_len, 0, 0);
+
+	const __m256i dd_mask = _mm256_set1_epi32(1);
+	const __m256i rvp_shuf_mask =
+		_mm256_set_epi8(7, 6, 5, 4,
+				3, 2, 13, 12,
+				0xFF, 0xFF, 13, 12,
+				0xFF, 0xFF, 0xFF, 0xFF,
+				7, 6, 5, 4,
+				3, 2, 13, 12,
+				0xFF, 0xFF, 13, 12,
+				0xFF, 0xFF, 0xFF, 0xFF);
+
+	const __m128i eop_shuf_mask =
+		_mm_set_epi8(0xFF, 0xFF, 0xFF, 0xFF,
+			     0xFF, 0xFF, 0xFF, 0xFF,
+			     8, 0, 10, 2,
+			     12, 4, 14, 6);
+
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, pkt_len) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 4);
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, data_len) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 8);
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, vlan_tci) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 10);
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, hash) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 12);
+
+	for (i = 0; i < nb_pkts; i += SXE2_RX_NUM_PER_LOOP_AVX,
+				desc += SXE2_RX_NUM_PER_LOOP_AVX) {
+		_mm256_storeu_si256((void *)&rx_pkts[i],
+					_mm256_loadu_si256((void *)&buffer[i]));
+#ifdef RTE_ARCH_X86_64
+		_mm256_storeu_si256((void *)&rx_pkts[i + 4],
+					_mm256_loadu_si256((void *)&buffer[i + 4]));
+#endif
+
+		const __m128i desc7 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 7));
+		rte_compiler_barrier();
+		const __m128i desc6 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 6));
+		rte_compiler_barrier();
+		const __m128i desc5 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 5));
+		rte_compiler_barrier();
+		const __m128i desc4 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 4));
+		rte_compiler_barrier();
+		const __m128i desc3 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 3));
+		rte_compiler_barrier();
+		const __m128i desc2 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 2));
+		rte_compiler_barrier();
+		const __m128i desc1 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 1));
+		rte_compiler_barrier();
+		const __m128i desc0 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 0));
+
+		const __m256i descs6_7 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc6), desc7, 1);
+		const __m256i descs4_5 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc4), desc5, 1);
+		const __m256i descs2_3 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc2), desc3, 1);
+		const __m256i descs0_1 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc0), desc1, 1);
+
+		if (split_rxe_flags) {
+			for (j = 0; j < SXE2_RX_NUM_PER_LOOP_AVX; j++)
+				rte_mbuf_prefetch_part2(rx_pkts[i + j]);
+		}
+
+		mbufs6_7 = _mm256_shuffle_epi8(descs6_7, rvp_shuf_mask);
+		mbufs4_5 = _mm256_shuffle_epi8(descs4_5, rvp_shuf_mask);
+
+		mbufs6_7 = _mm256_add_epi16(mbufs6_7, crc_adjust);
+		mbufs4_5 = _mm256_add_epi16(mbufs4_5, crc_adjust);
+
+		const __m256i ptype_mask = _mm256_set1_epi32(SXE2_RX_DESC_PTYPE_MASK);
+
+		const __m256i staterrs4_7 = _mm256_unpackhi_epi32(descs6_7, descs4_5);
+
+		__m256i ptypes4_7 = _mm256_and_si256(staterrs4_7, ptype_mask);
+
+		const uint16_t ptype7 = _mm256_extract_epi16(ptypes4_7, 9);
+		const uint16_t ptype6 = _mm256_extract_epi16(ptypes4_7, 1);
+		const uint16_t ptype5 = _mm256_extract_epi16(ptypes4_7, 11);
+		const uint16_t ptype4 = _mm256_extract_epi16(ptypes4_7, 3);
+
+		mbufs6_7 = _mm256_insert_epi32(mbufs6_7, ptype_tbl[ptype7], 4);
+		mbufs6_7 = _mm256_insert_epi32(mbufs6_7, ptype_tbl[ptype6], 0);
+		mbufs4_5 = _mm256_insert_epi32(mbufs4_5, ptype_tbl[ptype5], 4);
+		mbufs4_5 = _mm256_insert_epi32(mbufs4_5, ptype_tbl[ptype4], 0);
+
+		mbufs2_3 = _mm256_shuffle_epi8(descs2_3, rvp_shuf_mask);
+		mbufs0_1 = _mm256_shuffle_epi8(descs0_1, rvp_shuf_mask);
+
+		mbufs2_3 = _mm256_add_epi16(mbufs2_3, crc_adjust);
+		mbufs0_1 = _mm256_add_epi16(mbufs0_1, crc_adjust);
+
+		const __m256i staterrs0_3 = _mm256_unpackhi_epi32(descs2_3, descs0_1);
+
+		__m256i ptypes0_3 = _mm256_and_si256(staterrs0_3, ptype_mask);
+
+		const uint16_t ptype3 = _mm256_extract_epi16(ptypes0_3, 9);
+		const uint16_t ptype2 = _mm256_extract_epi16(ptypes0_3, 1);
+		const uint16_t ptype1 = _mm256_extract_epi16(ptypes0_3, 11);
+		const uint16_t ptype0 = _mm256_extract_epi16(ptypes0_3, 3);
+
+		mbufs2_3 = _mm256_insert_epi32(mbufs2_3, ptype_tbl[ptype3], 4);
+		mbufs2_3 = _mm256_insert_epi32(mbufs2_3, ptype_tbl[ptype2], 0);
+		mbufs0_1 = _mm256_insert_epi32(mbufs0_1, ptype_tbl[ptype1], 4);
+		mbufs0_1 = _mm256_insert_epi32(mbufs0_1, ptype_tbl[ptype0], 0);
+
+		__m256i staterrs0_7 = _mm256_unpacklo_epi64(staterrs4_7, staterrs0_3);
+
+		__m256i stu_len0_7 = _mm256_unpackhi_epi64(staterrs4_7, staterrs0_3);
+		__m256i mbuf_flags = _mm256_setzero_si256();
+
+		if (do_offload) {
+			const __m256i desc_flags_mask = _mm256_set1_epi32(0x00001C04);
+			const __m256i desc_flags_rss_mask = _mm256_set1_epi32(0x20000000);
+			const __m256i vlan_flags =
+				_mm256_set_epi8
+				(0, 0, 0, 0, 0, 0, 0, 0,
+				 0, 0, 0,
+				 RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED,
+				 0, 0, 0, 0,
+				 0, 0, 0, 0, 0, 0, 0, 0,
+				 0, 0, 0,
+				 RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED,
+				 0, 0, 0, 0);
+
+			const __m256i rss_flags =
+				_mm256_set_epi8
+				(0, 0, 0, 0, 0, 0, 0, 0,
+				 0, 0, 0, RTE_MBUF_F_RX_RSS_HASH, 0, 0, 0, 0,
+				 0, 0, 0, 0, 0, 0, 0, 0,
+				 0, 0, 0, RTE_MBUF_F_RX_RSS_HASH, 0, 0, 0, 0);
+
+			const __m256i cksum_flags =
+				_mm256_set_epi8
+				(0, 0, 0, 0, 0, 0, 0, 0,
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+
+				 0, 0, 0, 0, 0, 0, 0, 0,
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD |
+					RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_BAD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+				 ((RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+					RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1));
+
+			const __m256i cksum_mask =
+				_mm256_set1_epi32
+				(RTE_MBUF_F_RX_IP_CKSUM_MASK |
+				RTE_MBUF_F_RX_L4_CKSUM_MASK |
+				RTE_MBUF_F_RX_OUTER_L4_CKSUM_MASK |
+				RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD);
+			const __m256i vlan_mask =
+				_mm256_set1_epi32
+				(RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED);
+
+			__m256i tmp_flags;
+			__m256i descs_flags = _mm256_and_si256(staterrs0_7, desc_flags_mask);
+			stu_len0_7 = _mm256_and_si256(stu_len0_7, desc_flags_rss_mask);
+
+			tmp_flags = _mm256_shuffle_epi8(vlan_flags, descs_flags);
+			mbuf_flags = _mm256_and_si256(tmp_flags, vlan_mask);
+
+			descs_flags = _mm256_srli_epi32(descs_flags, 10);
+			tmp_flags = _mm256_shuffle_epi8(cksum_flags, descs_flags);
+			tmp_flags = _mm256_slli_epi32(tmp_flags, 1);
+			tmp_flags = _mm256_and_si256(tmp_flags, cksum_mask);
+			mbuf_flags = _mm256_or_si256(mbuf_flags, tmp_flags);
+
+			descs_flags = _mm256_srli_epi32(stu_len0_7, 27);
+			tmp_flags = _mm256_shuffle_epi8(rss_flags, descs_flags);
+			mbuf_flags = _mm256_or_si256(mbuf_flags, tmp_flags);
+
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+
+			if (rxq->fnav_enable) {
+				__m256i fnav_vld0_3, fnav_vld4_7;
+				__m256i fnav_vld0_7;
+				__m256i v_zeros, v_ffff, v_u32_one;
+				const __m256i fdir_flags =
+					_mm256_set1_epi32
+					(RTE_MBUF_F_RX_FDIR | RTE_MBUF_F_RX_FDIR_ID);
+				fnav_vld0_3 = _mm256_unpacklo_epi32(descs2_3, descs0_1);
+				fnav_vld4_7 = _mm256_unpacklo_epi32(descs6_7, descs4_5);
+
+				fnav_vld0_7 = _mm256_unpacklo_epi64(fnav_vld4_7, fnav_vld0_3);
+
+				fnav_vld0_7 = _mm256_slli_epi32(fnav_vld0_7, 26);
+				fnav_vld0_7 = _mm256_srli_epi32(fnav_vld0_7, 31);
+
+				v_zeros = _mm256_setzero_si256();
+				v_ffff = _mm256_cmpeq_epi32(v_zeros, v_zeros);
+				v_u32_one = _mm256_srli_epi32(v_ffff, 31);
+
+				tmp_flags = _mm256_cmpeq_epi32(fnav_vld0_7, v_u32_one);
+
+				tmp_flags = _mm256_and_si256(tmp_flags, fdir_flags);
+
+				mbuf_flags = _mm256_or_si256(mbuf_flags, tmp_flags);
+
+				rx_pkts[i + 0]->hash.fdir.hi = desc[0].wb.fd_filter_id;
+				rx_pkts[i + 1]->hash.fdir.hi = desc[1].wb.fd_filter_id;
+				rx_pkts[i + 2]->hash.fdir.hi = desc[2].wb.fd_filter_id;
+				rx_pkts[i + 3]->hash.fdir.hi = desc[3].wb.fd_filter_id;
+				rx_pkts[i + 4]->hash.fdir.hi = desc[4].wb.fd_filter_id;
+				rx_pkts[i + 5]->hash.fdir.hi = desc[5].wb.fd_filter_id;
+				rx_pkts[i + 6]->hash.fdir.hi = desc[6].wb.fd_filter_id;
+				rx_pkts[i + 7]->hash.fdir.hi = desc[7].wb.fd_filter_id;
+			}
+#endif
+		}
+
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, ol_flags) !=
+				 offsetof(struct rte_mbuf, rearm_data) + 8);
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, rx_descriptor_fields1) !=
+				 offsetof(struct rte_mbuf, rearm_data) + 16);
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, rearm_data) !=
+				 RTE_ALIGN(offsetof(struct rte_mbuf, rearm_data), 16));
+
+		__m256i rearm_arr[8];
+
+		rearm_arr[6] = _mm256_blend_epi32(mbuf_init, _mm256_slli_si256(mbuf_flags, 8), 4);
+		rearm_arr[4] = _mm256_blend_epi32(mbuf_init, _mm256_slli_si256(mbuf_flags, 4), 4);
+		rearm_arr[2] = _mm256_blend_epi32(mbuf_init, mbuf_flags, 4);
+		rearm_arr[0] = _mm256_blend_epi32(mbuf_init, _mm256_srli_si256(mbuf_flags, 4), 4);
+
+		rearm_arr[6] = _mm256_permute2f128_si256(rearm_arr[6], mbufs6_7, 0x20);
+		rearm_arr[4] = _mm256_permute2f128_si256(rearm_arr[4], mbufs4_5, 0x20);
+		rearm_arr[2] = _mm256_permute2f128_si256(rearm_arr[2], mbufs2_3, 0x20);
+		rearm_arr[0] = _mm256_permute2f128_si256(rearm_arr[0], mbufs0_1, 0x20);
+
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 6]->rearm_data, rearm_arr[6]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 4]->rearm_data, rearm_arr[4]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 2]->rearm_data, rearm_arr[2]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 0]->rearm_data, rearm_arr[0]);
+
+		const __m256i tmp_mbuf_flags =
+			_mm256_castsi128_si256(_mm256_extracti128_si256(mbuf_flags, 1));
+
+		rearm_arr[7] =
+			_mm256_blend_epi32(mbuf_init, _mm256_slli_si256(tmp_mbuf_flags, 8), 4);
+		rearm_arr[5] =
+			_mm256_blend_epi32(mbuf_init, _mm256_slli_si256(tmp_mbuf_flags, 4), 4);
+		rearm_arr[3] =
+			_mm256_blend_epi32(mbuf_init, tmp_mbuf_flags, 4);
+		rearm_arr[1] =
+			_mm256_blend_epi32(mbuf_init, _mm256_srli_si256(tmp_mbuf_flags, 4), 4);
+
+		rearm_arr[7] = _mm256_blend_epi32(rearm_arr[7], mbufs6_7, 0XF0);
+		rearm_arr[5] = _mm256_blend_epi32(rearm_arr[5], mbufs4_5, 0XF0);
+		rearm_arr[3] = _mm256_blend_epi32(rearm_arr[3], mbufs2_3, 0XF0);
+		rearm_arr[1] = _mm256_blend_epi32(rearm_arr[1], mbufs0_1, 0XF0);
+
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 7]->rearm_data, rearm_arr[7]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 5]->rearm_data, rearm_arr[5]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 3]->rearm_data, rearm_arr[3]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 1]->rearm_data, rearm_arr[1]);
+
+		if (umbcast_flags != NULL) {
+			const __m256i umbcast_mask =
+					_mm256_set1_epi32(SXE2_RX_DESC_STATUS_UMBCAST_MASK);
+			__m256i umbcast_bits_256 = _mm256_and_si256(staterrs0_7,
+								    umbcast_mask);
+
+			umbcast_bits_256 = _mm256_srli_epi32(umbcast_bits_256, 24);
+
+			__m128i umbcast_bits_128 = _mm_packs_epi32
+							(_mm256_castsi256_si128(umbcast_bits_256),
+							 _mm256_extractf128_si256
+								(umbcast_bits_256, 1));
+
+			umbcast_bits_128 = _mm_shuffle_epi8(umbcast_bits_128, eop_shuf_mask);
+
+			*(uint64_t *)umbcast_flags = _mm_cvtsi128_si64(umbcast_bits_128);
+			umbcast_flags += SXE2_RX_NUM_PER_LOOP_AVX;
+		}
+
+		if (split_rxe_flags != NULL) {
+			const __m256i eop_rxe_mask = _mm256_set1_epi32
+							(SXE2_RX_DESC_STATUS_EOP_MASK |
+							 SXE2_RX_DESC_ERROR_RXE_MASK |
+							 SXE2_RX_DESC_ERROR_OVERSIZE_MASK);
+
+			const __m128i eop_mask_128 = _mm_set1_epi16(SXE2_RX_DESC_STATUS_EOP_MASK);
+			const __m128i rxe_mask_128 = _mm_set1_epi16(SXE2_RX_DESC_ERROR_RXE_MASK |
+					SXE2_RX_DESC_ERROR_OVERSIZE_MASK);
+
+			const __m256i tmp_stats = _mm256_and_si256(staterrs0_7, eop_rxe_mask);
+
+			const __m128i eop_rxe_bits = _mm_packs_epi32
+							(_mm256_castsi256_si128(tmp_stats),
+							 _mm256_extractf128_si256(tmp_stats, 1));
+
+			__m128i not_eop_bits = _mm_andnot_si128(eop_rxe_bits, eop_mask_128);
+
+			not_eop_bits = _mm_or_si128
+					(not_eop_bits,
+					 _mm_srli_epi16
+					(_mm_and_si128(eop_rxe_bits, rxe_mask_128),
+					7));
+
+			not_eop_bits = _mm_shuffle_epi8(not_eop_bits, eop_shuf_mask);
+
+			*(uint64_t *)split_rxe_flags = _mm_cvtsi128_si64(not_eop_bits);
+			split_rxe_flags += SXE2_RX_NUM_PER_LOOP_AVX;
+		}
+
+		staterrs0_7 = _mm256_and_si256(staterrs0_7, dd_mask);
+
+		staterrs0_7 = _mm256_packs_epi32(staterrs0_7, _mm256_setzero_si256());
+		bit_num = rte_popcount64
+				(_mm_cvtsi128_si64(_mm256_extracti128_si256(staterrs0_7, 1)));
+		bit_num += rte_popcount64
+				(_mm_cvtsi128_si64(_mm256_castsi256_si128(staterrs0_7)));
+
+		done_num += bit_num;
+
+		if (bit_num != SXE2_RX_NUM_PER_LOOP_AVX)
+			break;
+	}
+
+	rxq->processing_idx += done_num;
+	rxq->processing_idx &= (rxq->ring_depth - 1);
+	if ((1 == (rxq->processing_idx & 1)) && done_num > 1) {
+		rxq->processing_idx--;
+		done_num--;
+	}
+	rxq->realloc_num     += done_num;
+
+l_end:
+	PMD_LOG_DEBUG(RX, "port_id=%u queue_id=%u last_id=%u recv_pkts=%d",
+		rxq->port_id, rxq->queue_id, rxq->processing_idx, done_num);
+	return done_num;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_scattered_batch_vec_avx2(struct sxe2_rx_queue *rxq, struct rte_mbuf **rx_pkts,
+		uint16_t nb_pkts, bool do_offload)
+{
+	const uint64_t *split_rxe_flags64;
+	uint8_t split_rxe_flags[SXE2_RX_PKTS_BURST_BATCH_NUM_VEC] = {0};
+	uint8_t umbcast_flags[SXE2_RX_PKTS_BURST_BATCH_NUM_VEC] = {0};
+	uint16_t rx_done_num;
+	uint16_t rx_pkt_done_num;
+
+	rx_pkt_done_num = 0;
+
+	if (rxq->vsi->adapter->devargs.sw_stats_en) {
+		rx_done_num = sxe2_rx_pkts_common_vec_avx2(rxq, rx_pkts, nb_pkts,
+				split_rxe_flags, umbcast_flags, do_offload);
+	} else {
+		rx_done_num = sxe2_rx_pkts_common_vec_avx2(rxq, rx_pkts, nb_pkts,
+				split_rxe_flags, NULL, do_offload);
+	}
+	if (rx_done_num == 0)
+		goto l_end;
+
+	if (!rxq->vsi->adapter->devargs.sw_stats_en) {
+		split_rxe_flags64 = (uint64_t *)split_rxe_flags;
+
+		if (rxq->pkt_first_seg == NULL &&
+				split_rxe_flags64[0] == 0 && split_rxe_flags64[1] == 0 &&
+				split_rxe_flags64[2] == 0 && split_rxe_flags64[3] == 0) {
+			rx_pkt_done_num = rx_done_num;
+			goto l_end;
+		}
+
+		if (rxq->pkt_first_seg == NULL) {
+			while (rx_pkt_done_num < rx_done_num &&
+					split_rxe_flags[rx_pkt_done_num] == 0)
+				rx_pkt_done_num++;
+
+			if (rx_pkt_done_num == rx_done_num)
+				goto l_end;
+
+			rxq->pkt_first_seg = rx_pkts[rx_pkt_done_num];
+		}
+	}
+
+	rx_pkt_done_num += sxe2_rx_pkts_refactor(rxq, &rx_pkts[rx_pkt_done_num],
+			rx_done_num - rx_pkt_done_num, &split_rxe_flags[rx_pkt_done_num],
+			&umbcast_flags[rx_pkt_done_num]);
+
+l_end:
+	return rx_pkt_done_num;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_scattered_common_vec_avx2(struct sxe2_rx_queue *rxq, struct rte_mbuf **rx_pkts,
+		uint16_t nb_pkts, bool do_offload)
+{
+	uint16_t done_num = 0;
+	uint16_t once_num;
+
+	while (nb_pkts > SXE2_RX_PKTS_BURST_BATCH_NUM) {
+		once_num =
+		sxe2_rx_pkts_scattered_batch_vec_avx2(rxq,
+						      rx_pkts + done_num,
+						      SXE2_RX_PKTS_BURST_BATCH_NUM,
+						      do_offload);
+		done_num += once_num;
+		nb_pkts -= once_num;
+		if (once_num < SXE2_RX_PKTS_BURST_BATCH_NUM)
+			goto l_end;
+	}
+
+	done_num += sxe2_rx_pkts_scattered_batch_vec_avx2(rxq,
+			rx_pkts + done_num, nb_pkts, do_offload);
+l_end:
+	return done_num;
+}
+
+uint16_t sxe2_rx_pkts_scattered_vec_avx2(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_rx_pkts_scattered_common_vec_avx2(rx_queue,
+			rx_pkts, nb_pkts, false);
+}
+
+uint16_t sxe2_rx_pkts_scattered_vec_avx2_offload(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_rx_pkts_scattered_common_vec_avx2(rx_queue,
+			rx_pkts, nb_pkts, true);
+}
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 01/20] net/sxe2: support AVX512 vectorized path for Rx and Tx
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Add AVX512 vector data path for Rx and Tx burst functions.
The decision to use AVX512 is based on:
1. CPU hardware flags (AVX512F, AVX512BW).
2. Compiler support (CC_AVX512_SUPPORT).
3. Max SIMD bitwidth configuration.

Performance shows approximately X% improvement in small packet
forwarding scenarios.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/net/sxe2/meson.build            |  24 +
 drivers/net/sxe2/sxe2_drv_cmd.h         |  80 +--
 drivers/net/sxe2/sxe2_ethdev.c          |   2 +-
 drivers/net/sxe2/sxe2_txrx.c            |  92 ++-
 drivers/net/sxe2/sxe2_txrx_vec.c        |  46 +-
 drivers/net/sxe2/sxe2_txrx_vec.h        |  18 +-
 drivers/net/sxe2/sxe2_txrx_vec_avx512.c | 897 ++++++++++++++++++++++++
 7 files changed, 1099 insertions(+), 60 deletions(-)
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx512.c

diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 6b2eb75b0e..7bd0d8120c 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -15,6 +15,30 @@ includes += include_directories('../../common/sxe2')
 
 if arch_subdir == 'x86'
         sources += files('sxe2_txrx_vec_sse.c')
+
+        sxe2_avx512_cpu_support =(
+                cc.get_define('__AVX512F__', args: machine_args) != '' and
+                cc.get_define('__AVX512BW__', args: machine_args) != '')
+
+        sxe2_avx512_cc_support = (
+                not machine_args.contains('-mno-avx512f') and
+                cc.has_argument('-mavx512f') and
+                cc.has_argument('-mavx512bw'))
+
+        if sxe2_avx512_cpu_support == true or sxe2_avx512_cc_support == true
+                cflags += ['-DCC_AVX512_SUPPORT']
+                avx512_args = [cflags, '-mavx512f', '-mavx512bw']
+                if cc.has_argument('-march=skylake-avx512')
+                        avx512_args += '-march=skylake-avx512'
+                endif
+                sxe2_avx512_lib = static_library('sxe2_avx512_lib', 'sxe2_txrx_vec_avx512.c',
+                        dependencies: [static_rte_ethdev,
+                        static_rte_kvargs, static_rte_hash,
+                        static_rte_security, static_rte_cryptodev, static_rte_bus_pci],
+                        include_directories: includes,
+                        c_args: avx512_args)
+                objs += sxe2_avx512_lib.extract_objects('sxe2_txrx_vec_avx512.c')
+        endif
 endif
 
 sources += files(
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index bba6476c2e..ccc9c20ef4 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -67,20 +67,20 @@ enum sxe2_dev_type {
 	SXE2_DEV_T_MAX,
 };
 
-struct sxe2_drv_queue_caps {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_queue_caps {
 	uint16_t queues_cnt;
 	uint16_t base_idx_in_pf;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_msix_caps {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_msix_caps {
 	uint16_t msix_vectors_cnt;
 	uint16_t base_idx_in_func;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_rss_hash_caps {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_rss_hash_caps {
 	uint16_t hash_key_size;
 	uint16_t lut_key_size;
-};
+} __rte_packed_end;
 
 enum sxe2_vf_vsi_valid {
 	SXE2_VF_VSI_BOTH = 0,
@@ -89,18 +89,18 @@ enum sxe2_vf_vsi_valid {
 	SXE2_VF_VSI_MAX,
 };
 
-struct sxe2_drv_vsi_caps {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_caps {
 	uint16_t func_id;
 	uint16_t dpdk_vsi_id;
 	uint16_t kernel_vsi_id;
 	uint16_t vsi_type;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_representor_caps {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_representor_caps {
 	uint16_t cnt_repr_vf;
 	uint8_t rsv[2];
 	struct sxe2_drv_vsi_caps repr_vf_id[256];
-};
+} __rte_packed_end;
 
 enum sxe2_phys_port_name_type {
 	SXE2_PHYS_PORT_NAME_TYPE_NOTSET = 0,
@@ -111,25 +111,25 @@ enum sxe2_phys_port_name_type {
 	SXE2_PHYS_PORT_NAME_TYPE_UNKNOWN,
 };
 
-struct sxe2_switchdev_mode_info {
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_mode_info {
 	uint8_t pf_id;
 	uint8_t is_switchdev;
 	uint8_t rsv[2];
-};
+} __rte_packed_end;
 
-struct sxe2_switchdev_cpvsi_info {
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_cpvsi_info {
 	uint16_t cp_vsi_id;
 	uint8_t rsv[2];
-};
+} __rte_packed_end;
 
-struct sxe2_txsch_caps {
+struct __rte_aligned(4) __rte_packed_begin sxe2_txsch_caps {
 	uint8_t layer_cap;
 	uint8_t tm_mid_node_num;
 	uint8_t prio_num;
 	uint8_t rev;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_dev_caps_resp {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_dev_caps_resp {
 	struct sxe2_drv_queue_caps queue_caps;
 	struct sxe2_drv_msix_caps msix_caps;
 	struct sxe2_drv_rss_hash_caps rss_hash_caps;
@@ -141,24 +141,24 @@ struct sxe2_drv_dev_caps_resp {
 	uint8_t dev_type;
 	uint8_t rev;
 	uint32_t cap_flags;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_dev_info_resp {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_dev_info_resp {
 	uint64_t dsn;
 	uint16_t vsi_id;
 	uint8_t rsv[2];
 	uint8_t mac_addr[SXE2_ETH_ALEN];
 	uint8_t rsv2[2];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_dev_fw_info_resp {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_dev_fw_info_resp {
 	uint8_t main_version_id;
 	uint8_t sub_version_id;
 	uint8_t fix_version_id;
 	uint8_t build_id;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_rxq_ctxt {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_rxq_ctxt {
 	uint64_t dma_addr;
 	uint32_t max_lro_size;
 	uint32_t split_type_mask;
@@ -170,62 +170,62 @@ struct sxe2_drv_rxq_ctxt {
 	uint8_t keep_crc_en;
 	uint8_t split_en;
 	uint8_t desc_size;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_rxq_cfg_req {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_rxq_cfg_req {
 	uint16_t q_cnt;
 	uint16_t vsi_id;
 	uint16_t max_frame_size;
 	uint8_t rsv[2];
 	struct sxe2_drv_rxq_ctxt cfg[];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_txq_ctxt {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_txq_ctxt {
 	uint64_t dma_addr;
 	uint32_t sched_mode;
 	uint16_t queue_id;
 	uint16_t depth;
 	uint16_t vsi_id;
 	uint8_t rsv[2];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_txq_cfg_req {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_txq_cfg_req {
 	uint16_t q_cnt;
 	uint16_t vsi_id;
 	struct sxe2_drv_txq_ctxt cfg[];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_q_switch_req {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_q_switch_req {
 	uint16_t q_idx;
 	uint16_t vsi_id;
 	uint8_t is_enable;
 	uint8_t sched_mode;
 	uint8_t rsv[2];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_vsi_create_req_resp {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_create_req_resp {
 	uint16_t vsi_id;
 	uint16_t vsi_type;
 	struct sxe2_drv_queue_caps used_queues;
 	struct sxe2_drv_msix_caps used_msix;
-};
+} __rte_packed_end;
 
-struct sxe2_drv_vsi_free_req {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_free_req {
 	uint16_t vsi_id;
 	uint8_t rsv[2];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_vsi_info_get_req {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_info_get_req {
 	uint16_t vsi_id;
 	uint8_t rsv[2];
-};
+} __rte_packed_end;
 
-struct sxe2_drv_vsi_info_get_resp {
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_info_get_resp {
 	uint16_t vsi_id;
 	uint16_t vsi_type;
 	struct sxe2_drv_queue_caps used_queues;
 	struct sxe2_drv_msix_caps used_msix;
-};
+} __rte_packed_end;
 
 enum sxe2_drv_cmd_module {
 	SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index b6cc8703a7..066e1faf7e 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -891,7 +891,7 @@ static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev,
 static int32_t sxe2_parse_eth_devargs(struct rte_device *dev,
 			  struct rte_eth_devargs *eth_da)
 {
-	int ret = 0;
+	int32_t ret = 0;
 
 	if (dev->devargs == NULL)
 		return 0;
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index 8d17535301..aa1c474088 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -157,6 +157,19 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
 		if (ret == 0 &&
 		    rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128) {
 			tx_mode_flags = vec_flags;
+#ifdef RTE_ARCH_X86
+			if ((rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_512) &&
+			    (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) == 1) &&
+			    (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW) == 1)) {
+#ifdef CC_AVX512_SUPPORT
+				tx_mode_flags |= SXE2_TX_MODE_VEC_AVX512;
+#else
+				PMD_LOG_INFO(TX, "AVX512 is not supported in build env.");
+#endif
+			}
+			if ((tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) == 0)
+				tx_mode_flags |= SXE2_TX_MODE_VEC_SSE;
+#endif
 			if (tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) {
 				ret = sxe2_tx_queues_vec_prepare(dev);
 				if (ret != 0)
@@ -172,14 +185,25 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
 		tx_mode_flags = adapter->q_ctxt.tx_mode_flags;
 	}
 
-#ifdef RTE_ARCH_X86
 	if (tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) {
-		if (tx_mode_flags & SXE2_TX_MODE_VEC_OFFLOAD) {
-			dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
-			dev->tx_pkt_burst = sxe2_tx_pkts_vec_sse;
+		dev->tx_pkt_prepare = NULL;
+#ifdef RTE_ARCH_X86
+		if (tx_mode_flags & SXE2_TX_MODE_VEC_AVX512) {
+#ifdef CC_AVX512_SUPPORT
+			if (tx_mode_flags & SXE2_TX_MODE_VEC_OFFLOAD) {
+				dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
+				dev->tx_pkt_burst = sxe2_tx_pkts_vec_avx512;
+			} else {
+				dev->tx_pkt_burst = sxe2_tx_pkts_vec_avx512_simple;
+			}
+#endif
 		} else {
-			dev->tx_pkt_prepare = NULL;
-			dev->tx_pkt_burst = sxe2_tx_pkts_vec_sse_simple;
+			if (tx_mode_flags & SXE2_TX_MODE_VEC_OFFLOAD) {
+				dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
+				dev->tx_pkt_burst = sxe2_tx_pkts_vec_sse;
+			} else {
+				dev->tx_pkt_burst = sxe2_tx_pkts_vec_sse_simple;
+			}
 		}
 	} else {
 #endif
@@ -201,8 +225,16 @@ static const struct {
 } sxe2_tx_burst_infos[] = {
 	{ sxe2_tx_pkts,   "Scalar" },
 #ifdef RTE_ARCH_X86
-	{ sxe2_tx_pkts_vec_sse,        "Vector SSE" },
-	{ sxe2_tx_pkts_vec_sse_simple, "Vector SSE Simple" },
+#ifdef CC_AVX512_SUPPORT
+	{ sxe2_tx_pkts_vec_avx512,
+	      "Vector AVX512" },
+	{ sxe2_tx_pkts_vec_avx512_simple,
+	      "Vector AVX512 Simple" },
+#endif
+	{ sxe2_tx_pkts_vec_sse,
+	      "Vector SSE" },
+	{ sxe2_tx_pkts_vec_sse_simple,
+	      "Vector SSE Simple" },
 #endif
 };
 
@@ -288,6 +320,20 @@ void sxe2_rx_mode_func_set(struct rte_eth_dev *dev)
 		if (ret == 0 &&
 		    rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128) {
 			rx_mode_flags = vec_flags;
+#ifdef RTE_ARCH_X86
+			if ((rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_512) &&
+				(rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) == 1) &&
+				(rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW) == 1)) {
+#ifdef CC_AVX512_SUPPORT
+				rx_mode_flags |= SXE2_RX_MODE_VEC_AVX512;
+#else
+				PMD_LOG_INFO(RX, "AVX512 support detected but not enabled");
+#endif
+			}
+			if ((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) == 0 &&
+				rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
+				rx_mode_flags |= SXE2_RX_MODE_VEC_SSE;
+#endif
 			if ((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) != 0) {
 				ret = sxe2_rx_queues_vec_prepare(dev);
 				if (ret != 0)
@@ -301,7 +347,16 @@ void sxe2_rx_mode_func_set(struct rte_eth_dev *dev)
 
 #ifdef RTE_ARCH_X86
 	if (rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) {
-		dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_sse_offload;
+		if (rx_mode_flags & SXE2_RX_MODE_VEC_AVX512) {
+#ifdef CC_AVX512_SUPPORT
+			if (rx_mode_flags & SXE2_RX_MODE_VEC_OFFLOAD)
+				dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_avx512_offload;
+			else
+				dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_avx512;
+#endif
+		} else {
+			dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_sse_offload;
+		}
 		return;
 	}
 #endif
@@ -315,19 +370,30 @@ static const struct {
 	eth_rx_burst_t rx_burst;
 	const char *info;
 } sxe2_rx_burst_infos[] = {
-	{ sxe2_rx_pkts_scattered,          "Scalar Scattered" },
-	{ sxe2_rx_pkts_scattered_split,          "Scalar Scattered split" },
+	{ sxe2_rx_pkts_scattered,
+	      "Scalar Scattered" },
+	{ sxe2_rx_pkts_scattered_split,
+	      "Scalar Scattered split" },
 #ifdef RTE_ARCH_X86
-	{ sxe2_rx_pkts_scattered_vec_sse_offload,      "Vector SSE Scattered" },
+#ifdef CC_AVX512_SUPPORT
+	{ sxe2_rx_pkts_scattered_vec_avx512,
+	      "Vector AVX512 Scattered" },
+	{ sxe2_rx_pkts_scattered_vec_avx512_offload,
+	      "Offload Vector AVX512 Scattered" },
+#endif
+	{ sxe2_rx_pkts_scattered_vec_sse_offload,
+	      "Vector SSE Scattered" },
 #endif
 };
 
 int32_t sxe2_rx_burst_mode_get(struct rte_eth_dev *dev,
-			__rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode)
+			       __rte_unused uint16_t queue_id,
+			       struct rte_eth_burst_mode *mode)
 {
 	eth_rx_burst_t pkt_burst = dev->rx_pkt_burst;
 	int32_t ret = -EINVAL;
 	uint32_t i, size;
+
 	size = RTE_DIM(sxe2_rx_burst_infos);
 	for (i = 0; i < size; ++i) {
 		if (pkt_burst == sxe2_rx_burst_infos[i].rx_burst) {
diff --git a/drivers/net/sxe2/sxe2_txrx_vec.c b/drivers/net/sxe2/sxe2_txrx_vec.c
index 8df4954d86..cf004f5eb2 100644
--- a/drivers/net/sxe2/sxe2_txrx_vec.c
+++ b/drivers/net/sxe2/sxe2_txrx_vec.c
@@ -165,16 +165,54 @@ static void sxe2_tx_queue_mbufs_release_vec(struct sxe2_tx_queue *txq)
 		return;
 	}
 	i = txq->next_dd - (txq->rs_thresh - 1);
-	buffer = txq->buffer_ring;
-	if (txq->next_use < i) {
-		for ( ; i < txq->ring_depth; ++i) {
+#ifdef CC_AVX512_SUPPORT
+	struct rte_eth_dev *dev;
+	struct sxe2_tx_buffer_vec *buffer_vec;
+
+	dev = &rte_eth_devices[txq->port_id];
+
+	if (dev->tx_pkt_burst == sxe2_tx_pkts_vec_avx512 ||
+		dev->tx_pkt_burst == sxe2_tx_pkts_vec_avx512_simple) {
+		buffer_vec = (struct sxe2_tx_buffer_vec *)txq->buffer_ring;
+
+		if (txq->next_use < i) {
+			for ( ; i < txq->ring_depth; ++i) {
+				if (buffer_vec[i].mbuf != NULL) {
+					rte_pktmbuf_free_seg(buffer_vec[i].mbuf);
+					buffer_vec[i].mbuf = NULL;
+				}
+			}
+			i = 0;
+		}
+		for ( ; i < txq->next_use; ++i) {
+			if (buffer_vec[i].mbuf != NULL) {
+				rte_pktmbuf_free_seg(buffer_vec[i].mbuf);
+				buffer_vec[i].mbuf = NULL;
+			}
+		}
+	} else {
+#endif
+		buffer = txq->buffer_ring;
+		buffer = txq->buffer_ring;
+		if (txq->next_use < i) {
+			for ( ; i < txq->ring_depth; ++i) {
+				if (buffer[i].mbuf != NULL) {
+					rte_pktmbuf_free_seg(buffer[i].mbuf);
+					buffer[i].mbuf = NULL;
+				}
+			}
+			i = 0;
+		}
+		for (; i < txq->next_use; ++i) {
 			if (buffer[i].mbuf != NULL) {
 				rte_pktmbuf_free_seg(buffer[i].mbuf);
 				buffer[i].mbuf = NULL;
 			}
 		}
-		i = 0;
+#ifdef CC_AVX512_SUPPORT
 	}
+#endif
+
 	for (; i < txq->next_use; ++i) {
 		if (buffer[i].mbuf != NULL) {
 			rte_pktmbuf_free_seg(buffer[i].mbuf);
diff --git a/drivers/net/sxe2/sxe2_txrx_vec.h b/drivers/net/sxe2/sxe2_txrx_vec.h
index 04ff4d96a5..af7c8d12b2 100644
--- a/drivers/net/sxe2/sxe2_txrx_vec.h
+++ b/drivers/net/sxe2/sxe2_txrx_vec.h
@@ -11,15 +11,19 @@
 #define SXE2_RX_MODE_VEC_SIMPLE    RTE_BIT32(0)
 #define SXE2_RX_MODE_VEC_OFFLOAD   RTE_BIT32(1)
 #define SXE2_RX_MODE_VEC_SSE       RTE_BIT32(2)
+#define SXE2_RX_MODE_VEC_AVX512    RTE_BIT32(4)
 #define SXE2_RX_MODE_BATCH_ALLOC   RTE_BIT32(10)
 #define SXE2_RX_MODE_VEC_SET_MASK	(SXE2_RX_MODE_VEC_SIMPLE | \
-			SXE2_RX_MODE_VEC_OFFLOAD | SXE2_RX_MODE_VEC_SSE)
+			SXE2_RX_MODE_VEC_OFFLOAD | SXE2_RX_MODE_VEC_SSE | \
+			SXE2_RX_MODE_VEC_AVX512)
 #define SXE2_TX_MODE_VEC_SIMPLE   RTE_BIT32(0)
 #define SXE2_TX_MODE_VEC_OFFLOAD  RTE_BIT32(1)
 #define SXE2_TX_MODE_VEC_SSE      RTE_BIT32(2)
+#define SXE2_TX_MODE_VEC_AVX512   RTE_BIT32(4)
 #define SXE2_TX_MODE_SIMPLE_BATCH RTE_BIT32(10)
 #define SXE2_TX_MODE_VEC_SET_MASK	(SXE2_TX_MODE_VEC_SIMPLE | \
-			SXE2_TX_MODE_VEC_OFFLOAD | SXE2_TX_MODE_VEC_SSE)
+			SXE2_TX_MODE_VEC_OFFLOAD | SXE2_TX_MODE_VEC_SSE | \
+			SXE2_TX_MODE_VEC_AVX512)
 #define SXE2_TX_VEC_NO_SUPPORT_OFFLOAD (		  \
 			RTE_ETH_TX_OFFLOAD_MULTI_SEGS |		  \
 			RTE_ETH_TX_OFFLOAD_QINQ_INSERT |	  \
@@ -54,6 +58,16 @@ uint16_t sxe2_tx_pkts_vec_sse(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_
 uint16_t sxe2_tx_pkts_vec_sse_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t sxe2_rx_pkts_scattered_vec_sse_offload(void *rx_queue,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_avx512_simple(void *tx_queue,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_avx512(void *tx_queue,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_avx512_ctx_offload(void *tx_queue,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_rx_pkts_scattered_vec_avx512(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_rx_pkts_scattered_vec_avx512_offload(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 #endif
 int32_t __rte_cold sxe2_tx_vec_support_check(struct rte_eth_dev *dev, uint32_t *vec_flags);
 int32_t __rte_cold sxe2_tx_queues_vec_prepare(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_txrx_vec_avx512.c b/drivers/net/sxe2/sxe2_txrx_vec_avx512.c
new file mode 100644
index 0000000000..2aec8037dd
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_vec_avx512.c
@@ -0,0 +1,897 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_TEST
+#include <rte_vect.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_common_log.h"
+#include "sxe2_queue.h"
+#include "sxe2_txrx_vec.h"
+#include "sxe2_txrx_vec_common.h"
+#include "sxe2_vsi.h"
+
+static __rte_always_inline int32_t sxe2_tx_bufs_free_vec_avx512(struct sxe2_tx_queue *txq)
+{
+	struct sxe2_tx_buffer_vec *buffer;
+	struct rte_mbuf *mbuf;
+	struct rte_mbuf *mbuf_free_arr[SXE2_TX_FREE_BUFFER_SIZE_MAX_VEC];
+	struct rte_mempool *mp;
+	struct rte_mempool_cache *cache;
+	void **cache_objs;
+	uint32_t copied;
+	uint32_t i;
+	int32_t ret;
+	uint16_t rs_thresh;
+	uint16_t free_num;
+
+	if (rte_cpu_to_le_64(SXE2_TX_DESC_DTYPE_DESC_DONE) !=
+		(txq->desc_ring[txq->next_dd].wb.dd &
+			rte_cpu_to_le_64(SXE2_TX_DESC_DTYPE_MASK))) {
+		ret = 0;
+		goto l_end;
+	}
+
+	rs_thresh = txq->rs_thresh;
+
+	buffer = (struct sxe2_tx_buffer_vec *)txq->buffer_ring;
+	buffer += txq->next_dd - (rs_thresh - 1);
+
+	if ((txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) &&
+			(rs_thresh & 31) == 0) {
+		mp = buffer[0].mbuf->pool;
+		cache = rte_mempool_default_cache(mp, rte_lcore_id());
+
+		if (cache == NULL || cache->len)
+			goto normal;
+
+		if (rs_thresh > RTE_MEMPOOL_CACHE_MAX_SIZE) {
+			(void)rte_mempool_ops_enqueue_bulk(mp, (void *)buffer, rs_thresh);
+			goto done;
+		}
+		cache_objs = &cache->objs[cache->len];
+
+		copied = 0;
+		while (copied < rs_thresh) {
+			const __m512i objs0 = _mm512_loadu_si512(&buffer[copied]);
+			const __m512i objs1 = _mm512_loadu_si512(&buffer[copied + 8]);
+			const __m512i objs2 = _mm512_loadu_si512(&buffer[copied + 16]);
+			const __m512i objs3 = _mm512_loadu_si512(&buffer[copied + 24]);
+
+			_mm512_storeu_si512(&cache_objs[copied], objs0);
+			_mm512_storeu_si512(&cache_objs[copied + 8], objs1);
+			_mm512_storeu_si512(&cache_objs[copied + 16], objs2);
+			_mm512_storeu_si512(&cache_objs[copied + 24], objs3);
+			copied += 32;
+		}
+		cache->len += rs_thresh;
+
+		if (cache->len >= cache->flushthresh) {
+			(void)rte_mempool_ops_enqueue_bulk(mp,
+					&cache->objs[cache->size], cache->len - cache->size);
+			cache->len = cache->size;
+		}
+		goto done;
+	}
+
+normal:
+	mbuf = rte_pktmbuf_prefree_seg(buffer[0].mbuf);
+
+	if (likely(mbuf)) {
+		mbuf_free_arr[0] = mbuf;
+		free_num = 1;
+
+		for (i = 1; i < rs_thresh; ++i) {
+			mbuf = rte_pktmbuf_prefree_seg(buffer[i].mbuf);
+
+			if (likely(mbuf)) {
+				if (likely(mbuf->pool == mbuf_free_arr[0]->pool)) {
+					mbuf_free_arr[free_num] = mbuf;
+					free_num++;
+				} else {
+					rte_mempool_put_bulk(mbuf_free_arr[0]->pool,
+						(void *)mbuf_free_arr, free_num);
+
+				mbuf_free_arr[0] = mbuf;
+				free_num = 1;
+			}
+			}
+		}
+
+		rte_mempool_put_bulk(mbuf_free_arr[0]->pool,
+						(void *)mbuf_free_arr, free_num);
+	} else {
+		for (i = 1; i < rs_thresh; ++i) {
+			mbuf = rte_pktmbuf_prefree_seg(buffer[i].mbuf);
+			if (mbuf != NULL)
+				rte_mempool_put(mbuf->pool, mbuf);
+		}
+	}
+
+done:
+	txq->desc_free_num += txq->rs_thresh;
+	txq->next_dd       += txq->rs_thresh;
+	if (txq->next_dd >= txq->ring_depth)
+		txq->next_dd = txq->rs_thresh - 1;
+	ret = rs_thresh;
+
+l_end:
+	return ret;
+}
+
+static __rte_always_inline void
+sxe2_tx_desc_fill_one_avx512(volatile union sxe2_tx_data_desc *desc, struct rte_mbuf *pkt,
+	uint64_t desc_cmd, bool with_offloads)
+{
+	__m128i data_desc;
+	uint64_t desc_qw1;
+	uint32_t desc_offset;
+
+	desc_qw1 = (SXE2_TX_DESC_DTYPE_DATA |
+				((uint64_t)desc_cmd) << SXE2_TX_DATA_DESC_CMD_SHIFT |
+				((uint64_t)pkt->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+	desc_offset = SXE2_TX_DATA_DESC_MACLEN_VAL(pkt->l2_len);
+	desc_qw1 |= ((uint64_t)desc_offset) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+	if (with_offloads)
+		sxe2_tx_desc_fill_offloads(pkt, &desc_qw1);
+
+	data_desc = _mm_set_epi64x(desc_qw1, rte_pktmbuf_iova(pkt));
+
+	_mm_store_si128(RTE_CAST_PTR(__m128i *, desc), data_desc);
+}
+
+static __rte_always_inline
+void sxe2_tx_desc_fill_avx512(volatile union sxe2_tx_data_desc *desc, struct rte_mbuf **pkts,
+	uint16_t pkts_num, uint64_t desc_cmd, bool with_offloads)
+{
+	__m512i desc_group;
+	uint64_t desc0_qw1;
+	uint64_t desc1_qw1;
+	uint64_t desc2_qw1;
+	uint64_t desc3_qw1;
+
+	const uint64_t desc_qw1_com = (SXE2_TX_DESC_DTYPE_DATA |
+					((uint64_t)desc_cmd) << SXE2_TX_DATA_DESC_CMD_SHIFT);
+	uint32_t desc_offset[4] = {0};
+
+	while (pkts_num > 3) {
+		desc3_qw1 = desc_qw1_com |
+				((uint64_t)pkts[3]->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT;
+
+		desc_offset[3] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[3]->l2_len);
+		desc3_qw1 |= ((uint64_t)desc_offset[3]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[3], &desc3_qw1);
+
+		desc2_qw1 = desc_qw1_com |
+				((uint64_t)pkts[2]->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT;
+		desc_offset[2] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[2]->l2_len);
+		desc2_qw1 |= ((uint64_t)desc_offset[2]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[2], &desc2_qw1);
+
+		desc1_qw1 = (desc_qw1_com |
+				((uint64_t)pkts[1]->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+		desc_offset[1] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[1]->l2_len);
+		desc1_qw1 |= ((uint64_t)desc_offset[1]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[1], &desc1_qw1);
+
+		desc0_qw1 = (desc_qw1_com |
+				((uint64_t)pkts[0]->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+		desc_offset[0] = SXE2_TX_DATA_DESC_MACLEN_VAL(pkts[0]->l2_len);
+		desc0_qw1 |= ((uint64_t)desc_offset[0]) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+		if (with_offloads)
+			sxe2_tx_desc_fill_offloads(pkts[0], &desc0_qw1);
+
+		desc_group =
+			_mm512_set_epi64(desc3_qw1, rte_pktmbuf_iova(pkts[3]),
+					 desc2_qw1, rte_pktmbuf_iova(pkts[2]),
+					 desc1_qw1, rte_pktmbuf_iova(pkts[1]),
+					 desc0_qw1, rte_pktmbuf_iova(pkts[0]));
+
+		_mm512_storeu_si512(RTE_CAST_PTR(void *, desc), desc_group);
+
+		pkts_num -= 4;
+		desc     += 4;
+		pkts     += 4;
+	}
+
+	while (pkts_num) {
+		sxe2_tx_desc_fill_one_avx512(desc, *pkts, desc_cmd, with_offloads);
+
+		pkts_num--;
+		desc++;
+		pkts++;
+	}
+}
+
+static __rte_always_inline void
+sxe2_tx_pkts_mbuf_fill_avx512(struct sxe2_tx_buffer_vec *buffer,
+	struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	uint16_t i;
+
+	for (i = 0; i < nb_pkts; ++i)
+		buffer[i].mbuf = tx_pkts[i];
+}
+
+static __rte_always_inline uint16_t
+sxe2_tx_pkts_vec_avx512_batch(struct sxe2_tx_queue *txq, struct rte_mbuf **tx_pkts,
+	uint16_t nb_pkts, bool with_offloads)
+{
+	volatile union sxe2_tx_data_desc *desc;
+	struct sxe2_tx_buffer_vec *buffer;
+	uint16_t next_use;
+	uint16_t res_num;
+	uint16_t tx_num;
+
+	if (txq->desc_free_num < txq->free_thresh)
+		(void)sxe2_tx_bufs_free_vec_avx512(txq);
+
+	nb_pkts = RTE_MIN(txq->desc_free_num, nb_pkts);
+	if (unlikely(nb_pkts == 0)) {
+		PMD_LOG_DEBUG(TX, "Tx pkts avx512 batch: may not enough free desc, "
+				"free_desc=%u, need_tx_pkts=%u",
+				txq->desc_free_num, nb_pkts);
+		goto l_end;
+	}
+	tx_num = nb_pkts;
+
+	next_use = txq->next_use;
+	desc     = &txq->desc_ring[next_use];
+	buffer   = (struct sxe2_tx_buffer_vec *)txq->buffer_ring;
+	buffer  += next_use;
+
+	txq->desc_free_num -= nb_pkts;
+
+	res_num = txq->ring_depth - txq->next_use;
+
+	if (tx_num >= res_num) {
+		sxe2_tx_pkts_mbuf_fill_avx512(buffer, tx_pkts, res_num);
+
+		sxe2_tx_desc_fill_avx512(desc, tx_pkts, res_num,
+					SXE2_TX_DATA_DESC_CMD_EOP, with_offloads);
+		tx_pkts += (res_num - 1);
+		desc    += (res_num - 1);
+
+		sxe2_tx_desc_fill_one_avx512(desc, *tx_pkts++,
+					(SXE2_TX_DATA_DESC_CMD_EOP | SXE2_TX_DATA_DESC_CMD_RS),
+					with_offloads);
+
+		tx_num -= res_num;
+
+		next_use     = 0;
+		txq->next_rs = txq->rs_thresh - 1;
+		desc         = txq->desc_ring;
+		buffer       = (struct sxe2_tx_buffer_vec *)txq->buffer_ring;
+	}
+
+	sxe2_tx_pkts_mbuf_fill_avx512(buffer, tx_pkts, tx_num);
+
+	sxe2_tx_desc_fill_avx512(desc, tx_pkts, tx_num,
+			SXE2_TX_DATA_DESC_CMD_EOP, with_offloads);
+
+	next_use += tx_num;
+	if (next_use > txq->next_rs) {
+		txq->desc_ring[txq->next_rs].read.type_cmd_off_bsz_l2t |=
+			rte_cpu_to_le_64(SXE2_TX_DATA_DESC_CMD_RS_MASK);
+
+		txq->next_rs += txq->rs_thresh;
+	}
+	txq->next_use = next_use;
+
+	SXE2_PCI_REG_WRITE_WC(txq->tdt_reg_addr, next_use);
+	PMD_LOG_DEBUG(TX, "port_id=%u queue_id=%u next_use=%u send_pkts=%u",
+			txq->port_id, txq->queue_id, next_use, nb_pkts);
+l_end:
+	return nb_pkts;
+}
+
+static __rte_always_inline uint16_t
+sxe2_tx_pkts_vec_avx512_common(struct sxe2_tx_queue *txq, struct rte_mbuf **tx_pkts,
+	uint16_t nb_pkts, bool with_offloads)
+{
+	uint16_t tx_done_num = 0;
+	uint16_t tx_once_num;
+	uint16_t tx_need_num;
+
+	while (nb_pkts) {
+		tx_need_num = RTE_MIN(nb_pkts, txq->rs_thresh);
+		tx_once_num =
+			sxe2_tx_pkts_vec_avx512_batch(txq, tx_pkts + tx_done_num,
+					     tx_need_num, with_offloads);
+		nb_pkts     -= tx_once_num;
+		tx_done_num += tx_once_num;
+		if (tx_once_num < tx_need_num)
+			break;
+	}
+
+	return tx_done_num;
+}
+
+uint16_t sxe2_tx_pkts_vec_avx512_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_tx_pkts_vec_avx512_common((struct sxe2_tx_queue *)tx_queue,
+					      tx_pkts, nb_pkts, false);
+}
+
+uint16_t sxe2_tx_pkts_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_tx_pkts_vec_avx512_common((struct sxe2_tx_queue *)tx_queue,
+					      tx_pkts, nb_pkts, true);
+}
+
+static inline void sxe2_rx_queue_rearm_avx512(struct sxe2_rx_queue *rxq)
+{
+	volatile union sxe2_rx_desc *desc;
+	struct rte_mbuf **buffer;
+	struct rte_mbuf *mbuf0, *mbuf1;
+	__m128i dma_addr0, dma_addr1;
+	__m128i virt_addr0, virt_addr1;
+	__m128i hdr_room = _mm_set_epi64x(RTE_PKTMBUF_HEADROOM, RTE_PKTMBUF_HEADROOM);
+	int32_t ret;
+	uint16_t i;
+	uint16_t new_tail;
+
+	buffer = &rxq->buffer_ring[rxq->realloc_start];
+	desc   = &rxq->desc_ring[rxq->realloc_start];
+
+	ret = rte_mempool_get_bulk(rxq->mb_pool, (void *)buffer, SXE2_RX_REARM_THRESH_VEC);
+	if (ret != 0) {
+		if ((rxq->realloc_num + SXE2_RX_REARM_THRESH_VEC) >= rxq->ring_depth) {
+			dma_addr0 = _mm_setzero_si128();
+			for (i = 0; i < SXE2_RX_NUM_PER_LOOP_AVX; ++i) {
+				buffer[i] = &rxq->fake_mbuf;
+				_mm_store_si128(RTE_CAST_PTR(__m128i *, &desc[i].read),
+						dma_addr0);
+			}
+		}
+
+		rxq->vsi->adapter->dev_info.dev_data->rx_mbuf_alloc_failed +=
+			SXE2_RX_REARM_THRESH_VEC;
+		goto l_end;
+	}
+
+	for (i = 0; i < SXE2_RX_REARM_THRESH_VEC; i += 2, buffer += 2) {
+		mbuf0 = buffer[0];
+		mbuf1 = buffer[1];
+
+#if RTE_IOVA_IN_MBUF
+
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, buf_iova) !=
+				 offsetof(struct rte_mbuf, buf_addr) + 8);
+#endif
+		virt_addr0 = _mm_loadu_si128((__m128i *)&mbuf0->buf_addr);
+		virt_addr1 = _mm_loadu_si128((__m128i *)&mbuf1->buf_addr);
+
+#if RTE_IOVA_IN_MBUF
+
+		dma_addr0 = _mm_unpackhi_epi64(virt_addr0, virt_addr0);
+		dma_addr1 = _mm_unpackhi_epi64(virt_addr1, virt_addr1);
+#else
+
+		dma_addr0 = _mm_unpacklo_epi64(virt_addr0, virt_addr0);
+		dma_addr1 = _mm_unpacklo_epi64(virt_addr1, virt_addr1);
+#endif
+
+		dma_addr0 = _mm_add_epi64(dma_addr0, hdr_room);
+		dma_addr1 = _mm_add_epi64(dma_addr1, hdr_room);
+
+		_mm_store_si128(RTE_CAST_PTR(__m128i *, &desc++->read), dma_addr0);
+		_mm_store_si128(RTE_CAST_PTR(__m128i *, &desc++->read), dma_addr1);
+	}
+
+	rxq->realloc_start += SXE2_RX_REARM_THRESH_VEC;
+	if (rxq->realloc_start >= rxq->ring_depth)
+		rxq->realloc_start = 0;
+	rxq->realloc_num -= SXE2_RX_REARM_THRESH_VEC;
+
+	new_tail = (rxq->realloc_start == 0) ? (rxq->ring_depth - 1) :
+		(rxq->realloc_start - 1);
+
+	SXE2_PCI_REG_WRITE_WC(rxq->rdt_reg_addr, new_tail);
+
+l_end:
+	return;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_common_vec_avx512(struct sxe2_rx_queue *rxq, struct rte_mbuf **rx_pkts,
+	uint16_t nb_pkts, uint8_t *split_rxe_flags,
+	uint8_t *umbcast_flags, bool do_offload)
+{
+	const uint32_t *ptype_tbl = rxq->vsi->adapter->ptype_tbl;
+	const __m256i mbuf_init = _mm256_set_epi64x(0, 0, 0, rxq->mbuf_init_value);
+	struct rte_mbuf **buffer;
+	volatile union sxe2_rx_desc *desc;
+	__m512i mbufs4_7;
+	__m512i mbufs0_3;
+	__m256i mbufs6_7;
+	__m256i mbufs4_5;
+	__m256i mbufs2_3;
+	__m256i mbufs0_1;
+	uint32_t bit_num  = 0;
+	uint16_t done_num = 0;
+	uint16_t i = 0;
+	uint16_t j = 0;
+
+	buffer   = &rxq->buffer_ring[rxq->processing_idx];
+	desc     = &rxq->desc_ring[rxq->processing_idx];
+
+	rte_prefetch0(desc);
+
+	nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, SXE2_RX_NUM_PER_LOOP_AVX);
+
+	if (rxq->realloc_num > SXE2_RX_REARM_THRESH_VEC)
+		sxe2_rx_queue_rearm_avx512(rxq);
+
+	if (0 == (rte_le_to_cpu_64(desc->wb.status_err_ptype_len) & SXE2_RX_DESC_STATUS_DD_MASK))
+		goto l_end;
+
+	const __m512i crc_adjust =
+			_mm512_set4_epi32(0, -rxq->crc_len, -rxq->crc_len, 0);
+
+	const __m256i dd_mask = _mm256_set1_epi32(1);
+
+	const __m512i rvp_shuf_mask =
+			_mm512_set4_epi32((7 << 24) | (6 << 16) | (5 << 8) | 4,
+					  (3 << 24) | (2 << 16) | (13 << 8) | 12,
+					  (0xFFU << 24) | (0xFF << 16) | (13 << 8) | 12,
+					  0xFFFFFFFF);
+
+	const __m128i eop_shuf_mask =
+		_mm_set_epi8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+			     0xFF, 0xFF, 8, 0, 10, 2, 12, 4, 14, 6);
+
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, pkt_len) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 4);
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, data_len) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 8);
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, vlan_tci) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 10);
+	RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, hash) !=
+			offsetof(struct rte_mbuf, rx_descriptor_fields1) + 12);
+
+	for (i = 0; i < nb_pkts; i += SXE2_RX_NUM_PER_LOOP_AVX,
+				desc += SXE2_RX_NUM_PER_LOOP_AVX) {
+		_mm256_storeu_si256((void *)&rx_pkts[i],
+			_mm256_loadu_si256((void *)&buffer[i]));
+#ifdef RTE_ARCH_X86_64
+		_mm256_storeu_si256((void *)&rx_pkts[i + 4],
+			_mm256_loadu_si256((void *)&buffer[i + 4]));
+#endif
+
+		const __m128i desc7 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 7));
+		rte_compiler_barrier();
+		const __m128i desc6 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 6));
+		rte_compiler_barrier();
+		const __m128i desc5 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 5));
+		rte_compiler_barrier();
+		const __m128i desc4 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 4));
+		rte_compiler_barrier();
+		const __m128i desc3 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 3));
+		rte_compiler_barrier();
+		const __m128i desc2 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 2));
+		rte_compiler_barrier();
+		const __m128i desc1 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 1));
+		rte_compiler_barrier();
+		const __m128i desc0 = _mm_loadu_si128(RTE_CAST_PTR(const __m128i *, desc + 0));
+
+		const __m256i descs6_7 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc6), desc7, 1);
+		const __m256i descs4_5 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc4), desc5, 1);
+		const __m256i descs2_3 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc2), desc3, 1);
+		const __m256i descs0_1 =
+			_mm256_inserti128_si256(_mm256_castsi128_si256(desc0), desc1, 1);
+
+		const __m512i descs4_7 =
+			_mm512_inserti64x4(_mm512_castsi256_si512(descs4_5), descs6_7, 1);
+		const __m512i descs0_3 =
+			_mm512_inserti64x4(_mm512_castsi256_si512(descs0_1), descs2_3, 1);
+
+		if (split_rxe_flags != NULL) {
+			for (j = 0; j < SXE2_RX_NUM_PER_LOOP_AVX; j++)
+				rte_mbuf_prefetch_part2(rx_pkts[i + j]);
+		}
+
+		mbufs4_7 = _mm512_shuffle_epi8(descs4_7, rvp_shuf_mask);
+		mbufs0_3 = _mm512_shuffle_epi8(descs0_3, rvp_shuf_mask);
+
+		mbufs4_7 = _mm512_add_epi32(mbufs4_7, crc_adjust);
+		mbufs0_3 = _mm512_add_epi32(mbufs0_3, crc_adjust);
+
+		const __m512i ptype_mask = _mm512_set1_epi64(SXE2_RX_FLEX_DESC_PTYPE_M <<
+					SXE2_RX_FLEX_DESC_PTYPE_S);
+
+		__m512i ptypes4_7 = _mm512_and_si512(descs4_7, ptype_mask);
+		__m512i ptypes0_3 = _mm512_and_si512(descs0_3, ptype_mask);
+
+		const __m256i ptypes6_7 = _mm512_extracti64x4_epi64(ptypes4_7, 1);
+		const __m256i ptypes4_5 = _mm512_extracti64x4_epi64(ptypes4_7, 0);
+		const __m256i ptypes2_3 = _mm512_extracti64x4_epi64(ptypes0_3, 1);
+		const __m256i ptypes0_1 = _mm512_extracti64x4_epi64(ptypes0_3, 0);
+
+		const uint16_t ptype7 = _mm256_extract_epi16(ptypes6_7, 13);
+		const uint16_t ptype6 = _mm256_extract_epi16(ptypes6_7, 5);
+		const uint16_t ptype5 = _mm256_extract_epi16(ptypes4_5, 13);
+		const uint16_t ptype4 = _mm256_extract_epi16(ptypes4_5, 5);
+		const uint16_t ptype3 = _mm256_extract_epi16(ptypes2_3, 13);
+		const uint16_t ptype2 = _mm256_extract_epi16(ptypes2_3, 5);
+		const uint16_t ptype1 = _mm256_extract_epi16(ptypes0_1, 13);
+		const uint16_t ptype0 = _mm256_extract_epi16(ptypes0_1, 5);
+
+		const __m512i ptype_mask4_7 =
+				_mm512_set_epi32(0, 0, 0, ptype_tbl[ptype7],
+						 0, 0, 0, ptype_tbl[ptype6],
+						 0, 0, 0, ptype_tbl[ptype5],
+						 0, 0, 0, ptype_tbl[ptype4]);
+		const __m512i ptype_mask0_3 =
+				_mm512_set_epi32(0, 0, 0, ptype_tbl[ptype3],
+						 0, 0, 0, ptype_tbl[ptype2],
+						 0, 0, 0, ptype_tbl[ptype1],
+						 0, 0, 0, ptype_tbl[ptype0]);
+
+		mbufs4_7 = _mm512_or_si512(mbufs4_7, ptype_mask4_7);
+		mbufs0_3 = _mm512_or_si512(mbufs0_3, ptype_mask0_3);
+
+		mbufs6_7 = _mm512_extracti64x4_epi64(mbufs4_7, 1);
+		mbufs4_5 = _mm512_extracti64x4_epi64(mbufs4_7, 0);
+		mbufs2_3 = _mm512_extracti64x4_epi64(mbufs0_3, 1);
+		mbufs0_1 = _mm512_extracti64x4_epi64(mbufs0_3, 0);
+
+		const __m512i staterr_per_mask =
+			_mm512_set_epi32(0x17, 0x1F, 0x07, 0x0F,
+					 0x13, 0x1B, 0x03, 0x0B,
+					 0x16, 0x1E, 0x06, 0x0E,
+					 0x12, 0x1A, 0x02, 0x0A);
+		__m512i qw1_0_7 = _mm512_permutex2var_epi32(descs4_7,
+							    staterr_per_mask,
+							    descs0_3);
+
+		__m256i staterrs0_7 = _mm512_extracti64x4_epi64(qw1_0_7, 0);
+
+		__m256i stu_len0_7 = _mm512_extracti64x4_epi64(qw1_0_7, 1);
+		__m256i mbuf_flags = _mm256_setzero_si256();
+
+		if (do_offload) {
+			const __m256i desc_flags_mask = _mm256_set1_epi32(0xC0001C04);
+			const __m256i desc_flags_rss_mask = _mm256_set1_epi32(0x20000000);
+			const __m256i vlan_flags =
+				_mm256_set_epi8(0, 0, 0, 0,
+					0, 0, 0, 0,
+					0, 0, 0, RTE_MBUF_F_RX_VLAN |
+						RTE_MBUF_F_RX_VLAN_STRIPPED,
+					0, 0, 0, 0,
+					0, 0, 0, 0,
+					0, 0, 0, 0,
+					0, 0, 0, RTE_MBUF_F_RX_VLAN |
+						RTE_MBUF_F_RX_VLAN_STRIPPED,
+					0, 0, 0, 0);
+
+			const __m256i rss_flags =
+				_mm256_set_epi8(0, 0, 0, 0,
+					0, 0, 0, 0,
+					0, 0, 0, RTE_MBUF_F_RX_RSS_HASH,
+					0, 0, 0, 0,
+					0, 0, 0, 0,
+					0, 0, 0, 0,
+					0, 0, 0, RTE_MBUF_F_RX_RSS_HASH,
+					0, 0, 0, 0);
+
+			const __m256i cksum_flags =
+			_mm256_set_epi8(0, 0, 0, 0, 0, 0, 0,
+			0,
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_BAD |
+				RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_BAD |
+				RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+				RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+				RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_GOOD | RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_GOOD | RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			0, 0, 0, 0, 0, 0, 0, 0,
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_BAD |
+				RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_BAD |
+				RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+				RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+				RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_GOOD | RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+			((RTE_MBUF_F_RX_L4_CKSUM_GOOD | RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1));
+
+			const __m256i cksum_mask =
+				_mm256_set1_epi32(RTE_MBUF_F_RX_IP_CKSUM_MASK |
+						  RTE_MBUF_F_RX_L4_CKSUM_MASK |
+						  RTE_MBUF_F_RX_OUTER_L4_CKSUM_MASK |
+						  RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD);
+
+			const __m256i vlan_mask =
+				_mm256_set1_epi32(RTE_MBUF_F_RX_VLAN |
+						  RTE_MBUF_F_RX_VLAN_STRIPPED);
+
+			__m256i tmp_flags;
+			__m256i descs_flags = _mm256_and_si256(staterrs0_7, desc_flags_mask);
+			stu_len0_7 = _mm256_and_si256(stu_len0_7, desc_flags_rss_mask);
+
+			tmp_flags = _mm256_shuffle_epi8(vlan_flags, descs_flags);
+			mbuf_flags = _mm256_and_si256(tmp_flags, vlan_mask);
+
+			descs_flags = _mm256_srli_epi32(descs_flags, 10);
+			tmp_flags   = _mm256_shuffle_epi8(cksum_flags, descs_flags);
+			tmp_flags   = _mm256_slli_epi32(tmp_flags, 1);
+			tmp_flags   = _mm256_and_si256(tmp_flags, cksum_mask);
+			mbuf_flags  = _mm256_or_si256(mbuf_flags, tmp_flags);
+
+			descs_flags = _mm256_srli_epi32(stu_len0_7, 27);
+			tmp_flags   = _mm256_shuffle_epi8(rss_flags, descs_flags);
+			mbuf_flags  = _mm256_or_si256(mbuf_flags, tmp_flags);
+
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+			if (rxq->fnav_enable) {
+				__m256i fnav_vld0_3, fnav_vld4_7;
+				__m256i fnav_vld0_7;
+				__m256i v_zeros, v_ffff, v_u32_one;
+				const __m256i fdir_flags =
+					_mm256_set1_epi32(RTE_MBUF_F_RX_FDIR |
+							  RTE_MBUF_F_RX_FDIR_ID);
+				fnav_vld0_3 = _mm256_unpacklo_epi32(descs2_3, descs0_1);
+				fnav_vld4_7 = _mm256_unpacklo_epi32(descs6_7, descs4_5);
+
+				fnav_vld0_7 = _mm256_unpacklo_epi64(fnav_vld4_7, fnav_vld0_3);
+
+				fnav_vld0_7 = _mm256_slli_epi32(fnav_vld0_7, 26);
+				fnav_vld0_7 = _mm256_srli_epi32(fnav_vld0_7, 31);
+
+				v_zeros = _mm256_setzero_si256();
+				v_ffff = _mm256_cmpeq_epi32(v_zeros, v_zeros);
+				v_u32_one = _mm256_srli_epi32(v_ffff, 31);
+
+				tmp_flags = _mm256_cmpeq_epi32(fnav_vld0_7, v_u32_one);
+
+				tmp_flags = _mm256_and_si256(tmp_flags, fdir_flags);
+
+				mbuf_flags = _mm256_or_si256(mbuf_flags, tmp_flags);
+
+				rx_pkts[i + 0]->hash.fdir.hi = desc[0].wb.fd_filter_id;
+				rx_pkts[i + 1]->hash.fdir.hi = desc[1].wb.fd_filter_id;
+				rx_pkts[i + 2]->hash.fdir.hi = desc[2].wb.fd_filter_id;
+				rx_pkts[i + 3]->hash.fdir.hi = desc[3].wb.fd_filter_id;
+				rx_pkts[i + 4]->hash.fdir.hi = desc[4].wb.fd_filter_id;
+				rx_pkts[i + 5]->hash.fdir.hi = desc[5].wb.fd_filter_id;
+				rx_pkts[i + 6]->hash.fdir.hi = desc[6].wb.fd_filter_id;
+				rx_pkts[i + 7]->hash.fdir.hi = desc[7].wb.fd_filter_id;
+			}
+#endif
+		}
+
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, ol_flags) !=
+				offsetof(struct rte_mbuf, rearm_data) + 8);
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, rx_descriptor_fields1) !=
+				offsetof(struct rte_mbuf, rearm_data) + 16);
+		RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, rearm_data) !=
+				RTE_ALIGN(offsetof(struct rte_mbuf, rearm_data), 16));
+
+		__m256i rearm_arr[8];
+
+		rearm_arr[6] = _mm256_blend_epi32(mbuf_init,
+					_mm256_slli_si256(mbuf_flags, 8), 0x04);
+		rearm_arr[4] = _mm256_blend_epi32(mbuf_init,
+					_mm256_slli_si256(mbuf_flags, 4), 0x04);
+		rearm_arr[2] = _mm256_blend_epi32(mbuf_init, mbuf_flags, 0x04);
+		rearm_arr[0] = _mm256_blend_epi32(mbuf_init,
+					_mm256_srli_si256(mbuf_flags, 4), 0x04);
+
+		rearm_arr[6] = _mm256_permute2f128_si256(rearm_arr[6], mbufs6_7, 0x20);
+		rearm_arr[4] = _mm256_permute2f128_si256(rearm_arr[4], mbufs4_5, 0x20);
+		rearm_arr[2] = _mm256_permute2f128_si256(rearm_arr[2], mbufs2_3, 0x20);
+		rearm_arr[0] = _mm256_permute2f128_si256(rearm_arr[0], mbufs0_1, 0x20);
+
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 6]->rearm_data, rearm_arr[6]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 4]->rearm_data, rearm_arr[4]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 2]->rearm_data, rearm_arr[2]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 0]->rearm_data, rearm_arr[0]);
+
+		const __m256i tmp_mbuf_flags =
+				_mm256_castsi128_si256(_mm256_extracti128_si256(mbuf_flags, 1));
+
+		rearm_arr[7] = _mm256_blend_epi32(mbuf_init,
+					_mm256_slli_si256(tmp_mbuf_flags, 8), 4);
+		rearm_arr[5] = _mm256_blend_epi32(mbuf_init,
+					_mm256_slli_si256(tmp_mbuf_flags, 4), 4);
+		rearm_arr[3] = _mm256_blend_epi32(mbuf_init, tmp_mbuf_flags, 4);
+		rearm_arr[1] = _mm256_blend_epi32(mbuf_init,
+					_mm256_srli_si256(tmp_mbuf_flags, 4), 4);
+
+		rearm_arr[7] = _mm256_blend_epi32(rearm_arr[7], mbufs6_7, 0XF0);
+		rearm_arr[5] = _mm256_blend_epi32(rearm_arr[5], mbufs4_5, 0XF0);
+		rearm_arr[3] = _mm256_blend_epi32(rearm_arr[3], mbufs2_3, 0XF0);
+		rearm_arr[1] = _mm256_blend_epi32(rearm_arr[1], mbufs0_1, 0XF0);
+
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 7]->rearm_data, rearm_arr[7]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 5]->rearm_data, rearm_arr[5]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 3]->rearm_data, rearm_arr[3]);
+		_mm256_storeu_si256((__m256i *)&rx_pkts[i + 1]->rearm_data, rearm_arr[1]);
+
+		if (umbcast_flags) {
+			const __m256i umbcast_mask =
+				_mm256_set1_epi32(SXE2_RX_DESC_STATUS_UMBCAST_MASK);
+			__m256i umbcast_bits_256 =
+				_mm256_and_si256(staterrs0_7, umbcast_mask);
+
+			umbcast_bits_256 = _mm256_srli_epi32(umbcast_bits_256, 24);
+			__m128i umbcast_bits_128 =
+				_mm_packs_epi32(_mm256_castsi256_si128(umbcast_bits_256),
+						_mm256_extractf128_si256(umbcast_bits_256, 1));
+
+			umbcast_bits_128 = _mm_shuffle_epi8(umbcast_bits_128, eop_shuf_mask);
+
+			*(uint64_t *)umbcast_flags = _mm_cvtsi128_si64(umbcast_bits_128);
+			umbcast_flags += SXE2_RX_NUM_PER_LOOP_AVX;
+		}
+
+		if (split_rxe_flags) {
+			const __m256i eop_rxe_mask =
+					_mm256_set1_epi32(SXE2_RX_DESC_STATUS_EOP_MASK |
+								SXE2_RX_DESC_ERROR_RXE_MASK |
+								SXE2_RX_DESC_ERROR_OVERSIZE_MASK);
+			const __m128i eop_mask_128 =
+					_mm_set1_epi16(SXE2_RX_DESC_STATUS_EOP_MASK);
+			const __m128i rxe_mask_128 =
+					_mm_set1_epi16(SXE2_RX_DESC_ERROR_RXE_MASK |
+							SXE2_RX_DESC_ERROR_OVERSIZE_MASK);
+
+			const __m256i tmp_stats = _mm256_and_si256(staterrs0_7, eop_rxe_mask);
+
+			const __m128i eop_rxe_bits = _mm_packs_epi32
+							(_mm256_castsi256_si128(tmp_stats),
+							 _mm256_extractf128_si256(tmp_stats, 1));
+
+			__m128i not_eop_bits = _mm_andnot_si128(eop_rxe_bits, eop_mask_128);
+
+			not_eop_bits =
+				_mm_or_si128(not_eop_bits,
+					     _mm_srli_epi16(_mm_and_si128(eop_rxe_bits,
+									       rxe_mask_128),
+							      7));
+
+			not_eop_bits = _mm_shuffle_epi8(not_eop_bits, eop_shuf_mask);
+
+			*(uint64_t *)split_rxe_flags = _mm_cvtsi128_si64(not_eop_bits);
+			split_rxe_flags += SXE2_RX_NUM_PER_LOOP_AVX;
+		}
+
+		staterrs0_7 = _mm256_and_si256(staterrs0_7, dd_mask);
+
+		staterrs0_7 = _mm256_packs_epi32(staterrs0_7, _mm256_setzero_si256());
+
+		bit_num = rte_popcount64
+				(_mm_cvtsi128_si64(_mm256_extracti128_si256(staterrs0_7, 1)));
+		bit_num += rte_popcount64
+				(_mm_cvtsi128_si64(_mm256_castsi256_si128(staterrs0_7)));
+		done_num += bit_num;
+
+		if (bit_num != SXE2_RX_NUM_PER_LOOP_AVX)
+			break;
+	}
+
+	rxq->processing_idx += done_num;
+	rxq->processing_idx &= (rxq->ring_depth - 1);
+	if ((rxq->processing_idx & 1) == 1 && done_num > 1) {
+		rxq->processing_idx--;
+		done_num--;
+	}
+	rxq->realloc_num     += done_num;
+
+l_end:
+	PMD_LOG_DEBUG(RX, "port_id=%u queue_id=%u last_id=%u recv_pkts=%d",
+			rxq->port_id, rxq->queue_id, rxq->processing_idx, done_num);
+	return done_num;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_scattered_batch_vec_avx512(struct sxe2_rx_queue *rxq, struct rte_mbuf **rx_pkts,
+	uint16_t nb_pkts, bool do_offload)
+{
+	const uint64_t *split_rxe_flags64;
+	uint8_t split_rxe_flags[SXE2_RX_PKTS_BURST_BATCH_NUM_VEC] = {0};
+	uint8_t umbcast_flags[SXE2_RX_PKTS_BURST_BATCH_NUM_VEC] = {0};
+	uint16_t rx_done_num;
+	uint16_t rx_pkt_done_num;
+
+	rx_pkt_done_num = 0;
+
+	if (rxq->vsi->adapter->devargs.sw_stats_en) {
+		rx_done_num = sxe2_rx_pkts_common_vec_avx512(rxq, rx_pkts,
+				nb_pkts, split_rxe_flags,
+				umbcast_flags, do_offload);
+	} else {
+		rx_done_num = sxe2_rx_pkts_common_vec_avx512(rxq, rx_pkts,
+				nb_pkts, split_rxe_flags,
+			    NULL, do_offload);
+	}
+	if (rx_done_num == 0)
+		goto l_end;
+
+	if (!rxq->vsi->adapter->devargs.sw_stats_en) {
+		split_rxe_flags64 = (uint64_t *)split_rxe_flags;
+
+		if (rxq->pkt_first_seg == NULL &&
+				!split_rxe_flags64[0] && !split_rxe_flags64[1] &&
+				!split_rxe_flags64[2] && !split_rxe_flags64[3]) {
+			rx_pkt_done_num = rx_done_num;
+			goto l_end;
+		}
+
+		if (rxq->pkt_first_seg == NULL) {
+			while (rx_pkt_done_num < rx_done_num &&
+			       split_rxe_flags[rx_pkt_done_num] == 0)
+				rx_pkt_done_num++;
+
+			if (rx_pkt_done_num == rx_done_num)
+				goto l_end;
+
+			rxq->pkt_first_seg = rx_pkts[rx_pkt_done_num];
+		}
+	}
+
+	rx_pkt_done_num += sxe2_rx_pkts_refactor(rxq, &rx_pkts[rx_pkt_done_num],
+			rx_done_num - rx_pkt_done_num, &split_rxe_flags[rx_pkt_done_num],
+			&umbcast_flags[rx_pkt_done_num]);
+
+l_end:
+
+	return rx_pkt_done_num;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_scattered_common_vec_avx512(void *rx_queue,
+	struct rte_mbuf **rx_pkts, uint16_t nb_pkts, bool offload)
+{
+	uint16_t done_num = 0;
+	uint16_t once_num  = 0;
+
+	while (nb_pkts > SXE2_RX_PKTS_BURST_BATCH_NUM) {
+		once_num = sxe2_rx_pkts_scattered_batch_vec_avx512(rx_queue, rx_pkts + done_num,
+			SXE2_RX_PKTS_BURST_BATCH_NUM, offload);
+
+		done_num  += once_num;
+		nb_pkts -= once_num;
+
+		if (once_num < SXE2_RX_PKTS_BURST_BATCH_NUM)
+			goto end;
+	}
+
+	done_num += sxe2_rx_pkts_scattered_batch_vec_avx512(rx_queue,
+		rx_pkts + done_num, nb_pkts, offload);
+
+end:
+	return done_num;
+}
+
+uint16_t sxe2_rx_pkts_scattered_vec_avx512(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_rx_pkts_scattered_common_vec_avx512(rx_queue,
+			rx_pkts, nb_pkts, false);
+}
+
+uint16_t sxe2_rx_pkts_scattered_vec_avx512_offload(void *rx_queue,
+		struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	return sxe2_rx_pkts_scattered_common_vec_avx512(rx_queue,
+			rx_pkts, nb_pkts, true);
+}
+
+#endif
-- 
2.52.0


^ permalink raw reply related

* [PATCH v14 00/20] net/sxe2: added Linkdata sxe2 ethernet driver
From: liujie5 @ 2026-06-09  1:39 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260608074257.3043531-21-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch set implements core functionality for the SXE2 PMD,
including basic driver framework, data path setup, and advanced
offload features (VLAN, RSS,TM, PTP etc.).

V14:
 - Addressed AI comments

Jie Liu (20):
  net/sxe2: support AVX512 vectorized path for Rx and Tx
  net/sxe2: add AVX2 vector data path for Rx and Tx
  drivers: add supported packet types get callback
  net/sxe2: support L2 filtering and MAC config
  drivers: support RSS feature
  net/sxe2: support TM hierarchy and shaping
  net/sxe2: support IPsec inline protocol offload
  net/sxe2: support statistics and multi-process
  drivers: interrupt handling
  net/sxe2: add NEON vec Rx/Tx burst functions
  drivers: add support for VF representors
  net/sxe2: add support for custom UDP tunnel ports
  net/sxe2: support firmware version reading
  net/sxe2: implement get monitor address
  common/sxe2: add shared SFP module definitions
  net/sxe2: support SFP module info and EEPROM access
  net/sxe2: implement private dump info
  net/sxe2: add mbuf validation in Tx debug mode
  drivers: add testpmd commands for private features
  net/sxe2: update sxe2 feature matrix docs

 doc/guides/nics/features/sxe2.ini          |   56 +
 drivers/common/sxe2/sxe2_common.c          |  156 ++
 drivers/common/sxe2/sxe2_common.h          |    4 +
 drivers/common/sxe2/sxe2_flow_public.h     |  633 +++++++
 drivers/common/sxe2/sxe2_ioctl_chnl.c      |  178 +-
 drivers/common/sxe2/sxe2_ioctl_chnl_func.h |   18 +
 drivers/common/sxe2/sxe2_msg.h             |  118 ++
 drivers/common/sxe2/sxe2_ptype.h           | 1793 ++++++++++++++++++
 drivers/net/sxe2/meson.build               |   56 +-
 drivers/net/sxe2/sxe2_cmd_chnl.c           | 1587 +++++++++++++++-
 drivers/net/sxe2/sxe2_cmd_chnl.h           |  139 ++
 drivers/net/sxe2/sxe2_drv_cmd.h            |  521 +++++-
 drivers/net/sxe2/sxe2_dump.c               |  304 +++
 drivers/net/sxe2/sxe2_dump.h               |   12 +
 drivers/net/sxe2/sxe2_ethdev.c             | 1531 +++++++++++++++-
 drivers/net/sxe2/sxe2_ethdev.h             |  112 +-
 drivers/net/sxe2/sxe2_ethdev_repr.c        |  610 ++++++
 drivers/net/sxe2/sxe2_ethdev_repr.h        |   32 +
 drivers/net/sxe2/sxe2_filter.c             |  895 +++++++++
 drivers/net/sxe2/sxe2_filter.h             |  100 +
 drivers/net/sxe2/sxe2_flow.c               | 1391 ++++++++++++++
 drivers/net/sxe2/sxe2_flow.h               |   30 +
 drivers/net/sxe2/sxe2_flow_define.h        |  144 ++
 drivers/net/sxe2/sxe2_flow_parse_action.c  | 1182 ++++++++++++
 drivers/net/sxe2/sxe2_flow_parse_action.h  |   23 +
 drivers/net/sxe2/sxe2_flow_parse_engine.c  |  106 ++
 drivers/net/sxe2/sxe2_flow_parse_engine.h  |   13 +
 drivers/net/sxe2/sxe2_flow_parse_pattern.c | 1935 ++++++++++++++++++++
 drivers/net/sxe2/sxe2_flow_parse_pattern.h |   46 +
 drivers/net/sxe2/sxe2_ipsec.c              | 1565 ++++++++++++++++
 drivers/net/sxe2/sxe2_ipsec.h              |  254 +++
 drivers/net/sxe2/sxe2_irq.c                | 1026 +++++++++++
 drivers/net/sxe2/sxe2_irq.h                |   25 +
 drivers/net/sxe2/sxe2_mac.c                |  535 ++++++
 drivers/net/sxe2/sxe2_mac.h                |   84 +
 drivers/net/sxe2/sxe2_mp.c                 |  414 +++++
 drivers/net/sxe2/sxe2_mp.h                 |   67 +
 drivers/net/sxe2/sxe2_queue.c              |   17 +-
 drivers/net/sxe2/sxe2_rss.c                |  584 ++++++
 drivers/net/sxe2/sxe2_rss.h                |   81 +
 drivers/net/sxe2/sxe2_rx.c                 |   38 +
 drivers/net/sxe2/sxe2_rx.h                 |    2 +
 drivers/net/sxe2/sxe2_security.c           |  335 ++++
 drivers/net/sxe2/sxe2_security.h           |   77 +
 drivers/net/sxe2/sxe2_stats.c              |  591 ++++++
 drivers/net/sxe2/sxe2_stats.h              |   39 +
 drivers/net/sxe2/sxe2_switchdev.c          |  332 ++++
 drivers/net/sxe2/sxe2_switchdev.h          |   33 +
 drivers/net/sxe2/sxe2_testpmd.c            |  733 ++++++++
 drivers/net/sxe2/sxe2_testpmd_lib.c        |  969 ++++++++++
 drivers/net/sxe2/sxe2_testpmd_lib.h        |  142 ++
 drivers/net/sxe2/sxe2_tm.c                 | 1169 ++++++++++++
 drivers/net/sxe2/sxe2_tm.h                 |   78 +
 drivers/net/sxe2/sxe2_tx.c                 |    7 +
 drivers/net/sxe2/sxe2_txrx.c               |  176 +-
 drivers/net/sxe2/sxe2_txrx.h               |    4 +
 drivers/net/sxe2/sxe2_txrx_check_mbuf.c    |  595 ++++++
 drivers/net/sxe2/sxe2_txrx_check_mbuf.h    |   38 +
 drivers/net/sxe2/sxe2_txrx_poll.c          |  243 ++-
 drivers/net/sxe2/sxe2_txrx_vec.c           |   46 +-
 drivers/net/sxe2/sxe2_txrx_vec.h           |   38 +-
 drivers/net/sxe2/sxe2_txrx_vec_avx2.c      |  776 ++++++++
 drivers/net/sxe2/sxe2_txrx_vec_avx512.c    |  897 +++++++++
 drivers/net/sxe2/sxe2_txrx_vec_common.h    |    1 +
 drivers/net/sxe2/sxe2_txrx_vec_neon.c      |  721 ++++++++
 drivers/net/sxe2/sxe2_vsi.c                |  146 ++
 drivers/net/sxe2/sxe2_vsi.h                |   12 +-
 drivers/net/sxe2/sxe2vf_regs.h             |   85 +
 68 files changed, 26576 insertions(+), 124 deletions(-)
 create mode 100644 drivers/common/sxe2/sxe2_flow_public.h
 create mode 100644 drivers/common/sxe2/sxe2_msg.h
 create mode 100644 drivers/common/sxe2/sxe2_ptype.h
 create mode 100644 drivers/net/sxe2/sxe2_dump.c
 create mode 100644 drivers/net/sxe2/sxe2_dump.h
 create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.c
 create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.h
 create mode 100644 drivers/net/sxe2/sxe2_filter.c
 create mode 100644 drivers/net/sxe2/sxe2_filter.h
 create mode 100644 drivers/net/sxe2/sxe2_flow.c
 create mode 100644 drivers/net/sxe2/sxe2_flow.h
 create mode 100644 drivers/net/sxe2/sxe2_flow_define.h
 create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.c
 create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.h
 create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.c
 create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.h
 create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.c
 create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.h
 create mode 100644 drivers/net/sxe2/sxe2_ipsec.c
 create mode 100644 drivers/net/sxe2/sxe2_ipsec.h
 create mode 100644 drivers/net/sxe2/sxe2_irq.c
 create mode 100644 drivers/net/sxe2/sxe2_mac.c
 create mode 100644 drivers/net/sxe2/sxe2_mac.h
 create mode 100644 drivers/net/sxe2/sxe2_mp.c
 create mode 100644 drivers/net/sxe2/sxe2_mp.h
 create mode 100644 drivers/net/sxe2/sxe2_rss.c
 create mode 100644 drivers/net/sxe2/sxe2_rss.h
 create mode 100644 drivers/net/sxe2/sxe2_security.c
 create mode 100644 drivers/net/sxe2/sxe2_security.h
 create mode 100644 drivers/net/sxe2/sxe2_stats.c
 create mode 100644 drivers/net/sxe2/sxe2_stats.h
 create mode 100644 drivers/net/sxe2/sxe2_switchdev.c
 create mode 100644 drivers/net/sxe2/sxe2_switchdev.h
 create mode 100644 drivers/net/sxe2/sxe2_testpmd.c
 create mode 100644 drivers/net/sxe2/sxe2_testpmd_lib.c
 create mode 100644 drivers/net/sxe2/sxe2_testpmd_lib.h
 create mode 100644 drivers/net/sxe2/sxe2_tm.c
 create mode 100644 drivers/net/sxe2/sxe2_tm.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx2.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx512.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_neon.c
 create mode 100644 drivers/net/sxe2/sxe2vf_regs.h

-- 
2.52.0


^ permalink raw reply

* [PATCH] net/iavf: fix to consolidate link change event handling
From: Anurag Mandal @ 2026-06-09  0:10 UTC (permalink / raw)
  To: dev
  Cc: bruce.richardson, vladimir.medvedkin, ciara.loftus, Anurag Mandal,
	stable

Handled link-change events through a common static function that
reads the correct advanced & legacy link fields properly and
updates no-poll/watchdog/LSC state consistently.

Fixes: 5e03e316c753 ("net/iavf: handle virtchnl event message without interrupt")
Fixes: 48de41ca11f0 ("net/avf: enable link status update")
Cc: stable@dpdk.org

Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
 drivers/net/intel/iavf/iavf_vchnl.c | 133 +++++++++++++++++-----------
 1 file changed, 81 insertions(+), 52 deletions(-)

diff --git a/drivers/net/intel/iavf/iavf_vchnl.c b/drivers/net/intel/iavf/iavf_vchnl.c
index 94ccfb5d6e..6454632541 100644
--- a/drivers/net/intel/iavf/iavf_vchnl.c
+++ b/drivers/net/intel/iavf/iavf_vchnl.c
@@ -216,6 +216,75 @@ iavf_convert_link_speed(enum virtchnl_link_speed virt_link_speed)
 	return speed;
 }
 
+/*
+ * iavf_handle_link_change_event: common handler for VIRTCHNL link change events
+ *
+ * @dev: pointer to rte_eth_dev for this VF
+ * @vpe: pointer to the virtchnl_pf_event payload received from the PF
+ *
+ * Handle PF link-change event: decode adv/legacy link info, update VF
+ * link state, sync no-poll/watchdog behavior & notify app via LSC event.
+ */
+static void
+iavf_handle_link_change_event(struct rte_eth_dev *dev,
+			      struct virtchnl_pf_event *vpe)
+{
+	struct iavf_adapter *adapter;
+	struct iavf_info *vf;
+	bool adv_link_speed;
+
+	if (dev == NULL || dev->data == NULL ||
+	    dev->data->dev_private == NULL || vpe == NULL) {
+		PMD_DRV_LOG(ERR, "Invalid device pointer in link change handler");
+		return;
+	}
+
+	adapter = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	vf = &adapter->vf;
+
+	adv_link_speed = (vf->vf_res != NULL) &&
+		((vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) != 0);
+
+	if (adv_link_speed) {
+		vf->link_up = vpe->event_data.link_event_adv.link_status;
+		vf->link_speed = vpe->event_data.link_event_adv.link_speed;
+	} else {
+		enum virtchnl_link_speed speed;
+
+		vf->link_up = vpe->event_data.link_event.link_status;
+		speed = vpe->event_data.link_event.link_speed;
+		vf->link_speed = iavf_convert_link_speed(speed);
+	}
+
+	iavf_dev_link_update(dev, 0);
+
+	/*
+	 * Update watchdog/no_poll state BEFORE notifying the application via
+	 * the LSC event. Otherwise the application's link-up callback could
+	 * race with stale (link-down) no_poll/watchdog state and either
+	 * continue to drop traffic or trigger a spurious reset detection.
+	 *
+	 * Keeping the watchdog enabled whenever the link cannot be trusted
+	 * (link is down or a VF reset is in progress); the watchdog drives
+	 * auto-reset recovery, so it must remain armed in those cases.
+	 */
+	if (vf->link_up && !vf->vf_reset)
+		iavf_dev_watchdog_disable(adapter);
+	else
+		iavf_dev_watchdog_enable(adapter);
+
+	if (adapter->devargs.no_poll_on_link_down) {
+		iavf_set_no_poll(adapter, true);
+		PMD_DRV_LOG(DEBUG, "VF no poll turned %s",
+			    adapter->no_poll ? "on" : "off");
+	}
+
+	iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0);
+
+	PMD_DRV_LOG(INFO, "Link status update:%s",
+		vf->link_up ? "up" : "down");
+}
+
 /* Read data in admin queue to get msg from pf driver */
 static enum iavf_aq_result
 iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,
@@ -249,38 +318,15 @@ iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len,
 	if (opcode == VIRTCHNL_OP_EVENT) {
 		struct virtchnl_pf_event *vpe =
 			(struct virtchnl_pf_event *)event.msg_buf;
+		if (vpe == NULL) {
+			PMD_DRV_LOG(ERR, "Invalid PF event message");
+			return IAVF_MSG_ERR;
+		}
 
 		result = IAVF_MSG_SYS;
 		switch (vpe->event) {
 		case VIRTCHNL_EVENT_LINK_CHANGE:
-			vf->link_up =
-				vpe->event_data.link_event.link_status;
-			if (vf->vf_res != NULL &&
-			    vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) {
-				vf->link_speed =
-				    vpe->event_data.link_event_adv.link_speed;
-			} else {
-				enum virtchnl_link_speed speed;
-				speed = vpe->event_data.link_event.link_speed;
-				vf->link_speed = iavf_convert_link_speed(speed);
-			}
-			iavf_dev_link_update(vf->eth_dev, 0);
-			iavf_dev_event_post(vf->eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0);
-			if (vf->link_up && !vf->vf_reset) {
-				iavf_dev_watchdog_disable(adapter);
-			} else {
-				if (!vf->link_up)
-					iavf_dev_watchdog_enable(adapter);
-			}
-			if (adapter->devargs.no_poll_on_link_down) {
-				iavf_set_no_poll(adapter, true);
-				if (adapter->no_poll)
-					PMD_DRV_LOG(DEBUG, "VF no poll turned on");
-				else
-					PMD_DRV_LOG(DEBUG, "VF no poll turned off");
-			}
-			PMD_DRV_LOG(INFO, "Link status update:%s",
-					vf->link_up ? "up" : "down");
+			iavf_handle_link_change_event(vf->eth_dev, vpe);
 			break;
 		case VIRTCHNL_EVENT_RESET_IMPENDING:
 			vf->vf_reset = true;
@@ -505,6 +551,12 @@ iavf_handle_pf_event_msg(struct rte_eth_dev *dev, uint8_t *msg,
 		PMD_DRV_LOG(DEBUG, "Error event");
 		return;
 	}
+
+	if (pf_msg == NULL) {
+		PMD_DRV_LOG(ERR, "Invalid PF event message");
+		return;
+	}
+
 	switch (pf_msg->event) {
 	case VIRTCHNL_EVENT_RESET_IMPENDING:
 		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
@@ -518,30 +570,7 @@ iavf_handle_pf_event_msg(struct rte_eth_dev *dev, uint8_t *msg,
 		break;
 	case VIRTCHNL_EVENT_LINK_CHANGE:
 		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
-		vf->link_up = pf_msg->event_data.link_event.link_status;
-		if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) {
-			vf->link_speed =
-				pf_msg->event_data.link_event_adv.link_speed;
-		} else {
-			enum virtchnl_link_speed speed;
-			speed = pf_msg->event_data.link_event.link_speed;
-			vf->link_speed = iavf_convert_link_speed(speed);
-		}
-		iavf_dev_link_update(dev, 0);
-		if (vf->link_up && !vf->vf_reset) {
-			iavf_dev_watchdog_disable(adapter);
-		} else {
-			if (!vf->link_up)
-				iavf_dev_watchdog_enable(adapter);
-		}
-		if (adapter->devargs.no_poll_on_link_down) {
-			iavf_set_no_poll(adapter, true);
-			if (adapter->no_poll)
-				PMD_DRV_LOG(DEBUG, "VF no poll turned on");
-			else
-				PMD_DRV_LOG(DEBUG, "VF no poll turned off");
-		}
-		iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0);
+		iavf_handle_link_change_event(dev, pf_msg);
 		break;
 	case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
 		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
-- 
2.34.1


^ permalink raw reply related

* RE: [EXTERNAL] Re: [PATCH v7 1/1] net/mana: add device reset support
From: Long Li @ 2026-06-08 23:32 UTC (permalink / raw)
  To: Stephen Hemminger, Wei Hu; +Cc: dev@dpdk.org, Wei Hu
In-Reply-To: <20260608121134.601e4f46@phoenix.local>

> > ---
> 
> This is is a rather complex set of state transitions so admit to relying on AI as
> backup for tracking this. It still sees some errors here.
> 
> Worth asking the question, "what does mlx5 do?" and "should DPDK EAL be
> doing this at the PCI layer instead?"

MLX5 doesn't have this device service model and will not attempt device recovery, it just quits and tells the app the device is removed via sending out RTE_ETH_EVENT_INTR_RMV.

This service event has very limited visibility over the PCI, as the device is servicing itself while keeping all the PCI endpoints alive. PCI device persists during the reset. Only the DMA queues need to be recreated.

I think processing the service events entirely in the mana driver is the right thing to do.

> 
> ---
> 
> Much better - this addresses the RCU, the macros, the thread-safety-analysis
> suppressions, and the callback-under-lock deadlock. The single-variable
> burst_state CAS is a clean way to do the drain and the acquire/release
> reasoning checks out.
> 
> One structural thing remains. The enter phase still runs the heavy teardown on
> the EAL interrupt thread under reset_ops_lock: dev_stop, then
> mana_mp_req_on_rxtx(RESET_ENTER) which is a blocking
> rte_mp_request_sync with a multi-second timeout, then dev_close with its ibv
> calls. You already moved the exit phase to a control thread because
> intr_callback_unregister cannot run on the interrupt thread; the same
> argument applies to blocking IPC and verbs teardown. A slow or absent
> secondary will stall the interrupt thread for the MP timeout, and this is the
> blocking-under-a-sleeping-mutex pattern. Please have the interrupt handler
> just set state and drain, then hand the rest of the teardown to the control
> thread. That also removes the last lock hand-off between functions/threads,
> so each function can own its lock.

Yes, we should move all the blocking calls from the system interrupt thread to the MANA control thread.

> 
> Smaller points:
> - RECOVERY_SUCCESS/FAILED are emitted from the reset thread. If the
> callback
>   calls dev_stop/dev_close, mana_join_reset_thread() joins the current thread
>   (EDEADLK, leaked handle). INTR_RMV is fine since it runs on the dev-event
>   thread.
> - The burst_state comment says bits 1+ encode device state, but only
>   RESET_ENTER<<1 is ever stored - it is effectively a single "blocked" flag.

^ permalink raw reply

* Re: [v2] dts: add support for no link topology
From: Patrick Robb @ 2026-06-08 22:12 UTC (permalink / raw)
  To: Andrew Bailey; +Cc: dev, dmarx, luca.vizzarro, probb
In-Reply-To: <CABJ3N2UVNvqK2y6776bVE0zufpcSERjiroNxpXkf26q_pgajzg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1154 bytes --]

On Mon, Jun 1, 2026 at 1:16 PM Andrew Bailey <abailey@iol.unh.edu> wrote:

>
> Also, does the topology type affect whether we want to use these custom
>> args, if the SUT driver is ice? I guess in a weird case we could have an
>> ethdev test using an ice DUT which does not need a TG?
>>
>> My understanding is that if the link topology is no link, there will be
> no ingress and the ports on the NIC would not be used for traffic. I do not
> believe this argument will still be required if no traffic is being
> handled. Please let me know if you disagree with this approach or if I am
> missing something.
>

So, yes it probably does not matter which way we decide on this given that
no traffic is going to be transmitted. But, I suppose we might as well
maintain the same logic (compile this way with this DPDK PMD) as with
single link and dual link topologies, unless we have any reason to do
otherwise? But again, if we did compile without the argument in a no_link
topology, I don't think it would matter. So, in this case, whatever your
preference is between these two (as long as you provide a reason), I will
approve it.

[-- Attachment #2: Type: text/html, Size: 1693 bytes --]

^ permalink raw reply

* Re: [PATCH v13 01/20] net/sxe2: support AVX512 vectorized path for Rx and Tx
From: Stephen Hemminger @ 2026-06-08 20:56 UTC (permalink / raw)
  To: liujie5; +Cc: dev
In-Reply-To: <20260608074257.3043531-2-liujie5@linkdatatechnology.com>

On Mon,  8 Jun 2026 15:42:38 +0800
liujie5@linkdatatechnology.com wrote:

>  
> -struct sxe2_drv_queue_caps {
> +struct __rte_aligned(4) __rte_packed_begin sxe2_drv_queue_caps {
>  	uint16_t queues_cnt;
>  	uint16_t base_idx_in_pf;
> -};
> +} __rte_packed_end;

I don't see the point of packed and aligned. This structure is already embedded
in other struct. The alignment will be right.
Packed should be reserved for where you are avoiding padding.

Bottom line: drivers should not use packed except for hardware registers,
network headers.  You probably could just use existing structures here
and elsewhere; with static_assert() added in the vector code to make
sure future changes don't break assumptions.

> diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
> index 8d66e5d8c5..e0f7002138 100644
> --- a/drivers/net/sxe2/sxe2_ethdev.c
> +++ b/drivers/net/sxe2/sxe2_ethdev.c
> @@ -891,7 +891,7 @@ static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev,
>  static int32_t sxe2_parse_eth_devargs(struct rte_device *dev,
>  			  struct rte_eth_devargs *eth_da)
>  {
> -	int ret = 0;
> +	int32_t ret = 0;
>  
>  	if (dev->devargs == NULL)
>  		return 0;

Hmm. This raises the question why did sxe2 clone the model from other drivers using vdpa
but change the return to int32_t.

I think you are making things unnecessarily complex here:

$ git grep probe_t | grep int
drivers/bus/auxiliary/bus_auxiliary_driver.h:typedef int (rte_auxiliary_probe_t)(struct rte_auxiliary_driver *drv,
drivers/bus/cdx/bus_cdx_driver.h:typedef int (rte_cdx_probe_t)(struct rte_cdx_driver *, struct rte_cdx_device *);
drivers/bus/dpaa/bus_dpaa_driver.h:typedef int (*rte_dpaa_probe_t)(struct rte_dpaa_driver *dpaa_drv,
drivers/bus/fslmc/bus_fslmc_driver.h:typedef int (*rte_dpaa2_probe_t)(struct rte_dpaa2_driver *dpaa2_drv,
drivers/bus/ifpga/bus_ifpga_driver.h:typedef int (afu_probe_t)(struct rte_afu_device *);
drivers/bus/pci/bus_pci_driver.h:typedef int (rte_pci_probe_t)(struct rte_pci_driver *, struct rte_pci_device *);
drivers/bus/platform/bus_platform_driver.h:typedef int (rte_platform_probe_t)(struct rte_platform_device *pdev);
drivers/bus/uacce/bus_uacce_driver.h:typedef int (rte_uacce_probe_t)(struct rte_uacce_driver *, struct rte_uacce_device *);
drivers/bus/vdev/bus_vdev_driver.h:typedef int (rte_vdev_probe_t)(struct rte_vdev_device *dev);
drivers/bus/vmbus/bus_vmbus_driver.h:typedef int (vmbus_probe_t)(struct rte_vmbus_driver *,
drivers/common/mlx5/mlx5_common.h:typedef int (mlx5_class_driver_probe_t)(struct mlx5_common_device *cdev,
drivers/common/nfp/nfp_common_pci.h:typedef int (nfp_class_driver_probe_t)(struct rte_pci_device *dev);
drivers/common/sxe2/sxe2_common.h:typedef int32_t (sxe2_class_driver_probe_t)(struct sxe2_common_device *scdev,
lib/eal/include/bus_driver.h:typedef int (*rte_bus_probe_t)(struct rte_bus *bus);

No other driver uses int32...

> @@ -315,19 +370,30 @@ static const struct {
>  	eth_rx_burst_t rx_burst;
>  	const char *info;
>  } sxe2_rx_burst_infos[] = {
> -	{ sxe2_rx_pkts_scattered,          "Scalar Scattered" },
> -	{ sxe2_rx_pkts_scattered_split,          "Scalar Scattered split" },
> +	{ sxe2_rx_pkts_scattered,
> +	      "Scalar Scattered" },
> +	{ sxe2_rx_pkts_scattered_split,
> +	      "Scalar Scattered split" },
>  #ifdef RTE_ARCH_X86
> -	{ sxe2_rx_pkts_scattered_vec_sse_offload,      "Vector SSE Scattered" },
> +#ifdef CC_AVX512_SUPPORT
> +	{ sxe2_rx_pkts_scattered_vec_avx512,
> +	      "Vector AVX512 Scattered" },
> +	{ sxe2_rx_pkts_scattered_vec_avx512_offload,
> +	      "Offload Vector AVX512 Scattered" },
> +#endif
> +	{ sxe2_rx_pkts_scattered_vec_sse_offload,
> +	      "Vector SSE Scattered" },
>  #endif
>  };

The table looked better before with longer lines.
The DPDK coding style allows lines up to 100 characters; why not use it

>  int32_t sxe2_rx_burst_mode_get(struct rte_eth_dev *dev,
> -			__rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode)
> +			       __rte_unused uint16_t queue_id,
> +			       struct rte_eth_burst_mode *mode)
>  {
>  	eth_rx_burst_t pkt_burst = dev->rx_pkt_burst;
>  	int32_t ret = -EINVAL;
>  	uint32_t i, size;
> +
>  	size = RTE_DIM(sxe2_rx_burst_infos);
>  	for (i = 0; i < size; ++i) {
>  		if (pkt_burst == sxe2_rx_burst_infos[i].rx_burst) {

The old code was fine, no need to change this. Either indentation style is OK.
Prefer not to have non-related changes.


> +static __rte_always_inline void
> +sxe2_tx_pkts_mbuf_fill_avx512(struct sxe2_tx_buffer_vec *buffer,
> +	struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
> +{

Please only use always_inline where it is absolutely necessary.
Dont fight with the compiler.

> +static __rte_always_inline int32_t sxe2_tx_bufs_free_vec_avx512(struct sxe2_tx_queue *txq)
> +{
> +	struct sxe2_tx_buffer_vec *buffer;
> +	struct rte_mbuf *mbuf;
> +	struct rte_mbuf *mbuf_free_arr[SXE2_TX_FREE_BUFFER_SIZE_MAX_VEC];
> +	struct rte_mempool *mp;
> +	struct rte_mempool_cache *cache;
> +	void **cache_objs;
> +	uint32_t copied;
> +	uint32_t i;
> +	int32_t ret;
> +	uint16_t rs_thresh;
> +	uint16_t free_num;
> +
> +	if (rte_cpu_to_le_64(SXE2_TX_DESC_DTYPE_DESC_DONE) !=
> +		(txq->desc_ring[txq->next_dd].wb.dd &
> +			rte_cpu_to_le_64(SXE2_TX_DESC_DTYPE_MASK))) {
> +		ret = 0;
> +		goto l_end;
> +	}
> +
> +	rs_thresh = txq->rs_thresh;
> +
> +	buffer = (struct sxe2_tx_buffer_vec *)txq->buffer_ring;
> +	buffer += txq->next_dd - (rs_thresh - 1);
> +
> +	if ((txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) &&
> +			(rs_thresh & 31) == 0) {
> +		mp = buffer[0].mbuf->pool;
> +		cache = rte_mempool_default_cache(mp, rte_lcore_id());
> +
> +		if (cache == NULL || cache->len)
> +			goto normal;
> +
> +		if (rs_thresh > RTE_MEMPOOL_CACHE_MAX_SIZE) {
> +			(void)rte_mempool_ops_enqueue_bulk(mp, (void *)buffer, rs_thresh);
> +			goto done;
> +		}
> +		cache_objs = &cache->objs[cache->len];

Directly using cache is going to be brittle and likely get broken by other
coming changes to mempool cache.


^ permalink raw reply

* [PATCH 4/4] bpf/arm64: add BPF_ABS/BPF_IND packet load support
From: Stephen Hemminger @ 2026-06-08 20:28 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, Wathsala Vithanage, Konstantin Ananyev,
	Marat Khalili
In-Reply-To: <20260608203322.1116296-1-stephen@networkplumber.org>

The arm64 JIT rejected BPF_LD | BPF_ABS and BPF_LD | BPF_IND with
"invalid opcode", so cBPF programs converted by rte_bpf_convert() could
not be JITed. Add these opcodes, mirroring the x86 JIT: a fast path for
data held in the first mbuf segment and a __rte_pktmbuf_read() slow path
for everything else. Programs using these opcodes now use the call
register layout, since the slow path makes a function call.

Bugzilla ID: 1427

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/bpf/bpf_jit_arm64.c | 147 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 146 insertions(+), 1 deletion(-)

diff --git a/lib/bpf/bpf_jit_arm64.c b/lib/bpf/bpf_jit_arm64.c
index 099822e9f1..6952c61806 100644
--- a/lib/bpf/bpf_jit_arm64.c
+++ b/lib/bpf/bpf_jit_arm64.c
@@ -1123,6 +1123,133 @@ emit_branch(struct a64_jit_ctx *ctx, uint8_t op, uint32_t i, int16_t off)
 	emit_b_cond(ctx, ebpf_to_a64_cond(op), jump_offset_get(ctx, i, off));
 }
 
+/* LD_ABS/LD_IND code block offsets (in arm64 instructions) */
+enum {
+	LDMB_FAST_OFS, /* fast path */
+	LDMB_SLOW_OFS, /* slow path */
+	LDMB_FIN_OFS,  /* common tail */
+	LDMB_OFS_NUM
+};
+
+/*
+ * Helper for emit_ld_mbuf(): fast path.
+ * Compute the packet offset; if it lies inside the first segment leave the
+ * data pointer in R0, otherwise branch to the slow path.
+ */
+static void
+emit_ldmb_fast_path(struct a64_jit_ctx *ctx, uint8_t src, uint8_t mode,
+		    uint32_t sz, int32_t imm, const uint32_t ofs[LDMB_OFS_NUM])
+{
+	uint8_t r0 = ebpf_to_a64_reg(ctx, EBPF_REG_0);
+	uint8_t r6 = ebpf_to_a64_reg(ctx, EBPF_REG_6);
+	uint8_t tmp1 = ebpf_to_a64_reg(ctx, TMP_REG_1);
+	uint8_t tmp2 = ebpf_to_a64_reg(ctx, TMP_REG_2);
+	uint8_t tmp3 = ebpf_to_a64_reg(ctx, TMP_REG_3);
+
+	/* off = imm (+ src for BPF_IND) */
+	emit_mov_imm(ctx, 1, tmp1, imm);
+	if (mode == BPF_IND)
+		emit_add(ctx, 1, tmp1, src);
+
+	/* if ((int64_t)(mbuf->data_len - off) < sz) goto slow_path */
+	emit_mov_imm(ctx, 1, tmp2, offsetof(struct rte_mbuf, data_len));
+	emit_ldr(ctx, BPF_H, tmp2, r6, tmp2);
+	emit_sub(ctx, 1, tmp2, tmp1);
+	emit_mov_imm(ctx, 1, tmp3, sz);
+	emit_cmp(ctx, 1, tmp2, tmp3);
+	emit_b_cond(ctx, A64_LT, (int32_t)(ofs[LDMB_SLOW_OFS] - ctx->idx));
+
+	/* R0 = mbuf->buf_addr + mbuf->data_off + off */
+	emit_mov_imm(ctx, 1, tmp2, offsetof(struct rte_mbuf, data_off));
+	emit_ldr(ctx, BPF_H, tmp2, r6, tmp2);
+	emit_mov_imm(ctx, 1, r0, offsetof(struct rte_mbuf, buf_addr));
+	emit_ldr(ctx, EBPF_DW, r0, r6, r0);
+	emit_add(ctx, 1, r0, tmp2);
+	emit_add(ctx, 1, r0, tmp1);
+
+	emit_b(ctx, (int32_t)(ofs[LDMB_FIN_OFS] - ctx->idx));
+}
+
+/*
+ * Helper for emit_ld_mbuf(): slow path.
+ * R0 = __rte_pktmbuf_read(mbuf, off, sz, buf); return 0 if NULL.
+ * The scratch buffer is the space reserved by __rte_bpf_validate() at the
+ * bottom of the eBPF stack frame, i.e. (frame_pointer - stack_ofs).
+ */
+static void
+emit_ldmb_slow_path(struct a64_jit_ctx *ctx, uint32_t sz, uint32_t stack_ofs)
+{
+	uint8_t r0 = ebpf_to_a64_reg(ctx, EBPF_REG_0);
+	uint8_t r6 = ebpf_to_a64_reg(ctx, EBPF_REG_6);
+	uint8_t fp = ebpf_to_a64_reg(ctx, EBPF_FP);
+	uint8_t tmp1 = ebpf_to_a64_reg(ctx, TMP_REG_1);
+
+	/* arguments of __rte_pktmbuf_read(mbuf, off, len, buf) */
+	emit_mov_64(ctx, A64_R(1), tmp1);		/* off (held in tmp1) */
+	emit_mov_64(ctx, A64_R(0), r6);			/* mbuf */
+	emit_mov_imm(ctx, 0, A64_R(2), sz);		/* len */
+	emit_sub_imm_64(ctx, A64_R(3), fp, stack_ofs);	/* buf */
+
+	emit_call(ctx, tmp1, (void *)(uintptr_t)__rte_pktmbuf_read);
+	emit_return_zero_if_src_zero(ctx, 1, r0);
+}
+
+/*
+ * Helper for emit_ld_mbuf(): common tail.
+ * Load the value pointed to by R0 and convert from network byte order.
+ */
+static void
+emit_ldmb_fin(struct a64_jit_ctx *ctx, uint8_t opsz, uint32_t sz)
+{
+	uint8_t r0 = ebpf_to_a64_reg(ctx, EBPF_REG_0);
+
+	emit_ldr(ctx, opsz, r0, r0, A64_ZR);
+	if (opsz != BPF_B)
+		emit_be(ctx, r0, sz * 8);
+}
+
+/*
+ * Emit code for BPF_LD | BPF_ABS and BPF_LD | BPF_IND packet loads:
+ *
+ *	off = imm (+ src for BPF_IND)
+ *	if (mbuf->data_len - off >= sz)			    -- fast path
+ *		ptr = mbuf->buf_addr + mbuf->data_off + off;
+ *	else						    -- slow path
+ *		ptr = __rte_pktmbuf_read(mbuf, off, sz, buf);
+ *		if (ptr == NULL)
+ *			return 0;
+ *	R0 = ntoh(*(size *)ptr);			    -- common tail
+ *
+ * The three blocks are sized in a dry run so the forward branches can be
+ * resolved, then emitted for real (arm64 instructions are fixed width, so
+ * the dry run reproduces the real instruction count exactly).
+ */
+static void
+emit_ld_mbuf(struct a64_jit_ctx *ctx, uint8_t op, uint8_t src, int32_t imm,
+	     uint32_t stack_ofs)
+{
+	uint8_t mode = BPF_MODE(op);
+	uint8_t opsz = BPF_SIZE(op);
+	uint32_t sz = bpf_size(opsz);
+	uint32_t ofs[LDMB_OFS_NUM];
+
+	/* seed offsets so the dry-run branches stay in range */
+	ofs[LDMB_FAST_OFS] = ofs[LDMB_SLOW_OFS] = ofs[LDMB_FIN_OFS] = ctx->idx;
+
+	/* dry run to record block offsets */
+	emit_ldmb_fast_path(ctx, src, mode, sz, imm, ofs);
+	ofs[LDMB_SLOW_OFS] = ctx->idx;
+	emit_ldmb_slow_path(ctx, sz, stack_ofs);
+	ofs[LDMB_FIN_OFS] = ctx->idx;
+	emit_ldmb_fin(ctx, opsz, sz);
+
+	/* rewind and emit for real with resolved offsets */
+	ctx->idx = ofs[LDMB_FAST_OFS];
+	emit_ldmb_fast_path(ctx, src, mode, sz, imm, ofs);
+	emit_ldmb_slow_path(ctx, sz, stack_ofs);
+	emit_ldmb_fin(ctx, opsz, sz);
+}
+
 static void
 check_program_has_call(struct a64_jit_ctx *ctx, struct rte_bpf *bpf)
 {
@@ -1135,8 +1262,17 @@ check_program_has_call(struct a64_jit_ctx *ctx, struct rte_bpf *bpf)
 		op = ins->code;
 
 		switch (op) {
-		/* Call imm */
+		/*
+		 * BPF_ABS/BPF_IND can fall through to __rte_pktmbuf_read(),
+		 * so they need the call-clobbered register layout as well.
+		 */
 		case (BPF_JMP | EBPF_CALL):
+		case (BPF_LD | BPF_ABS | BPF_B):
+		case (BPF_LD | BPF_ABS | BPF_H):
+		case (BPF_LD | BPF_ABS | BPF_W):
+		case (BPF_LD | BPF_IND | BPF_B):
+		case (BPF_LD | BPF_IND | BPF_H):
+		case (BPF_LD | BPF_IND | BPF_W):
 			ctx->foundcall = 1;
 			return;
 		}
@@ -1338,6 +1474,15 @@ emit(struct a64_jit_ctx *ctx, struct rte_bpf *bpf)
 			emit_mov_imm(ctx, 1, dst, u64);
 			i++;
 			break;
+		/* R0 = ntoh(*(size *)(mbuf data + (src) + imm)) */
+		case (BPF_LD | BPF_ABS | BPF_B):
+		case (BPF_LD | BPF_ABS | BPF_H):
+		case (BPF_LD | BPF_ABS | BPF_W):
+		case (BPF_LD | BPF_IND | BPF_B):
+		case (BPF_LD | BPF_IND | BPF_H):
+		case (BPF_LD | BPF_IND | BPF_W):
+			emit_ld_mbuf(ctx, op, src, imm, bpf->stack_sz);
+			break;
 		/* *(size *)(dst + off) = src */
 		case (BPF_STX | BPF_MEM | BPF_B):
 		case (BPF_STX | BPF_MEM | BPF_H):
-- 
2.53.0


^ permalink raw reply related

* [PATCH 3/4] test: bpf check that bpf_convert can be JIT'd
From: Stephen Hemminger @ 2026-06-08 20:28 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Konstantin Ananyev, Marat Khalili
In-Reply-To: <20260608203322.1116296-1-stephen@networkplumber.org>

Add followup in bpf conversion tests to make sure resulting
code was also run through JIT.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test/test_bpf.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/app/test/test_bpf.c b/app/test/test_bpf.c
index 79d547dc82..f5ab447ff6 100644
--- a/app/test/test_bpf.c
+++ b/app/test/test_bpf.c
@@ -4569,6 +4569,7 @@ test_bpf_filter(pcap_t *pcap, const char *s)
 	struct bpf_program fcode;
 	struct rte_bpf_prm *prm = NULL;
 	struct rte_bpf *bpf = NULL;
+	int ret = -1;
 
 	if (pcap_compile(pcap, &fcode, s, 1, PCAP_NETMASK_UNKNOWN)) {
 		printf("%s@%d: pcap_compile('%s') failed: %s;\n",
@@ -4592,6 +4593,18 @@ test_bpf_filter(pcap_t *pcap, const char *s)
 			__func__, __LINE__, rte_errno, strerror(rte_errno));
 		goto error;
 	}
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_ARM64)
+	{
+		struct rte_bpf_jit jit;
+
+		rte_bpf_get_jit(bpf, &jit);
+		if (jit.func == NULL) {
+			printf("%s@%d: no JIT generated\n", __func__, __LINE__);
+			goto error;
+		}
+	}
+#endif
+	ret = 0;
 
 error:
 	if (bpf)
@@ -4603,7 +4616,7 @@ test_bpf_filter(pcap_t *pcap, const char *s)
 
 	rte_free(prm);
 	pcap_freecode(&fcode);
-	return (bpf == NULL) ? -1 : 0;
+	return ret;
 }
 
 static int
-- 
2.53.0


^ permalink raw reply related

* [PATCH 2/4] test: bpf check that JIT was generated
From: Stephen Hemminger @ 2026-06-08 20:28 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Konstantin Ananyev, Marat Khalili
In-Reply-To: <20260608203322.1116296-1-stephen@networkplumber.org>

Avoid silently ignoring JIT failures. The test cases should
all succeed JIT compilation; if not it is a bug in the JIT
implementation and should be reported.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test/test_bpf.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/app/test/test_bpf.c b/app/test/test_bpf.c
index dd24722450..79d547dc82 100644
--- a/app/test/test_bpf.c
+++ b/app/test/test_bpf.c
@@ -3508,6 +3508,14 @@ run_test(const struct bpf_test *tst)
 				rv, strerror(rv));
 		}
 	}
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_ARM64)
+	else {
+		/* a JIT backend exists for this arch, so it must compile */
+		printf("%s@%d: %s: no JIT code generated;\n",
+			__func__, __LINE__, tst->name);
+		ret = -1;
+	}
+#endif
 
 	rte_bpf_destroy(bpf);
 	return ret;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 1/4] bpf/arm64: fix zero-return branch in multi-exit programs
From: Stephen Hemminger @ 2026-06-08 20:28 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, stable, Wathsala Vithanage, Konstantin Ananyev,
	Marat Khalili, Jerin Jacob
In-Reply-To: <20260608203322.1116296-1-stephen@networkplumber.org>

If a JIT'd BPF program has more than one exit,
the branch to the epilogue can be backwards.

The current code assumed it is always forward:
emit_return_zero_if_src_zero() held the offset in an unsigned uint16_t,
so a backward (negative) offset wrapped to a large positive value and
branch off the end of the program, faulting at run time.

This was masked until now: the only test with this shape, test_ld_mbuf,
needs BPF_ABS/BPF_IND which the arm64 JIT did not implement, so it never
ran under the JIT.  The x86 JIT is unaffected because emit_epilog() keeps a
single exit (st->exit.off) reached from later exits and the divide-by-zero
check via a signed absolute jump (emit_abs_jcc), so direction does not
matter.

Use a signed offset; emit_b() already sign-extends imm26 correctly.

Fixes: 111e2a747a4f ("bpf/arm: add basic arithmetic operations")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/bpf/bpf_jit_arm64.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/bpf/bpf_jit_arm64.c b/lib/bpf/bpf_jit_arm64.c
index a04ef33a9c..099822e9f1 100644
--- a/lib/bpf/bpf_jit_arm64.c
+++ b/lib/bpf/bpf_jit_arm64.c
@@ -957,7 +957,7 @@ static void
 emit_return_zero_if_src_zero(struct a64_jit_ctx *ctx, bool is64, uint8_t src)
 {
 	uint8_t r0 = ebpf_to_a64_reg(ctx, EBPF_REG_0);
-	uint16_t jump_to_epilogue;
+	int32_t jump_to_epilogue;
 
 	emit_cbnz(ctx, is64, src, 3);
 	emit_mov_imm(ctx, is64, r0, 0);
-- 
2.53.0


^ permalink raw reply related

* [PATCH 0/4] bpf/arm64: add BPF_ABS/BPF_IND packet load support
From: Stephen Hemminger @ 2026-06-08 20:28 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger

Discovered this while exploring packet filtering.
The arm64 BPF JIT did not implement BPF_LD | BPF_ABS or BPF_LD | BPF_IND,
so cBPF filters converted by rte_bpf_convert() could not be JIT compiled
and silently fell back to the interpreter on arm64.

The first patch fixes a latent bug in emit_return_zero_if_src_zero():
the offset of the branch to the epilogue was held in an unsigned.
A backward branch wrapped around. Existing JIT tests were never
being run on ARM.

The next two patches make the bpf tests assert that,
on an architecture with a JITbackend, code is actually generated,
so a missing or failed JIT is reported rather than skipped.

The final patch adds the ABS/IND opcodes, mirroring the x86 JIT
with a fast path for data in the first
mbuf segment and a __rte_pktmbuf_read() slow path for the rest.


Stephen Hemminger (4):
  bpf/arm64: fix zero-return branch in multi-exit programs
  test: bpf check that JIT was generated
  test: bpf check that bpf_convert can be JIT'd
  bpf/arm64: add BPF_ABS/BPF_IND packet load support

 app/test/test_bpf.c     |  23 ++++++-
 lib/bpf/bpf_jit_arm64.c | 149 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 169 insertions(+), 3 deletions(-)

-- 
2.53.0


^ permalink raw reply

* RE: [PATCH v15 0/5] Support add/remove memory region and get-max-slots
From: Bathija, Pravin @ 2026-06-08 20:13 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: dev@dpdk.org, fengchengwen@huawei.com, maxime.coquelin@redhat.com,
	thomas@monjalon.net
In-Reply-To: <20260605094533.26cd079c@phoenix.local>

Hi Stephen, Answers inline. I have also sent out patch-set v16 incorporating the fixes from your AI review.


Internal Use - Confidential
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Friday, June 5, 2026 9:46 AM
> To: Bathija, Pravin <Pravin.Bathija@dell.com>
> Cc: dev@dpdk.org; fengchengwen@huawei.com;
> maxime.coquelin@redhat.com; thomas@monjalon.net
> Subject: Re: [PATCH v15 0/5] Support add/remove memory region and get-max-
> slots
>
>
> [EXTERNAL EMAIL]
>
> On Thu, 4 Jun 2026 23:57:18 +0000
> <pravin.bathija@dell.com> wrote:
>
> > From: Pravin M Bathija <pravin.bathija@dell.com>
> >
> > This is version v15 of the patchset and it incorporates the
> > recommendations made by Maxime Coquelin.
> >
> > Patch 4/5
> > - Changed VHOST_USER_REM_MEM_REG handler declaration from
> >   accepts_fd=true to accepts_fd=false, as the remove request does not
> >   expect FDs in ancillary data.
> > - Removed all close_msg_fds(ctx) calls from vhost_user_rem_mem_reg(), no
> >   longer needed since the handler is declared as not accepting FDs.
> > - Removed validate_msg_fds(dev, ctx, 0) check from
> >   vhost_user_rem_mem_reg(), as FD validation is now handled generically
> >   by the framework.
> > - Added targeted IOTLB cache invalidation in vhost_user_rem_mem_reg()
> >   using vhost_user_iotlb_cache_remove() for the removed region's GPA
> >   range, instead of the nuclear iotlb_flush_all() used by set_mem_table.
> >
> > This implementation has been extensively tested by doing Read/Write
> > I/O from multiple instances of fio + libblkio (front-end) talking to
> > spdk/dpdk (back-end) based drives. Tested with qemu front-end talking
> > to dpdk testpmd (back-end) performing add/removal of memory regions.
> > Also tested post-copy live migration after doing add_memory_region.
> >
> > Version Log:
> > Version v15 (Current version): Incorporate code review suggestions
> > from Maxime Coquelin as described above.
> >
> > Version v14: Incorporate code review suggestions from Stephen
> > Hemminger and Fengcheng Wen.
> > Changes from Fengcheng Wen review:
> > Patch 3/5
> > - Moved free_all_mem_regions() call sites in vhost_user_set_mem_table()
> >   from patch 4/5 to patch 3/5 so each commit compiles independently
> > Patch 4/5
> > - Renamed _dev_invalidate_vrings() to vhost_user_invalidate_vrings() to
> >   follow vhost naming convention
> > -  Added comment explaining *pdev propagation through
> >    translate_ring_addresses / numa_realloc()
> > - Reordered local variables in vhost_user_add_mem_reg() and
> >   vhost_user_rem_mem_reg() by descending line length
> > - Shortened overlap check variable names (current_region_guest_start/end
> >   --> cur_start/end, proposed_region_guest_start/end -> new_start/end)
> > - Fixed DMA error path in vhost_user_add_mem_reg(): added
> >   free_new_region_no_dma label so async_dma_map_region(false) is not
> >   called when the map itself failed.
> > Changes from Stephen Hemminger review:
> > Patch 4/5
> > - vhost_user_add_mem_reg() now constructs a reply with the back-end's
> >   host mapping address in userspace_addr and returns
> >   RTE_VHOST_MSG_RESULT_REPLY per the vhost-user spec
> > - Added validate_msg_fds(dev, ctx, 0) in vhost_user_rem_mem_reg() to
> >   reject malformed messages with unexpected file descriptors
> > - Dropped unnecessary (uint64_t) cast in
> > vhost_user_get_max_mem_slots()
> >
> > Version v13: Incorporate code review suggestions from Fengcheng Wen
> > Patch 2/5 Renamed VhostUserSingleMemReg to VhostUserMemRegMsg and
> > memory_single to memreg Patches 3/5 and 4/5 Relocated function
> > remove_guest_pages from patch 3/5 to 4/5
> >
> > Version v12: Incorporate code review suggestions from Maxime Coquelin
> > and ai-code-review.
> > Patch 3/5
> > Refactored async_dma_map() to delegate to async_dma_map_region(),
> > eliminating code duplication between the two functions.
> > Restored original comments in async_dma_map_region() explaining why
> > ENODEV and EINVAL errors are ignored (these were stripped in v10)
> > Reverted unnecessary changes to vhost_user_postcopy_register() --
> > removed the host_user_addr == 0 checks and reg_msg_index indirection
> > that were added in  v10, since this function is only called from
> > vhost_user_set_mem_table() where regions are always contiguous.
> >
> > Version v11: Incorporate code review suggestions from Stephen Hemminger.
> > Patch 4/5
> > Fix incomplete cleanup in vhost_user_add_mem_reg() when
> > vhost_user_mmap_region() fails after the mmap succeeds (e.g.
> > add_guest_pages() realloc failure) realloc failure). The error path
> > now calls remove_guest_pages() and free_mem_region() to undo the
> > mapping and stale guest-page entries, preventing a leaked mmap and
> > slot reuse corruption. The plain close(fd) path is kept for pre-mmap failures.
> >
> > Version v10: Incorporate code review suggestions from Stephen Hemminger.
> > Patch 4/5
> > Moved dev_invalidate_vrings after free_mem_region, array compaction,
> > and nregions decrement. This ensures translate_ring_addresses only
> > sees surviving memory regions, preventing vring pointers from
> > resolving into a region that is about to be unmapped.
> >
> > Version v9: Incorporate code review suggestions from Stephen Hemminger.
> > Patch 3/5
> > Restored max_guest_pages initial value to hardcoded 8 instead of
> > VHOST_MEMORY_MAX_NREGIONS, matching upstream semantics.
> > Patch 4/5
> > Added close(reg->fd) and reg->fd = -1 before goto close_msg_fds in the
> > mmap failure path to fix fd leak after fd was moved from ctx->fds[0].
> > Converted dev_invalidate_vrings from a plain function to a macro +
> > implementation function pair, accepting message ID as a parameter so
> > the static_assert reports the correct handler at each call site.
> > Updated dev_invalidate_vrings call in add_mem_reg to pass
> > VHOST_USER_ADD_MEM_REG as message ID.
> > Updated dev_invalidate_vrings call in rem_mem_reg to pass
> > VHOST_USER_REM_MEM_REG as message ID.
> >
> > Version v8:  Incorporate code review suggestions from Stephen Hemminger.
> > rewrite async_dma_map_region function to iterate guest pages by host
> > address range matching change function dev_invalidate_vrings to accept
> > a double pointer to propagate pointer updates new function
> > remove_guest_pages was added add_mem_reg error path was narrowed to
> > only clean up the single failed region instead of destroting all
> > existing regions
> >
> > Version v7: Incorporate code review suggestions from Maxime Coquelin.
> > Add debug messages to vhost_postcopy_register function.
> >
> > Version v6: Added the enablement of this feature as a final patch in
> > this patch-set and other code optimizations as suggested by Maxime
> > Coquelin.
> >
> > Version v5: removed the patch that increased the number of memory
> > regions from 8 to 128. This will be submitted as a separate feature at
> > a later point after incorporating additional optimizations. Also
> > includes code optimizations as suggested by Feng Cheng Wen.
> >
> > Version v4: code optimizations as suggested by Feng Cheng Wen.
> >
> > Version v3: code optimizations as suggested by Maxime Coquelin and
> > Thomas Monjalon.
> >
> > Version v2: code optimizations as suggested by Maxime Coquelin.
> >
> > Version v1: Initial patch set.
> >
> > Pravin M Bathija (5):
> >   vhost: add user to mailmap and define to vhost hdr
> >   vhost: header defines for add/rem mem region
> >   vhost: refactor memory helper functions
> >   vhost: add mem region add/remove handlers
> >   vhost: enable configure memory slots
> >
> >  .mailmap               |   1 +
> >  lib/vhost/rte_vhost.h  |   4 +
> >  lib/vhost/vhost_user.c | 425
> > +++++++++++++++++++++++++++++++++++------
> >  lib/vhost/vhost_user.h |  10 +
> >  4 files changed, 378 insertions(+), 62 deletions(-)
> >
>
> I don't think this is ready to merge based on AI review.
> Did AI review with Opus 4.8 on a chat which has past context.
>
> Summary of v15 findings
>
>
> New in v15 (both patch 4/5, both errors):
>
>     Use-after-free on the reply path: reg points into dev->mem->regions[], but
> dev_invalidate_vrings() -> translate_ring_addresses() -> numa_realloc() can
> relocate dev->mem. dev is refreshed via *pdev, reg is not, then reg-
> >host_user_addr is read for the reply. Re-derive reg (or capture
> host_user_addr) after dev = *pdev.
Confirmed. reg points into dev->mem->regions[], and dev_invalidate_vrings() -> translate_ring_addresses() -> numa_realloc()
can reallocate dev->mem, leaving reg dangling before reg->host_user_addr is read. Fixed by re-deriving the region from the
refreshed dev (reg = &dev->mem->regions[dev->mem->nregions - 1]) after dev = *pdev, before building the reply.

>     ADD_MEM_REG reply sent unconditionally: handler always returns
> RESULT_REPLY, but the spec makes the mapping-address reply postcopy- only.
> In non-postcopy mode this desyncs the channel (no REPLY_ACK: the front-end
> never reads it; with REPLY_ACK: it expects a u64 ack, not a memreg). Gate the
> reply on dev->postcopy_listening, else return RESULT_OK -- same as
> SET_MEM_TABLE.
Confirmed against the vhost-user spec, which states the mapping-address reply is postcopy-only ("In postcopy mode... the
back-end replies  with the bases of the memory mapped region"). The reply is now gated on dev->postcopy_listening: return
RTE_VHOST_MSG_RESULT_REPLY in postcopy mode, and RTE_VHOST_MSG_RESULT_OK otherwise, matching
VHOST_USER_SET_MEM_TABLE. This avoids desyncing the channel in non-postcopy mode.

>
> Carried over from v13 (now in a different form):
>
>     The v13 Warning (missing postcopy mapping-address reply) is addressed but
> mis-gated; correct fix is the conditional reply above. Until then postcopy
> correctness still isn't right.

Same fix as above.


^ permalink raw reply

* Re: [PATCH v7 1/1] net/mana: add device reset support
From: Stephen Hemminger @ 2026-06-08 19:11 UTC (permalink / raw)
  To: Wei Hu; +Cc: dev, longli, weh
In-Reply-To: <20260608120824.287050-2-weh@linux.microsoft.com>

On Mon,  8 Jun 2026 05:08:24 -0700
Wei Hu <weh@linux.microsoft.com> wrote:

> From: Wei Hu <weh@microsoft.com>
> 
> Add support for handling hardware reset events in the MANA driver.
> When the MANA kernel driver receives a hardware service event, it
> initiates a device reset and notifies userspace via
> IBV_EVENT_DEVICE_FATAL. The DPDK driver handles this by performing
> an automatic teardown and recovery sequence.
> 
> The reset flow has two phases. In the enter phase, running on the
> EAL interrupt thread, the driver transitions the device state,
> waits for data path threads to drain using per-queue atomic flags,
> stops queues, tears down IB resources, and frees per-queue MR
> caches. A control thread is then spawned to handle the exit phase:
> it waits for the hardware to recover, unregisters the interrupt
> handler, re-probes the PCI device, reinitializes MR caches, and
> restarts queues.
> 
> Each queue has an atomic burst_state variable where bit 0 is the
> in-burst flag and bits 1+ encode device state. The data path uses
> a single compare-and-swap (0 to 1) to enter a burst, which fails
> immediately if the reset path has set any state bits. The reset
> path sets state bits via atomic fetch-or and polls bit 0 to wait
> for in-flight bursts to drain. This single-variable design avoids
> the need for sequential consistency ordering.
> 
> A per-device mutex serializes the reset path with ethdev
> operations. The mutex uses PTHREAD_PROCESS_SHARED for multi-process
> support and is held across blocking IB verbs calls. A trylock
> helper encapsulates the lock acquisition and device state check
> for all ethdev operation wrappers. Operations that cannot wait
> (configure, queue setup) return -EBUSY during reset, while
> dev_stop and dev_close join the reset thread before acquiring
> the lock to ensure proper sequencing. A CAS-based helper prevents
> double-join of the reset thread.
> 
> Multi-process support is included: secondary processes unmap and
> remap doorbell pages via IPC during the reset enter and exit
> phases. Data path functions in both primary and secondary
> processes check the device state atomically and return early when
> the device is not active.
> 
> The driver emits RTE_ETH_EVENT_ERR_RECOVERING before entering the
> reset path so that upper layers (e.g. netvsc) can switch their
> data path before queues are stopped. The event is emitted outside
> the reset lock to avoid deadlock if the callback calls dev_stop or
> dev_close. On completion, the driver emits RECOVERY_SUCCESS or
> RECOVERY_FAILED. If the enter phase fails internally,
> RECOVERY_FAILED is sent immediately so the application receives a
> terminal event. A PCI device removal event callback distinguishes
> hot-remove from service reset.
> 
> Documentation for the device reset feature is added in the MANA
> NIC guide and the 26.07 release notes.
> 
> Signed-off-by: Wei Hu <weh@microsoft.com>
> ---

This is is a rather complex set of state transitions so admit to relying
on AI as backup for tracking this. It still sees some errors here.

Worth asking the question, "what does mlx5 do?" and "should DPDK
EAL be doing this at the PCI layer instead?"

---

Much better - this addresses the RCU, the macros, the thread-safety-analysis
suppressions, and the callback-under-lock deadlock. The single-variable
burst_state CAS is a clean way to do the drain and the acquire/release
reasoning checks out.

One structural thing remains. The enter phase still runs the heavy teardown
on the EAL interrupt thread under reset_ops_lock: dev_stop, then
mana_mp_req_on_rxtx(RESET_ENTER) which is a blocking rte_mp_request_sync with
a multi-second timeout, then dev_close with its ibv calls. You already moved
the exit phase to a control thread because intr_callback_unregister cannot run
on the interrupt thread; the same argument applies to blocking IPC and verbs
teardown. A slow or absent secondary will stall the interrupt thread for the
MP timeout, and this is the blocking-under-a-sleeping-mutex pattern. Please
have the interrupt handler just set state and drain, then hand the rest of the
teardown to the control thread. That also removes the last lock hand-off
between functions/threads, so each function can own its lock.

Smaller points:
- RECOVERY_SUCCESS/FAILED are emitted from the reset thread. If the callback
  calls dev_stop/dev_close, mana_join_reset_thread() joins the current thread
  (EDEADLK, leaked handle). INTR_RMV is fine since it runs on the dev-event
  thread.
- The burst_state comment says bits 1+ encode device state, but only
  RESET_ENTER<<1 is ever stored - it is effectively a single "blocked" flag.

^ permalink raw reply

* Re: [PATCH] net/crc: reduce usage of static arrays in net_crc_sse.c
From: Stephen Hemminger @ 2026-06-08 17:16 UTC (permalink / raw)
  To: Shreesh Adiga; +Cc: Bruce Richardson, Konstantin Ananyev, Jasvinder Singh, dev
In-Reply-To: <20251011113202.937991-1-16567adigashreesh@gmail.com>

On Sat, 11 Oct 2025 16:59:34 +0530
Shreesh Adiga <16567adigashreesh@gmail.com> wrote:

> Replace the clearing of lower 32 bits of XMM register with blend of
> zero register.
> Remove the clearing of upper 64 bits of tmp1 as it is redundant.
> tmp1 after clearing upper bits was being xor with tmp2 before the
> bits 96:65 from tmp2 were returned. The xor operation of bits 96:65
> remains unchanged due to tmp1 having bits 96:64 cleared to 0.
> After removing the xor operation, the clearing of upper 64 bits of tmp1
> becomes redundant and hence can be removed.
> Clang is able to optimize away the AND + memory operand with the
> above sequence, however GCC is still emitting the code for AND with
> memory operands which is being explicitly eliminated here.
> 
> Additionally replace the 48 byte crc_xmm_shift_tab with the contents of
> shf_table which is 32 bytes, achieving the same functionality.
> 

Applied to net-next

^ permalink raw reply

* Re: [PATCH] net/crc: reduce usage of static arrays in net_crc_sse.c
From: Stephen Hemminger @ 2026-06-08 17:16 UTC (permalink / raw)
  To: Shreesh Adiga; +Cc: Bruce Richardson, Konstantin Ananyev, Jasvinder Singh, dev
In-Reply-To: <20250716103439.831760-1-16567adigashreesh@gmail.com>

On Wed, 16 Jul 2025 16:04:39 +0530
Shreesh Adiga <16567adigashreesh@gmail.com> wrote:

> Replace the clearing of lower 32 bits of XMM register with blend of
> zero register.
> Replace the clearing of upper 64 bits of XMM register with _mm_move_epi64.
> Clang is able to optimize away the AND + memory operand with the
> above sequence, however GCC is still emitting the code for AND with
> memory operands which is being explicitly eliminated here.
> 
> Additionally replace the 48 byte crc_xmm_shift_tab with the contents of
> shf_table which is 32 bytes, achieving the same functionality.
> 
> Signed-off-by: Shreesh Adiga <16567adigashreesh@gmail.com>
> ---

Applied to net-next

^ permalink raw reply

* Re: [PATCH v2 2/3] event/cnxk: add pause to spinloops
From: Stephen Hemminger @ 2026-06-08 17:44 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: dev, Pavan Nikhilesh, Shijith Thotton
In-Reply-To: <CALBAE1PzEtyBzKiKaU83q0OtwRwaCTmqDETsc5NNODDQ9hzauw@mail.gmail.com>

On Mon, 8 Jun 2026 21:19:20 +0530
Jerin Jacob <jerinjacobk@gmail.com> wrote:

> On Mon, Apr 13, 2026 at 10:36 PM Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On SMT systems when a spinloop is done without a pause
> > it may cause excessive latency. This problem was found
> > by the fix_empty_spinloops coccinelle script.
> >
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>  
> 
> rte_pause() translates to YIELD instruction. Since cnxk is an
> integrated SoC and it is a single threaded core, it won't help on
> anything other than adding one instruction bit more latency.
> In general 3/3 devtool is good. Please send a it separate version so
> that 3/3 patches can be merged through the main tree.


It matters if your SOC has SMT where two cores are sharing
and one core is waiting for its partner.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox