DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 20/20] net/sxe2: update sxe2 feature matrix docs
From: liujie5 @ 2026-06-02  5:54 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260602055414.630859-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Update the sxe2.ini feature sheet to accurately reflect the recently
implemented hardware capabilities in the sxe2 PMD.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 doc/guides/nics/features/sxe2.ini | 65 +++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/doc/guides/nics/features/sxe2.ini b/doc/guides/nics/features/sxe2.ini
index 09ba2f558c..b8d6c937ab 100644
--- a/doc/guides/nics/features/sxe2.ini
+++ b/doc/guides/nics/features/sxe2.ini
@@ -7,17 +7,82 @@
 ; is selected.
 ;
 [Features]
+Speed capabilities   = Y
+Link status          = Y
+Link status event    = Y
+Rx interrupt         = Y
 Fast mbuf free       = P
 Free Tx mbuf on demand = Y
 Burst mode info      = Y
 Queue start/stop     = Y
+Power mgmt address monitor = Y
 Buffer split on Rx   = P
 Scattered Rx         = Y
+Traffic manager      = Y
 CRC offload          = Y
+VLAN offload         = Y
+QinQ offload         = P
 L3 checksum offload  = Y
 L4 checksum offload  = Y
+Timestamp offload    = P
+Inner L3 checksum    = P
+Inner L4 checksum    = P
 Rx descriptor status = Y
 Tx descriptor status = Y
+MTU update           = Y
+TSO                  = P
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+RSS hash             = Y
+RSS key update       = Y
+RSS reta update      = Y
+VLAN filter          = Y
+Inline crypto        = Y
+Packet type parsing  = Y
+Timesync             = Y
+Basic stats          = Y
+Extended stats       = Y
+FW version           = Y
+Module EEPROM dump   = Y
+Multiprocess aware   = Y
 Linux                = Y
 x86-32               = Y
 x86-64               = Y
+
+[rte_flow items]
+ah                   = Y
+any                  = Y
+arp_eth_ipv4         = Y
+esp                  = Y
+eth                  = P
+gtpu                 = Y
+gtp_psc              = Y
+icmp                 = Y
+icmp6                = Y
+ipv4                 = Y
+ipv6                 = Y
+ipv6_frag_ext        = Y
+l2tpv3oip            = Y
+nvgre                = Y
+pfcp                 = Y
+pppoed               = Y
+pppoes               = Y
+pppoe_proto_id       = Y
+raw                  = Y
+sctp                 = Y
+tcp                  = Y
+udp                  = Y
+vlan                 = P
+vxlan                = Y
+
+[rte_flow actions]
+count                = Y
+drop                 = Y
+mark                 = Y
+passthru             = Y
+port_representor     = Y
+queue                = Y
+represented_port     = Y
+rss                  = Y
+send_to_kernel       = Y
-- 
2.52.0


^ permalink raw reply related

* [PATCH v5 15/20] common/sxe2: add shared SFP module definitions
From: liujie5 @ 2026-06-02  5:54 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260602055414.630859-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch adds a new shared header file 'sxe2_msg.h' which
contains definitions for SFP/SFP+ modules. This file is shared across
Firmware, Kernel driver, and DPDK PMD to ensure consistent protocol
handling.

The header includes:
- SFP EEPROM memory map offsets.
- Module type encoding definitions.

By using this shared header, the PMD can correctly identify module
capabilities and report diagnostic information in a way that is
consistent with the underlying firmware logic.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_msg.h | 118 +++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 drivers/common/sxe2/sxe2_msg.h

diff --git a/drivers/common/sxe2/sxe2_msg.h b/drivers/common/sxe2/sxe2_msg.h
new file mode 100644
index 0000000000..f08944f7c9
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_msg.h
@@ -0,0 +1,118 @@
+
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_MSG_H__
+#define __SXE2_MSG_H__
+
+enum sfp_type_identifier {
+	SXE2_SFP_TYPE_UNKNOWN       = 0x00,
+	SXE2_SFP_TYPE_SFP          = 0x03,
+
+	SXE2_SFP_TYPE_QSFP_PLUS    = 0x0D,
+	SXE2_SFP_TYPE_QSFP28       = 0x11,
+
+	SXE2_SFP_TYPE_MAX          = 0xFF,
+};
+
+#ifndef SFP_DEFINE
+#define SFP_DEFINE
+
+#define SXE2_SFP_EEP_WR            0x1
+#define SXE2_SFP_EEP_QSFP          0x1
+
+enum sfp_bus_addr {
+	SXE2_SFP_EEP_I2C_ADDR0 = 0xA0,
+	SXE2_SFP_EEP_I2C_ADDR1 = 0xA2,
+	SXE2_SFP_EEP_I2C_ADDR_NR = 0xFFFF,
+};
+
+struct sxe2_sfp_req {
+	uint8_t is_wr;
+	uint8_t is_qsfp;
+	uint16_t bus_addr;
+	uint16_t page_cnt;
+	uint16_t offset;
+	uint16_t data_len;
+	uint16_t rvd;
+	uint8_t data[];
+};
+
+struct sxe2_sfp_resp {
+	uint8_t is_wr;
+	uint8_t is_qsfp;
+	uint16_t data_len;
+	uint8_t data[];
+};
+
+enum sfp_page_cnt {
+	SXE2_SFP_EEP_PAGE_CNT0     = 0,
+	SXE2_SFP_EEP_PAGE_CNT1,
+	SXE2_SFP_EEP_PAGE_CNT2,
+	SXE2_SFP_EEP_PAGE_CNT3,
+	SXE2_SFP_EEP_PAGE_CNT20    = 20,
+	SXE2_SFP_EEP_PAGE_CNT21    = 21,
+
+	SXE2_SFP_EEP_PAGE_CNT_NR   = 0xFFFF,
+};
+
+#define SXE2_SFP_E2P_I2C_7BIT_ADDR0             (SXE2_SFP_EEP_I2C_ADDR0 >> 1)
+#define SXE2_SFP_E2P_I2C_7BIT_ADDR1             (SXE2_SFP_EEP_I2C_ADDR1 >> 1)
+
+#define SXE2_QSFP_PAGE_OFST_START  128
+#define SXE2_SFP_EEP_OFST_MAX      255
+#define SXE2_SFP_EEP_LEN_MAX       256
+#endif
+
+#ifndef FW_STATE_DEFINE
+#define FW_STATE_DEFINE
+
+#define SXE2_FW_STATUS_MAIN_SHIF       (16)
+#define SXE2_FW_STATUS_MAIN_MASK       (0xFF0000)
+#define SXE2_FW_STATUS_SUB_MASK        (0xFFFF)
+
+enum Sxe2FwStateMain {
+	SXE2_FW_STATE_MAIN_UNDEFINED       = 0x00,
+	SXE2_FW_STATE_MAIN_INIT            = 0x10000,
+	SXE2_FW_STATE_MAIN_RUN             = 0x20000,
+	SXE2_FW_STATE_MAIN_ABNOMAL         = 0x30000,
+};
+
+enum Sxe2FwState {
+	SXE2_FW_START_STATE_UNDEFINED = SXE2_FW_STATE_MAIN_UNDEFINED,
+	SXE2_FW_START_STATE_INIT_BASE = (SXE2_FW_STATE_MAIN_INIT + 0x1),
+	SXE2_FW_START_STATE_SCAN_DEVICE = (SXE2_FW_STATE_MAIN_INIT + 0x20),
+	SXE2_FW_START_STATE_FINISHED = (SXE2_FW_STATE_MAIN_RUN + 0x0),
+	SXE2_FW_START_STATE_UPGRADE = (SXE2_FW_STATE_MAIN_RUN + 0x1),
+	SXE2_FW_START_STATE_SYNC = (SXE2_FW_STATE_MAIN_RUN + 0x2),
+	SXE2_FW_RUNNING_STATE_ABNOMAL = (SXE2_FW_STATE_MAIN_ABNOMAL + 0x1),
+	SXE2_FW_RUNNING_STATE_ABNOMAL_CORE1 = (SXE2_FW_STATE_MAIN_ABNOMAL + 0x2),
+	SXE2_FW_RUNNING_STATE_ABNOMAL_HEART = (SXE2_FW_STATE_MAIN_ABNOMAL + 0x3),
+	SXE2_FW_START_STATE_MASK = (SXE2_FW_STATUS_MAIN_MASK | SXE2_FW_STATUS_SUB_MASK),
+};
+#endif
+
+#ifndef LED_DEFINE
+#define LED_DEFINE
+
+enum sxe2_led_mode {
+	SXE2_IDENTIFY_LED_BLINK_ON   = 0,
+	SXE2_IDENTIFY_LED_BLINK_OFF,
+	SXE2_IDENTIFY_LED_ON,
+	SXE2_IDENTIFY_LED_OFF,
+	SXE2_IDENTIFY_LED_RESET,
+};
+
+
+typedef struct sxe2_led_ctrl {
+	uint32_t mode;
+	uint32_t duration;
+} sxe2_led_ctrl_s;
+
+typedef struct sxe2_led_ctrl_resp {
+	uint32_t ack;
+} sxe2_led_ctrl_resp_s;
+#endif
+
+#endif /* __SXE2_MSG_H__ */
-- 
2.52.0


^ permalink raw reply related

* [PATCH v5 11/20] drivers: add support for VF representors
From: liujie5 @ 2026-06-02  5:54 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260602055414.630859-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Add support for VF representors in sxe2 PMD. This allows the host
application (e.g., OVS-DPDK) to control and monitor virtual functions
through a dedicated ethdev on the PF (Physical Function) side.

Key changes include:
- Added representor enumeration and identification logic.
- Implemented representor-specific dev_ops (link update, stats, etc.).
- Configured back-channel communication between PF and VF for control
  messages.
- Supported the "-a <DBDF>,representor=[0-N]" EAL parameter to
  instantiate representor ports.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_common.c          |   46 +
 drivers/common/sxe2/sxe2_common.h          |    2 +
 drivers/net/sxe2/meson.build               |    6 +
 drivers/net/sxe2/sxe2_cmd_chnl.c           |  311 +++-
 drivers/net/sxe2/sxe2_cmd_chnl.h           |   28 +
 drivers/net/sxe2/sxe2_drv_cmd.h            |   55 +-
 drivers/net/sxe2/sxe2_ethdev.c             |  201 ++-
 drivers/net/sxe2/sxe2_ethdev.h             |   11 +
 drivers/net/sxe2/sxe2_ethdev_repr.c        |  607 +++++++
 drivers/net/sxe2/sxe2_ethdev_repr.h        |   32 +
 drivers/net/sxe2/sxe2_filter.c             |  121 +-
 drivers/net/sxe2/sxe2_filter.h             |    2 +
 drivers/net/sxe2/sxe2_flow.c               | 1337 ++++++++++++++
 drivers/net/sxe2/sxe2_flow.h               |   29 +
 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 | 1822 ++++++++++++++++++++
 drivers/net/sxe2/sxe2_flow_parse_pattern.h |   40 +
 drivers/net/sxe2/sxe2_irq.c                |   54 +
 drivers/net/sxe2/sxe2_irq.h                |    4 +
 drivers/net/sxe2/sxe2_queue.c              |    6 +-
 drivers/net/sxe2/sxe2_stats.c              |   17 +-
 drivers/net/sxe2/sxe2_switchdev.c          |  332 ++++
 drivers/net/sxe2/sxe2_switchdev.h          |   33 +
 drivers/net/sxe2/sxe2_txrx.c               |    7 +
 drivers/net/sxe2/sxe2_txrx_poll.c          |    8 +
 drivers/net/sxe2/sxe2_vsi.c                |  146 ++
 drivers/net/sxe2/sxe2_vsi.h                |   12 +-
 30 files changed, 6571 insertions(+), 22 deletions(-)
 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_flow.c
 create mode 100644 drivers/net/sxe2/sxe2_flow.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_switchdev.c
 create mode 100644 drivers/net/sxe2/sxe2_switchdev.h

diff --git a/drivers/common/sxe2/sxe2_common.c b/drivers/common/sxe2/sxe2_common.c
index f34427c569..a5d36998e1 100644
--- a/drivers/common/sxe2/sxe2_common.c
+++ b/drivers/common/sxe2/sxe2_common.c
@@ -169,6 +169,37 @@ static int32_t sxe2_parse_class_type(const char *key, const char *value, void *a
 	return ret;
 }
 
+static int32_t sxe2_parse_driver(const char *key, const char *value, void *args)
+{
+	int32_t ret = -EINVAL;
+
+	if (value == NULL || args == NULL) {
+		ret = 0;
+		goto l_end;
+	}
+
+	if (strcmp(value, "sxe2") != 0) {
+		PMD_LOG_ERR(COM, "%s: \"%s\" is not a valid driver.",
+			key, value);
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_parse_representor(const char *key, const char *value, void *args)
+{
+	int32_t ret = 0;
+
+	if (value == NULL || args == NULL)
+		goto l_end;
+
+	PMD_LOG_INFO(COM, "representor arg %s: \"%s\".", key, value);
+
+l_end:
+	return ret;
+}
+
 static int32_t sxe2_common_device_setup(struct sxe2_common_device *cdev)
 {
 	struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(cdev->dev);
@@ -394,6 +425,21 @@ static int32_t sxe2_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused
 			goto l_free_args;
 		}
 
+		ret = sxe2_kvargs_process(kv_info_p, SXE2_DEVARGS_KEY_DRIVER,
+				sxe2_parse_driver, NULL);
+		if (ret < 0) {
+			PMD_LOG_ERR(COM, "Unsupported sxe2 driver name: %s",
+				rte_dev->devargs->args);
+			goto l_free_args;
+		}
+
+		ret = sxe2_kvargs_process(kv_info_p, SXE2_DEVARGS_KEY_REPR,
+				sxe2_parse_representor, NULL);
+		if (ret < 0) {
+			PMD_LOG_ERR(COM, "Unsupported sxe2 driver representor: %s",
+				rte_dev->devargs->args);
+			goto l_free_args;
+		}
 	}
 
 	cdev = sxe2_common_device_alloc(rte_dev, class_type);
diff --git a/drivers/common/sxe2/sxe2_common.h b/drivers/common/sxe2/sxe2_common.h
index 482d29a7bb..b02b6317da 100644
--- a/drivers/common/sxe2/sxe2_common.h
+++ b/drivers/common/sxe2/sxe2_common.h
@@ -18,6 +18,8 @@
 	((cdev)->config.cmd_fd)
 
 #define SXE2_DEVARGS_KEY_CLASS "class"
+#define SXE2_DEVARGS_KEY_DRIVER "driver"
+#define SXE2_DEVARGS_KEY_REPR "representor"
 
 struct sxe2_class_driver;
 
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 4565046eae..65286299aa 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -71,4 +71,10 @@ sources += files(
         'sxe2_mp.c',
         'sxe2_stats.c',
         'sxe2_irq.c',
+        'sxe2_switchdev.c',
+        'sxe2_ethdev_repr.c',
+        'sxe2_flow.c',
+        'sxe2_flow_parse_action.c',
+        'sxe2_flow_parse_pattern.c',
+        'sxe2_flow_parse_engine.c',
 )
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index d1f15084ed..6e2dd139a5 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -64,6 +64,23 @@ int32_t sxe2_drv_dev_caps_get(struct sxe2_adapter *adapter, struct sxe2_drv_dev_
 	return ret;
 }
 
+int32_t sxe2_drv_switchdev_info_get(struct sxe2_adapter *adapter,
+				    struct sxe2_switchdev_info *switchdev_info)
+{
+	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_DEV_GET_SWITCHDEV_INFO,
+				 NULL, 0, switchdev_info,
+				 sizeof(struct sxe2_switchdev_info));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "get switchdev info failed, ret=%d", ret);
+
+	return ret;
+}
+
 int32_t sxe2_drv_dev_info_get(struct sxe2_adapter *adapter,
 				struct sxe2_drv_dev_info_resp *dev_info_resp)
 {
@@ -167,7 +184,11 @@ static int32_t sxe2_rxq_ctxt_cfg_fill(struct sxe2_rx_queue *rxq,
 	req->q_cnt = rxq_cnt;
 	req->max_frame_size = dev_data->mtu + SXE2_ETH_OVERHEAD;
 
-	ctxt->queue_id = rxq->queue_id;
+	if (adapter->is_dev_repr)
+		ctxt->queue_id = adapter->repr_priv_data->repr_q_id;
+	else
+		ctxt->queue_id = rxq->queue_id;
+
 	ctxt->depth = rxq->ring_depth;
 	ctxt->buf_len = RTE_ALIGN(rxq->rx_buf_len, SXE2_RXQ_CTXT_CFG_BUF_LEN_ALIGN);
 	ctxt->dma_addr = rxq->base_addr;
@@ -241,7 +262,10 @@ static void sxe2_txq_ctxt_cfg_fill(struct sxe2_tx_queue *txq,
 		ctxt = &req->cfg[q_idx];
 		ctxt->depth = txq[q_idx].ring_depth;
 		ctxt->dma_addr = txq[q_idx].base_addr;
-		ctxt->queue_id = txq[q_idx].queue_id;
+		if (adapter->is_dev_repr)
+			ctxt->queue_id = adapter->repr_priv_data->repr_q_id;
+		else
+			ctxt->queue_id = txq[q_idx].queue_id;
 
 		ctxt->sched_mode = sxe2_sched_mode_get(adapter);
 	}
@@ -288,7 +312,10 @@ int32_t sxe2_drv_rxq_switch(struct sxe2_adapter *adapter, struct sxe2_rx_queue *
 	struct sxe2_drv_q_switch_req req;
 
 	req.vsi_id = rte_cpu_to_le_16(rxq->vsi->vsi_id);
-	req.q_idx = rxq->queue_id;
+	if (adapter->is_dev_repr)
+		req.q_idx = adapter->repr_priv_data->repr_q_id;
+	else
+		req.q_idx = rxq->queue_id;
 
 	req.is_enable  = (uint8_t)enable;
 	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_RXQ_DISABLE,
@@ -310,7 +337,10 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
 	struct sxe2_drv_q_switch_req req;
 
 	req.vsi_id = rte_cpu_to_le_16(txq->vsi->vsi_id);
-	req.q_idx = txq->queue_id;
+	if (adapter->is_dev_repr)
+		req.q_idx = adapter->repr_priv_data->repr_q_id;
+	else
+		req.q_idx = txq->queue_id;
 
 	req.is_enable  = (uint8_t)enable;
 	req.sched_mode = sxe2_sched_mode_get(adapter);
@@ -326,6 +356,37 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
 	return ret;
 }
 
+int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_drv_vsi_info_get_req vsi_info_get_req = {0};
+	struct sxe2_drv_vsi_info_get_resp vsi_info_get_resp = {0};
+
+	vsi_info_get_req.vsi_id = vsi->vsi_id;
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_VSI_INFO_GET,
+			&vsi_info_get_req, sizeof(vsi_info_get_req),
+			&vsi_info_get_resp, sizeof(vsi_info_get_resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "switchdev cpvsi info get failed, ret=%d", ret);
+		goto l_end;
+	}
+
+	vsi->txqs.q_cnt = vsi_info_get_resp.used_queues.queues_cnt;
+	vsi->txqs.base_idx_in_func = vsi_info_get_resp.used_queues.base_idx_in_pf;
+
+	vsi->rxqs.q_cnt = vsi_info_get_resp.used_queues.queues_cnt;
+	vsi->rxqs.base_idx_in_func = vsi_info_get_resp.used_queues.base_idx_in_pf;
+
+	vsi->irqs.avail_cnt = vsi_info_get_resp.used_msix.msix_vectors_cnt;
+	vsi->irqs.base_idx_in_pf = vsi_info_get_resp.used_msix.base_idx_in_func;
+
+l_end:
+	return ret;
+}
+
 int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter)
 {
 	int32_t ret = 0;
@@ -614,6 +675,101 @@ int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set)
 	return ret;
 }
 
+int32_t sxe2_drv_switchdev_uplink_config(struct sxe2_adapter *adapter,  bool set)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_switchdev_uplink_info switchdev_uplink_info_req = {0};
+
+	switchdev_uplink_info_req.pf_id = adapter->pf_idx;
+	switchdev_uplink_info_req.is_set = set;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_SWITCH_UPLINK,
+				 &switchdev_uplink_info_req,
+				 sizeof(switchdev_uplink_info_req),
+				 NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_WARN(adapter, DRV, "switchdev uplink info config failed, ret=%d", ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_switchdev_repr_vf_config(struct sxe2_adapter *adapter,
+				      struct sxe2_switchdev_repr_info *repr_vf,
+				      bool set)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_switchdev_repr_info switchdev_repr_info_req = {0};
+
+	switchdev_repr_info_req.pf_id = adapter->pf_idx;
+	switchdev_repr_info_req.is_set = set;
+	switchdev_repr_info_req.cp_vsi_id = repr_vf->cp_vsi_id;
+	switchdev_repr_info_req.repr_pf_id = repr_vf->repr_pf_id;
+	switchdev_repr_info_req.repr_vf_id = repr_vf->repr_vf_id;
+	switchdev_repr_info_req.repr_q_id = repr_vf->repr_q_id;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_SWITCH_REPR,
+			&switchdev_repr_info_req,
+			sizeof(switchdev_repr_info_req),
+			NULL, 0);
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_WARN(adapter, DRV, "switchdev repr info config failed, ret=%d", ret);
+
+	return ret;
+}
+
+int32_t sxe2_drv_switchdev_mode_get(struct sxe2_adapter *adapter, bool *is_switchdev)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_switchdev_mode_info switchdev_mode_info_req = {0};
+	struct sxe2_switchdev_mode_info switchdev_mode_info_resp = {0};
+
+	switchdev_mode_info_req.pf_id = adapter->pf_idx;
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_SWITCH_MODE,
+				 &switchdev_mode_info_req,
+				 sizeof(switchdev_mode_info_req),
+				 &switchdev_mode_info_resp,
+				 sizeof(switchdev_mode_info_resp));
+
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_WARN(adapter, DRV, "switchdev mode info get failed, ret=%d", ret);
+	else
+		*is_switchdev = (bool)switchdev_mode_info_resp.is_switchdev;
+
+	return ret;
+}
+
+int32_t sxe2_drv_switchdev_cpvsi_get(struct sxe2_adapter *adapter, uint16_t *cp_vsi_id)
+{
+	int32_t ret = 0;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_switchdev_cpvsi_info switchdev_cpvsi_resp = {0};
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_SWITCH_CPVSI,
+				 NULL, 0,
+				 &switchdev_cpvsi_resp,
+				 sizeof(switchdev_cpvsi_resp));
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_WARN(adapter, DRV, "switchdev cpvsi info get failed, ret=%d", ret);
+	else
+		*cp_vsi_id = switchdev_cpvsi_resp.cp_vsi_id;
+
+	return ret;
+}
+
 int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add)
 {
 	int32_t ret = 0;
@@ -1434,3 +1590,150 @@ int32_t sxe2_drv_mapping_stats_info_clear(struct rte_eth_dev *eth_dev)
 
 	return ret;
 }
+
+int32_t sxe2_drv_flow_filter_add(struct sxe2_adapter *adapter, struct sxe2_flow *flow)
+{
+	struct sxe2_drv_flow_filter_req req = { 0 };
+	struct sxe2_drv_flow_filter_resp resp = { 0 };
+	struct sxe2_drv_cmd_params cmd             = { 0 };
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret                                 = -1;
+
+	memcpy(&req.pattern_inner, &flow->pattern_inner, sizeof(req.pattern_inner));
+	memcpy(&req.pattern_outer, &flow->pattern_outer, sizeof(req.pattern_outer));
+	memcpy(&req.action, &flow->action, sizeof(req.action));
+	memcpy(&req.meta, &flow->meta, sizeof(req.meta));
+	req.engine_type = flow->engine_type;
+	req.flow_id = 0;
+
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FILTER_ADD, &req,
+			   sizeof(req), &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add flow filter, ret: %d.", ret);
+	flow->flow_id = resp.flow_id;
+	flow->create_err = ret;
+	return ret;
+}
+
+int32_t sxe2_drv_flow_filter_del(struct sxe2_adapter *adapter, struct sxe2_flow *flow)
+{
+	struct sxe2_drv_cmd_params cmd             = { 0 };
+	struct sxe2_drv_flow_filter_req req = { 0 };
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret                                 = -1;
+	memcpy(&req.pattern_inner, &flow->pattern_inner, sizeof(req.pattern_inner));
+	memcpy(&req.pattern_outer, &flow->pattern_outer, sizeof(req.pattern_outer));
+	memcpy(&req.action, &flow->action, sizeof(req.action));
+	memcpy(&req.meta, &flow->meta, sizeof(req.meta));
+	req.engine_type = flow->engine_type;
+	req.flow_id = flow->flow_id;
+
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FILTER_DEL, &req,
+			   sizeof(req), NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret)
+		PMD_DEV_LOG_ERR(adapter, DRV,
+			"Failed to delete flow filter, flow id: %u, ret: %d.",
+			flow->flow_id, ret);
+	return ret;
+}
+
+int32_t sxe2_drv_flow_fnav_get_stat_id(struct sxe2_adapter *adapter, uint32_t *stat_id)
+{
+	struct sxe2_drv_flow_fnav_get_stat_id_req req = { 0 };
+	struct sxe2_drv_flow_fnav_get_stat_id_resp resp = { 0 };
+	struct sxe2_drv_cmd_params cmd             = { 0 };
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret                                 = -1;
+
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FNAV_STAT_ALLOC,
+				 &req, sizeof(req),
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get fnav stat id, ret: %d.", ret);
+		goto l_end;
+	}
+	*stat_id = resp.stat_id;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_flow_fnav_free_stat(struct sxe2_adapter *adapter, uint32_t stat_id)
+{
+	struct sxe2_drv_flow_fnav_free_stat_id_req req = { 0 };
+	struct sxe2_drv_cmd_params cmd             = { 0 };
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret                                 = -1;
+
+	req.stat_id = stat_id;
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FNAV_STAT_FREE,
+				 &req, sizeof(req),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to free fnav stat id, ret: %d.", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_flow_fnav_query_stat(struct sxe2_adapter *adapter,
+		struct sxe2_fnav_cid_mgr *mgr)
+{
+	struct sxe2_drv_flow_fnav_query_stat_req req = { 0 };
+	struct sxe2_drv_flow_fnav_query_stat_resp resp = { 0 };
+	struct sxe2_drv_cmd_params cmd             = { 0 };
+	struct sxe2_common_device *cdev = adapter->cdev;
+	int32_t ret                                 = -1;
+
+	req.stat_id = mgr->stat_index;
+	req.stat_ctrl = mgr->count_type;
+	req.is_clear = 1;
+
+	sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FNAV_STAT_QUERY,
+				 &req, sizeof(req),
+				 &resp, sizeof(resp));
+	ret = sxe2_drv_cmd_exec(cdev, &cmd);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV,
+			"Failed to query fnav stat, stat id: %u, ret: %d.",
+			req.stat_id, ret);
+		goto l_end;
+	}
+	mgr->hits += resp.stat_hits;
+	mgr->bytes += resp.stat_bytes;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_drv_srcvsi_prune_config(struct sxe2_adapter *adapter,
+			uint16_t *vsi_list, uint16_t vsi_cnt, bool set)
+{
+	int32_t ret = 0;
+	uint16_t idx;
+	struct sxe2_common_device *cdev = adapter->cdev;
+	struct sxe2_drv_cmd_params param = {0};
+	struct sxe2_srcvsi_ext_cfg_req srcvsi_list_prune_cfg_req = {0};
+
+	srcvsi_list_prune_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+	srcvsi_list_prune_cfg_req.is_add = set;
+	srcvsi_list_prune_cfg_req.srcvsi_cnt = vsi_cnt;
+	for (idx = 0; idx < vsi_cnt; idx++)
+		srcvsi_list_prune_cfg_req.srcvsi_list[idx] = vsi_list[idx];
+
+	sxe2_drv_cmd_params_fill(adapter, &param, SXE2_DRV_CMD_VSI_SRCVSI_PRUNE,
+				 &srcvsi_list_prune_cfg_req,
+				 sizeof(srcvsi_list_prune_cfg_req),
+				 NULL, 0);
+	ret = sxe2_drv_cmd_exec(cdev, &param);
+	if (ret)
+		PMD_DEV_LOG_WARN(adapter, DRV, "srcvsi prune config 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 3eb30078e1..52cd9922ad 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -12,6 +12,9 @@
 int32_t sxe2_drv_dev_caps_get(struct sxe2_adapter *adapter,
 		struct sxe2_drv_dev_caps_resp *dev_caps);
 
+int32_t sxe2_drv_switchdev_info_get(struct sxe2_adapter *adapter,
+		struct sxe2_switchdev_info *switchdev_info);
+
 int32_t sxe2_drv_dev_info_get(struct sxe2_adapter *adapter,
 		struct sxe2_drv_dev_info_resp *dev_info_resp);
 
@@ -64,6 +67,8 @@ 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_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi);
+
 int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
 
 int32_t sxe2_drv_get_mac_stats(struct sxe2_adapter *adapter);
@@ -91,6 +96,15 @@ 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);
 
+int32_t sxe2_drv_switchdev_uplink_config(struct sxe2_adapter *adapter,  bool set);
+
+int32_t sxe2_drv_switchdev_repr_vf_config(struct sxe2_adapter *adapter,
+				struct sxe2_switchdev_repr_info *repr_vf, bool set);
+
+int32_t sxe2_drv_switchdev_cpvsi_get(struct sxe2_adapter *adapter, uint16_t *cp_vsi_id);
+
+int32_t sxe2_drv_switchdev_mode_get(struct sxe2_adapter *adapter, bool *is_switchdev);
+
 int32_t sxe2_drv_mc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
 
 int32_t sxe2_drv_vlan_config_query(struct sxe2_adapter *adapter);
@@ -122,4 +136,18 @@ int32_t sxe2_drv_rxq_bind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx, ui
 
 int32_t sxe2_drv_rxq_unbind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx);
 
+int32_t sxe2_drv_flow_filter_add(struct sxe2_adapter *adapter, struct sxe2_flow *flow);
+
+int32_t sxe2_drv_flow_filter_del(struct sxe2_adapter *adapter, struct sxe2_flow *flow);
+
+int32_t sxe2_drv_flow_fnav_get_stat_id(struct sxe2_adapter *adapter, uint32_t *stat_id);
+
+int32_t sxe2_drv_flow_fnav_free_stat(struct sxe2_adapter *adapter, uint32_t stat_id);
+
+int32_t sxe2_drv_flow_fnav_query_stat(struct sxe2_adapter *adapter,
+		struct sxe2_fnav_cid_mgr *mgr);
+
+int32_t sxe2_drv_srcvsi_prune_config(struct sxe2_adapter *adapter,
+		uint16_t *vsi_list, uint16_t vsi_cnt, bool set);
+
 #endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 576aa0e728..9db8cb1ad1 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -108,7 +108,6 @@ enum sxe2_phys_port_name_type {
 	SXE2_PHYS_PORT_NAME_TYPE_LEGACY,
 	SXE2_PHYS_PORT_NAME_TYPE_UPLINK,
 	SXE2_PHYS_PORT_NAME_TYPE_PFVF,
-
 	SXE2_PHYS_PORT_NAME_TYPE_UNKNOWN,
 };
 
@@ -564,6 +563,60 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_queue_irq_bind_req {
 	uint8_t rsv[2];
 } __rte_packed_end;
 
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_uplink_info {
+	uint8_t pf_id;
+	uint8_t is_set;
+	uint8_t rsv[2];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_repr_info {
+	uint8_t pf_id;
+	uint8_t is_set;
+	uint8_t rsv[2];
+	uint16_t cp_vsi_id;
+	uint16_t repr_pf_id;
+	uint16_t repr_vf_id;
+	uint16_t repr_q_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_filter_req {
+	uint32_t flow_id;
+	struct sxe2_flow_meta meta;
+	enum sxe2_flow_engine_type engine_type;
+	struct sxe2_flow_pattern pattern_outer;
+	struct sxe2_flow_pattern pattern_inner;
+	struct sxe2_flow_action action;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_filter_resp {
+	enum sxe2_flow_engine_type engine_type;
+	uint32_t flow_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_get_stat_id_req {
+	uint8_t need_update;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_get_stat_id_resp {
+	uint32_t stat_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_free_stat_id_req {
+	uint32_t stat_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_query_stat_req {
+	uint32_t stat_id;
+	uint32_t stat_ctrl;
+	uint32_t is_clear;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_query_stat_resp {
+	uint32_t stat_index;
+	uint64_t stat_hits;
+	uint64_t stat_bytes;
+} __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 f3fee74ddf..317101fb60 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -33,9 +33,13 @@
 #include "sxe2_ptype.h"
 #include "sxe2_common_log.h"
 #include "sxe2_mp.h"
+#include "sxe2_flow.h"
 #include "sxe2_stats.h"
 #include "sxe2_host_regs.h"
+#include "sxe2_switchdev.h"
 #include "sxe2_ioctl_chnl_func.h"
+#include "sxe2_ethdev_repr.h"
+#include "sxe2vf_regs.h"
 
 #define SXE2_PCI_VENDOR_ID_1    0x1ff2
 #define SXE2_PCI_DEVICE_ID_PF_1 0x10b1
@@ -83,6 +87,27 @@ static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_pf[SXE2_PCI_MAP_RES_
 				      .reg_width = 10},
 };
 
+static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_vf[SXE2_PCI_MAP_RES_MAX_COUNT] = {
+	[SXE2_PCI_MAP_RES_INVALID]  = {.addr_base = 0,
+				      .bar_idx = 0,
+				      .reg_width = 0},
+	[SXE2_PCI_MAP_RES_DOORBELL_TX] = {.addr_base = SXE2VF_TXQ_TAIL(0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL] = {.addr_base = SXE2VF_RXQ_TAIL(0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_IRQ_DYN] = {.addr_base = SXE2VF_VF_DYN_CTL(0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_IRQ_ITR] = {.addr_base = SXE2VF_VF_INT_ITR(0, 0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_IRQ_MSIX] = {.addr_base = SXE2VF_BAR4_MSIX_CTL(0),
+				      .bar_idx = 4,
+				      .reg_width = 0x10},
+};
+
 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);
@@ -137,6 +162,7 @@ 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,
 
+	.flow_ops_get               = sxe2_flow_ops_get,
 	.tm_ops_get                 = sxe2_tm_ops_get,
 
 	.stats_get                  = sxe2_stats_info_get,
@@ -566,7 +592,7 @@ static int32_t sxe2_eth_init(struct rte_eth_dev *dev)
 	return ret;
 }
 
-static void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused)
+void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused)
 {
 	sxe2_mac_addr_uinit(dev);
 	(void)sxe2_filter_uinit(dev);
@@ -607,6 +633,16 @@ static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
 		adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_FC_STATE;
 }
 
+static void sxe2_sw_representor_ctx_hw_cap_set(struct sxe2_adapter *adapter,
+			struct sxe2_drv_representor_caps *repr_caps)
+{
+	adapter->repr_ctxt.nb_vf = repr_caps->cnt_repr_vf;
+	if (adapter->repr_ctxt.nb_vf > 0) {
+		memcpy(adapter->repr_ctxt.repr_vf_id, repr_caps->repr_vf_id,
+			adapter->repr_ctxt.nb_vf * sizeof(struct sxe2_drv_vsi_caps));
+	}
+}
+
 static void sxe2_sw_sched_hw_cap_set(struct sxe2_adapter *adapter,
 				     struct sxe2_txsch_caps *txsch_caps)
 {
@@ -636,20 +672,47 @@ 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_representor_ctx_hw_cap_set(adapter, &dev_caps.repr_caps);
+
 	sxe2_sw_sched_hw_cap_set(adapter, &dev_caps.txsch_caps);
 
 l_end:
 	return ret;
 }
 
+static int32_t sxe2_switchdev_info_get(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	struct sxe2_switchdev_info switchdev_info = {0};
+
+	ret = sxe2_drv_switchdev_info_get(adapter, &switchdev_info);
+	if (ret)
+		goto l_end;
+	if (switchdev_info.master && switchdev_info.representor) {
+		PMD_LOG_ERR(INIT, "device could not be both master and representor");
+		ret = -ENODEV;
+		goto l_end;
+	}
+	adapter->switchdev_info = switchdev_info;
+l_end:
+	return ret;
+}
+
 static int32_t sxe2_dev_caps_get(struct sxe2_adapter *adapter)
 {
 	int32_t ret = -1;
 
 	ret = sxe2_func_caps_get(adapter);
-	if (ret)
+	if (ret) {
 		PMD_LOG_ERR(INIT, "get function caps failed, ret=%d", ret);
+		goto l_end;
+	}
+
+	ret = sxe2_switchdev_info_get(adapter);
+	if (ret)
+		PMD_LOG_ERR(INIT, "get switchdev info failed, ret=%d", ret);
 
+l_end:
 	return ret;
 }
 
@@ -935,7 +998,10 @@ int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev)
 	bar_info[1].seg_info = seg_info;
 	map_ctxt->bar_info = bar_info;
 
-	map_ctxt->addr_info = sxe2_net_map_addr_info_pf;
+	if (adapter->dev_type == SXE2_DEV_T_VF)
+		map_ctxt->addr_info = sxe2_net_map_addr_info_vf;
+	else
+		map_ctxt->addr_info = sxe2_net_map_addr_info_pf;
 
 	ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX,
 				       txq_cnt, txq_base);
@@ -1138,6 +1204,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_dev_info_err;
 	}
 
+	ret = sxe2_switchdev_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize switchdev mode, ret=[%d]", ret);
+		goto init_switchdev_err;
+	}
+
 	ret = sxe2_sw_init(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret);
@@ -1168,6 +1240,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto init_rss_err;
 	}
 
+	ret = sxe2_flow_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to init flow, ret=%d", ret);
+		goto init_flow_err;
+	}
+
 	ret = sxe2_sched_init(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "Failed to init sched, ret=%d", ret);
@@ -1191,15 +1269,19 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 init_xstats_err:
 	(void)sxe2_sched_uinit(dev);
 init_sched_err:
+	(void)sxe2_flow_uninit(dev);
+init_flow_err:
 init_rss_err:
 	sxe2_security_uinit(dev);
 init_security_err:
+	sxe2_eth_uinit(dev);
+init_eth_err:
 	sxe2_intr_uninit(dev);
 init_irq_err:
 	sxe2_sw_uninit(dev);
 init_sw_err:
-	sxe2_eth_uinit(dev);
-init_eth_err:
+	(void)sxe2_switchdev_uninit(dev);
+init_switchdev_err:
 init_dev_info_err:
 	sxe2_vsi_uninit(dev);
 init_vsi_err:
@@ -1214,6 +1296,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 		sxe2_mp_uninit(dev);
 		goto l_end;
 	}
+	sxe2_repr_all_close(dev);
 	(void)sxe2_dev_stop(dev);
 	(void)sxe2_queues_release(dev);
 	sxe2_mp_uninit(dev);
@@ -1222,6 +1305,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 	sxe2_vsi_uninit(dev);
 	sxe2_security_uinit(dev);
 	sxe2_intr_uninit(dev);
+	(void)sxe2_switchdev_uninit(dev);
 	sxe2_sw_uninit(dev);
 	sxe2_eth_uinit(dev);
 	sxe2_dev_pci_map_uinit(dev);
@@ -1233,10 +1317,29 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 static int32_t sxe2_dev_uninit(struct rte_eth_dev *dev)
 {
 	int32_t ret = 0;
+	int32_t i = 0;
+	struct sxe2_adapter *adapter = NULL;
+	struct rte_eth_dev *rep_dev = NULL;
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		goto l_end;
 
+	adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	for (i = 0; i < adapter->repr_ctxt.nb_repr_vf; i++) {
+		rep_dev = adapter->repr_ctxt.vf_rep_eth_dev[i];
+		if (rep_dev) {
+			ret = rep_dev->dev_ops->dev_close(rep_dev);
+			if (ret)
+				goto l_end;
+			if (rep_dev->intr_handle)
+				rte_intr_instance_free(rep_dev->intr_handle);
+			ret = rte_eth_dev_release_port(rep_dev);
+			if (ret)
+				goto l_end;
+			adapter->repr_ctxt.vf_rep_eth_dev[i] = NULL;
+		}
+	}
+
 	ret = sxe2_dev_close(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "Sxe2 dev close failed, ret=%d", ret);
@@ -1270,6 +1373,65 @@ static int32_t sxe2_eth_pmd_remove(struct sxe2_common_device *cdev)
 	return ret;
 }
 
+static uint16_t sxe2_switchdev_repr_id_encode_get(struct sxe2_switchdev_info *switchdev_info)
+{
+	enum rte_eth_representor_type type;
+	uint16_t repr = switchdev_info->vf_num;
+	uint32_t pf = switchdev_info->pf_num;
+
+	switch (switchdev_info->port_name_type) {
+	case SXE2_PHYS_PORT_NAME_TYPE_UPLINK:
+		if (!switchdev_info->representor)
+			return UINT16_MAX;
+		type = RTE_ETH_REPRESENTOR_PF;
+		pf = switchdev_info->mpesw_owner;
+		break;
+	case SXE2_PHYS_PORT_NAME_TYPE_PFVF:
+	default:
+		type = RTE_ETH_REPRESENTOR_VF;
+		break;
+	}
+
+	return SXE2_REPRESENTOR_ID(pf, type, repr);
+}
+
+static bool sxe2_switchdev_repr_match(struct sxe2_adapter *adapter,
+				   struct rte_eth_devargs *req_eth_da)
+{
+	uint32_t port_idx = 0;
+	uint32_t repr_idx;
+	uint16_t kernel_repr_id = sxe2_switchdev_repr_id_encode_get(&adapter->switchdev_info);
+	uint16_t repr_id;
+
+	switch (req_eth_da->type) {
+	case RTE_ETH_REPRESENTOR_PF:
+		break;
+	case RTE_ETH_REPRESENTOR_VF:
+		if (adapter->switchdev_info.port_name_type !=
+		SXE2_PHYS_PORT_NAME_TYPE_PFVF) {
+			rte_errno = EBUSY;
+			return false;
+		}
+		break;
+	case RTE_ETH_REPRESENTOR_NONE:
+		rte_errno = EBUSY;
+		return false;
+	default:
+		rte_errno = ENOTSUP;
+		return false;
+	}
+
+	for (repr_idx = 0; repr_idx < req_eth_da->nb_representor_ports; ++repr_idx) {
+		repr_id = SXE2_REPRESENTOR_ID(req_eth_da->ports[port_idx],
+					      req_eth_da->type,
+					      req_eth_da->representor_ports[repr_idx]);
+		if (repr_id == kernel_repr_id)
+			return true;
+	}
+	rte_errno = EBUSY;
+	return false;
+}
+
 static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev,
 		struct rte_eth_devargs *req_eth_da __rte_unused,
 		uint16_t owner_id __rte_unused,
@@ -1311,10 +1473,34 @@ static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev,
 		goto l_release_port;
 	}
 
+	if (req_eth_da->nb_representor_ports > 0) {
+		if (!adapter->switchdev_info.is_switchdev) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Representor requested but Switchdev not enabled");
+			ret = -ENOTSUP;
+			goto l_dev_uinit;
+		}
+
+		if (!sxe2_switchdev_repr_match(adapter, req_eth_da)) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Representor parameters mismatch");
+			ret = -ENOTSUP;
+			goto l_dev_uinit;
+		}
+
+		ret = sxe2_switchdev_repr_devs_init(adapter, req_eth_da);
+		if (ret) {
+			PMD_DEV_LOG_ERR(adapter, INIT, "Failed to init representor, ret=%d", ret);
+			goto l_dev_uinit;
+		}
+	} else {
+		PMD_DEV_LOG_DEBUG(adapter, INIT, "No representors requested, skipping.");
+	}
+
 	rte_eth_dev_probing_finish(eth_dev);
 	PMD_DEV_LOG_DEBUG(adapter, INIT, "Sxe2 eth pmd probe successful!");
 	goto l_end;
 
+l_dev_uinit:
+	(void)sxe2_dev_uninit(eth_dev);
 l_release_port:
 	(void)rte_eth_dev_release_port(eth_dev);
 l_end:
@@ -1384,6 +1570,11 @@ static struct sxe2_class_driver sxe2_eth_pmd = {
 	.intr_rmv = 1,
 };
 
+bool sxe2_ethdev_check(struct rte_eth_dev *dev)
+{
+	return !strcmp(dev->device->driver->name, "sxe2_pci");
+}
+
 RTE_INIT(rte_sxe2_pmd_init)
 {
 	sxe2_common_init();
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 8dcff8af37..ca4e23f5a8 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -65,6 +65,9 @@ enum sxe2_fnav_tunnel_flag_type {
 #define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
 #define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
 
+#define SXE2_REPRESENTOR_ID(pf, type, repr) \
+		(((pf) << 14) + ((type) << 12) + ((repr) & 0xfff))
+
 #define SXE2_I2C_EEPROM_DEV_ADDR	0xA0
 #define SXE2_I2C_EEPROM_DEV_ADDR2	0xA2
 #define SXE2_MODULE_TYPE_SFP		0x03
@@ -310,16 +313,20 @@ struct sxe2_adapter {
 	struct sxe2_vsi_context       vsi_ctxt;
 	struct sxe2_filter_context    filter_ctxt;
 	struct sxe2_rss_context       rss_ctxt;
+	struct sxe2_flow_context      flow_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_security_ctx      security_ctx;
+	struct sxe2_repr_context      repr_ctxt;
 	struct sxe2_switchdev_info    switchdev_info;
 	bool                          rule_started;
 	bool                          flow_isolated;
+	bool                          flow_isolate_cfg;
 	uint16_t                           dev_port_id;
+	bool                          is_dev_repr;
 	uint64_t                           cap_flags;
 	enum sxe2_dev_type            dev_type;
 	uint32_t    ptype_tbl[SXE2_MAX_PTYPE_NUM];
@@ -341,6 +348,8 @@ void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter,
 			    enum sxe2_pci_map_resource res_type,
 			    uint16_t idx_in_func);
 
+bool sxe2_ethdev_check(struct rte_eth_dev *dev);
+
 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,
@@ -367,6 +376,8 @@ int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
 
 void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
 
+void sxe2_eth_uinit(struct rte_eth_dev *dev);
+
 static inline bool
 sxe2_dev_port_vlan_check(struct rte_eth_dev *dev)
 {
diff --git a/drivers/net/sxe2/sxe2_ethdev_repr.c b/drivers/net/sxe2/sxe2_ethdev_repr.c
new file mode 100644
index 0000000000..a43991c379
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.c
@@ -0,0 +1,607 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_ethdev_repr.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_common.h"
+#include "sxe2_common_log.h"
+#include "sxe2_tx.h"
+#include "sxe2_rx.h"
+#include "sxe2_txrx.h"
+#include "sxe2_switchdev.h"
+#include "sxe2_ptype.h"
+#include "sxe2_mp.h"
+#include "sxe2_stats.h"
+#include "sxe2_flow.h"
+
+static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_repr[SXE2_PCI_MAP_RES_MAX_COUNT] = {
+	{0, 0, 0},
+	{ SXE2_TXQ_LEGACY_DBLL(0), 0, 4},
+	{ SXE2_RXQ_TAIL(0), 0, 4},
+	{ SXE2_VF_DYN_CTL(0), 0, 4},
+	{ SXE2_VF_INT_ITR(0, 0), 0, 4},
+	{ SXE2_BAR4_MSIX_CTL(0), 4, 0x10},
+};
+
+static void sxe2_repr_dev_uinit(struct rte_eth_dev *dev);
+
+static int32_t sxe2_repr_promisc_enable(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+static int32_t sxe2_repr_promisc_disable(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+static int32_t sxe2_repr_allmulti_enable(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+static int32_t sxe2_repr_allmulti_disable(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static int32_t sxe2_repr_dev_configure(struct rte_eth_dev *dev)
+{
+	dev->data->mtu = SXE2_FRAME_SIZE_MAX - SXE2_ETH_OVERHEAD;
+	return 0;
+}
+
+static int32_t sxe2_repr_dev_start(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	PMD_INIT_FUNC_TRACE();
+
+	ret = sxe2_queues_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to init queues.");
+		goto l_end;
+	}
+
+	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_repr_rxq_intr_enable(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to enable rx queue intr");
+		goto l_end;
+	}
+
+	ret = sxe2_queues_start(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "enable queues failed");
+		goto l_start_queues_err;
+	}
+
+	dev->data->dev_started = 1;
+	adapter->started = 1;
+	goto l_end;
+l_start_queues_err:
+	(void)sxe2_rxq_intr_disable(dev);
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_repr_dev_stop(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	PMD_INIT_FUNC_TRACE();
+
+	if (adapter->started == 0)
+		goto l_end;
+
+	sxe2_repr_rxq_intr_disable(dev);
+
+	sxe2_txqs_all_stop(dev);
+	sxe2_rxqs_all_stop(dev);
+
+	dev->data->dev_started = 0;
+	adapter->started = 0;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_repr_dev_close(struct rte_eth_dev *dev)
+{
+	PMD_DEV_LOG_INFO(SXE2_DEV_PRIVATE_TO_ADAPTER(dev),
+			 INIT, "repr close");
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		sxe2_mp_uninit(dev);
+		goto l_end;
+	}
+	(void)sxe2_repr_dev_stop(dev);
+	(void)sxe2_queues_release(dev);
+	sxe2_mp_uninit(dev);
+	sxe2_repr_dev_uinit(dev);
+l_end:
+	return 0;
+}
+
+static int32_t sxe2_repr_dev_infos_get(struct rte_eth_dev *dev,
+			struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_rx_queues = 1;
+	dev_info->max_tx_queues = 1;
+	dev_info->min_rx_bufsize = SXE2_MIN_BUF_SIZE;
+	dev_info->max_rx_pktlen = SXE2_FRAME_SIZE_MAX;
+	dev_info->max_lro_pkt_size = SXE2_FRAME_SIZE_MAX * SXE2_RX_LRO_DESC_MAX_NUM;
+	dev_info->max_mtu = dev_info->max_rx_pktlen - SXE2_ETH_OVERHEAD;
+	dev_info->min_mtu = RTE_ETHER_MIN_MTU;
+	dev_info->max_mac_addrs = SXE2_NUM_MACADDR_MAX;
+
+	dev_info->rx_offload_capa =
+		RTE_ETH_RX_OFFLOAD_KEEP_CRC |
+		RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
+		RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
+		RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
+		RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
+		RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM;
+	dev_info->tx_offload_capa =
+		RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+		RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+		RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+		RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+		RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+		RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
+	dev_info->tx_queue_offload_capa = RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
+
+	dev_info->default_rxconf = (struct rte_eth_rxconf) {
+		.rx_thresh = {
+			.pthresh = SXE2_DEFAULT_RX_PTHRESH,
+			.hthresh = SXE2_DEFAULT_RX_HTHRESH,
+			.wthresh = SXE2_DEFAULT_RX_WTHRESH,
+		},
+		.rx_free_thresh = SXE2_DEFAULT_RX_FREE_THRESH,
+		.rx_drop_en = 0,
+		.offloads = 0,
+	};
+
+	dev_info->default_txconf = (struct rte_eth_txconf) {
+		.tx_thresh = {
+			.pthresh = SXE2_DEFAULT_TX_PTHRESH,
+			.hthresh = SXE2_DEFAULT_TX_HTHRESH,
+			.wthresh = SXE2_DEFAULT_TX_WTHRESH,
+		},
+		.tx_free_thresh = SXE2_DEFAULT_TX_FREE_THRESH,
+		.tx_rs_thresh = SXE2_DEFAULT_TX_RSBIT_THRESH,
+		.offloads = 0,
+	};
+
+	dev_info->rx_desc_lim = (struct rte_eth_desc_lim) {
+		.nb_max = SXE2_MAX_RING_DESC,
+		.nb_min = SXE2_MIN_RING_DESC,
+		.nb_align = SXE2_ALIGN,
+	};
+
+	dev_info->tx_desc_lim = (struct rte_eth_desc_lim) {
+		.nb_max = SXE2_MAX_RING_DESC,
+		.nb_min = SXE2_MIN_RING_DESC,
+		.nb_align = SXE2_ALIGN,
+		.nb_mtu_seg_max = SXE2_TX_MTU_SEG_MAX,
+		.nb_seg_max = SXE2_MAX_RING_DESC,
+	};
+
+	dev_info->speed_capa = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_25G |
+			 RTE_ETH_LINK_SPEED_50G | RTE_ETH_LINK_SPEED_100G;
+
+	dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+	dev_info->nb_tx_queues = dev->data->nb_tx_queues;
+
+	dev_info->default_rxportconf.burst_size = SXE2_RX_MAX_BURST;
+	dev_info->default_txportconf.burst_size = SXE2_TX_MAX_BURST;
+	dev_info->default_rxportconf.nb_queues = 1;
+	dev_info->default_txportconf.nb_queues = 1;
+	dev_info->default_rxportconf.ring_size = SXE2_RING_SIZE_MIN;
+	dev_info->default_txportconf.ring_size = SXE2_RING_SIZE_MIN;
+
+	dev_info->rx_seg_capa.offset_allowed = false;
+
+	dev_info->rx_seg_capa.offset_align_log2 = false;
+
+	return 0;
+}
+
+static const struct eth_dev_ops sxe2_switchdev_repr_dev_ops = {
+	.dev_configure              = sxe2_repr_dev_configure,
+
+	.dev_start                  = sxe2_repr_dev_start,
+	.dev_stop                   = sxe2_repr_dev_stop,
+
+	.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,
+
+	.dev_close                  = sxe2_repr_dev_close,
+	.dev_infos_get              = sxe2_repr_dev_infos_get,
+	.dev_supported_ptypes_get   = sxe2_dev_supported_ptypes_get,
+	.link_update                = sxe2_link_update,
+
+	.promiscuous_enable         = sxe2_repr_promisc_enable,
+	.promiscuous_disable        = sxe2_repr_promisc_disable,
+	.allmulticast_enable        = sxe2_repr_allmulti_enable,
+	.allmulticast_disable       = sxe2_repr_allmulti_disable,
+
+	.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,
+};
+
+void sxe2_repr_all_close(struct rte_eth_dev *dev)
+{
+	uint16_t vf_id;
+	struct rte_eth_dev *repr_eth_dev = NULL;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (adapter->repr_ctxt.nb_repr_vf) {
+		for (vf_id = 0; vf_id < adapter->repr_ctxt.nb_repr_vf; vf_id++) {
+			repr_eth_dev = adapter->repr_ctxt.vf_rep_eth_dev[vf_id];
+			if (!repr_eth_dev || repr_eth_dev->data->dev_started == 0)
+				continue;
+
+			(void)rte_eth_dev_stop(repr_eth_dev->data->port_id);
+			(void)rte_eth_dev_close(repr_eth_dev->data->port_id);
+		}
+	}
+}
+
+static void sxe2_repr_adapter_init(struct rte_eth_dev *dev_repr,
+				   struct sxe2_adapter *parent_adapter,
+				   uint16_t repr_id)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev_repr);
+
+	dev_repr->data->backer_port_id = parent_adapter->dev_port_id;
+	dev_repr->data->representor_id = repr_id;
+	dev_repr->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
+
+	adapter->is_dev_repr = true;
+	adapter->dev_port_id = dev_repr->data->port_id;
+	adapter->dev_type = parent_adapter->dev_type;
+	adapter->switchdev_info.is_switchdev = parent_adapter->switchdev_info.is_switchdev;
+	adapter->port_idx = parent_adapter->port_idx;
+	adapter->pf_idx = parent_adapter->pf_idx;
+	adapter->dev_info.pci = parent_adapter->dev_info.pci;
+	adapter->dev_info.fw = parent_adapter->dev_info.fw;
+}
+
+static int32_t sxe2_repr_eth_init(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+
+	ret = sxe2_filter_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize l2 filter, ret:%d", ret);
+		goto l_end;
+	}
+	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_mac_addr_init(dev);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to initialize mac address, ret:%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_repr_dev_pci_map_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *rep_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_pci_map_context *map_ctxt = &rep_adapter->map_ctxt;
+	struct sxe2_pci_map_bar_info *bar_info = NULL;
+	struct sxe2_pci_map_segment_info *seg_info = NULL;
+	uint16_t txq_cnt = rep_adapter->q_ctxt.qp_cnt_assign;
+	uint16_t txq_base = rep_adapter->q_ctxt.base_idx_in_pf;
+	uint16_t rxq_cnt = rep_adapter->q_ctxt.qp_cnt_assign;
+	uint16_t rxq_base = rep_adapter->q_ctxt.base_idx_in_pf;
+	uint16_t irq_cnt = rep_adapter->irq_ctxt.max_cnt_hw;
+	uint16_t irq_base = rep_adapter->irq_ctxt.base_idx_in_func;
+	int32_t ret = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	rep_adapter->dev_info.dev_data = dev->data;
+
+	map_ctxt->bar_cnt = 2;
+
+	bar_info = rte_zmalloc("repr_bar_info",
+			sizeof(struct sxe2_pci_map_bar_info) * map_ctxt->bar_cnt, 0);
+	if (bar_info == NULL) {
+		PMD_LOG_ERR(INIT, "Failed to alloc bar_info");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	bar_info[0].bar_idx = 0;
+	bar_info[0].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT;
+	seg_info = rte_zmalloc("repr_seg_info_bar0",
+			sizeof(struct sxe2_pci_map_segment_info) * bar_info[0].map_cnt, 0);
+	if (seg_info == NULL) {
+		PMD_LOG_ERR(INIT, "Failed to alloc seg_info");
+		ret = -ENOMEM;
+		goto l_free_bar;
+	}
+
+	bar_info[0].seg_info = seg_info;
+
+	bar_info[1].bar_idx = 4;
+	bar_info[1].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT;
+	seg_info = rte_zmalloc("repr_seg_info_bar4",
+			sizeof(struct sxe2_pci_map_segment_info) * bar_info[1].map_cnt,
+			0);
+	if (!seg_info) {
+		PMD_LOG_ERR(INIT, "Failed to alloc seg_info");
+		ret = -ENOMEM;
+		goto l_free_seg0;
+	}
+
+	bar_info[1].seg_info = seg_info;
+	map_ctxt->bar_info = bar_info;
+
+	map_ctxt->addr_info = sxe2_net_map_addr_info_repr;
+
+	ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_TX,
+			txq_cnt, txq_base);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to map txq doorbell addr, ret=%d", ret);
+		goto l_free_seg1;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL,
+			rxq_cnt, rxq_base);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to map rxq tail doorbell addr, ret=%d", ret);
+		goto l_free_txq;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_IRQ_DYN,
+			irq_cnt, irq_base);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to map irq dyn addr, ret=%d", ret);
+		goto l_free_rxq_tail;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_IRQ_ITR,
+			irq_cnt, irq_base);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to map irq itr addr, ret=%d", ret);
+		goto l_free_irq_dyn;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_IRQ_MSIX,
+			irq_cnt, irq_base);
+	if (ret != 0) {
+		PMD_LOG_ERR(INIT, "Failed to map irq msix addr, ret=%d", ret);
+		goto l_free_irq_itr;
+	}
+	goto l_end;
+
+l_free_irq_itr:
+	(void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_IRQ_ITR);
+l_free_irq_dyn:
+	(void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_IRQ_DYN);
+l_free_rxq_tail:
+	(void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL);
+l_free_txq:
+	(void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_TX);
+l_free_seg1:
+	if (bar_info[1].seg_info) {
+		rte_free(bar_info[1].seg_info);
+		bar_info[1].seg_info = NULL;
+	}
+l_free_seg0:
+	if (bar_info[0].seg_info) {
+		rte_free(bar_info[0].seg_info);
+		bar_info[0].seg_info = NULL;
+	}
+l_free_bar:
+	if (bar_info) {
+		rte_free(bar_info);
+		bar_info = NULL;
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_repr_dev_init(struct rte_eth_dev *dev,
+			   struct sxe2_adapter *parent_adapter,
+			   uint16_t repr_id)
+{
+	int32_t ret = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	sxe2_set_common_function(dev);
+
+	sxe2_repr_adapter_init(dev, parent_adapter, repr_id);
+
+	dev->dev_ops = &sxe2_switchdev_repr_dev_ops;
+
+	ret = sxe2_vsi_repr_main_vsi_create(dev, parent_adapter, repr_id);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to create representor main vsi, ret=[%d]", ret);
+		goto l_end;
+	}
+
+	ret = sxe2_switchdev_repr_private_data_init(dev, parent_adapter, repr_id);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to fill representor private data, ret=[%d]", ret);
+		goto l_init_priv_data_err;
+	}
+
+	ret = sxe2_repr_dev_pci_map_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to pci addr map, ret=[%d]", ret);
+		goto l_init_pci_error;
+	}
+
+	ret = sxe2_switchdev_dev_info_init(dev, parent_adapter);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to get device info, ret=[%d]", ret);
+		goto l_init_dev_info_err;
+	}
+
+	ret = sxe2_flow_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to init flow, ret=%d", ret);
+		goto l_init_flow_err;
+	}
+
+	ret = sxe2_repr_eth_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to init device, status = %d", ret);
+		goto l_init_eth_err;
+	}
+
+	ret = sxe2_sw_irq_ctxt_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret);
+		goto l_init_sw_err;
+	}
+
+	goto l_end;
+
+l_init_sw_err:
+	sxe2_eth_uinit(dev);
+l_init_eth_err:
+	(void)sxe2_flow_uninit(dev);
+l_init_flow_err:
+l_init_dev_info_err:
+	sxe2_dev_pci_map_uinit(dev);
+l_init_pci_error:
+	(void)sxe2_switchdev_uninit(dev);
+l_init_priv_data_err:
+	sxe2_vsi_repr_main_vsi_destroy(dev);
+l_end:
+	return ret;
+}
+
+static void sxe2_repr_dev_uinit(struct rte_eth_dev *dev)
+{
+	sxe2_eth_uinit(dev);
+	(void)sxe2_flow_uninit(dev);
+	sxe2_dev_pci_map_uinit(dev);
+	(void)sxe2_switchdev_uninit(dev);
+	sxe2_vsi_repr_main_vsi_destroy(dev);
+}
+
+int32_t sxe2_switchdev_repr_devs_init(struct sxe2_adapter *adapter,
+				  struct rte_eth_devargs *req_eth_da)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+	int32_t ret;
+	uint16_t repr_idx = 0, tmp_repr_idx = 0;
+	char name[RTE_ETH_NAME_MAX_LEN];
+
+	if (req_eth_da->nb_representor_ports == 0) {
+		ret = 0;
+		goto l_end;
+	}
+
+	if (req_eth_da->nb_representor_ports > adapter->repr_ctxt.nb_vf) {
+		PMD_LOG_ERR(INIT, "Failed to create repr vsi, nb_representor_ports=%d, nb_vf=%d",
+			    req_eth_da->nb_representor_ports, adapter->repr_ctxt.nb_vf);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_other_vsi_create(adapter, req_eth_da->nb_representor_ports);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to create representor vsi, ret=%d", ret);
+		goto l_release_port;
+	}
+
+	adapter->repr_ctxt.vf_rep_eth_dev = rte_zmalloc("sxe2_repr_ethdev",
+			req_eth_da->nb_representor_ports * sizeof(struct rte_eth_dev *), 0);
+	if (adapter->repr_ctxt.vf_rep_eth_dev == NULL) {
+		PMD_LOG_ERR(INIT, "Failed to malloc representor eth dev.");
+		ret = -ENOMEM;
+		goto l_release_port;
+	}
+
+	for (repr_idx = 0; repr_idx < req_eth_da->nb_representor_ports; ++repr_idx) {
+		snprintf(name, sizeof(name), "sxe2_representor_c%dpf%d%s%u",
+			 adapter->pf_idx, adapter->pf_idx,
+			 "vf",
+			 req_eth_da->representor_ports[repr_idx]);
+
+		eth_dev = rte_eth_dev_allocate(name);
+		if (!eth_dev) {
+			ret = -ENOMEM;
+			goto l_release_port;
+		}
+		eth_dev->data->dev_private = rte_zmalloc_socket(name,
+			sizeof(struct sxe2_adapter),
+			RTE_CACHE_LINE_SIZE,
+			rte_socket_id());
+
+		if (!eth_dev->data->dev_private) {
+			rte_eth_dev_release_port(eth_dev);
+			ret = -ENOMEM;
+			goto l_release_port;
+		}
+
+		eth_dev->device = rte_eth_devices[adapter->dev_info.dev_data->port_id].device;
+
+		ret = sxe2_repr_dev_init(eth_dev, adapter,
+					 req_eth_da->representor_ports[repr_idx]);
+		if (ret) {
+			PMD_LOG_ERR(INIT, "Sxe2 dev init failed, ret=%d", ret);
+			rte_eth_dev_release_port(eth_dev);
+			goto l_release_port;
+		}
+
+		eth_dev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
+		if (eth_dev->intr_handle == NULL) {
+			PMD_LOG_ERR(INIT, "Sxe2 dev init representor intr_handle failed");
+			ret = -ENOMEM;
+			sxe2_repr_dev_uinit(eth_dev);
+			rte_eth_dev_release_port(eth_dev);
+			goto l_release_port;
+		}
+		adapter->repr_ctxt.vf_rep_eth_dev[repr_idx] = eth_dev;
+		rte_eth_dev_probing_finish(eth_dev);
+	}
+	adapter->repr_ctxt.nb_repr_vf = req_eth_da->nb_representor_ports;
+	goto l_end;
+
+l_release_port:
+	for (tmp_repr_idx = 0; tmp_repr_idx < repr_idx; ++tmp_repr_idx) {
+		struct rte_eth_dev *rep_dev = adapter->repr_ctxt.vf_rep_eth_dev[tmp_repr_idx];
+		if (rep_dev) {
+			sxe2_repr_dev_uinit(rep_dev);
+			if (rep_dev->intr_handle)
+				rte_intr_instance_free(rep_dev->intr_handle);
+			rte_eth_dev_release_port(rep_dev);
+			adapter->repr_ctxt.vf_rep_eth_dev[tmp_repr_idx] = NULL;
+		}
+	}
+
+	rte_free(adapter->repr_ctxt.vf_rep_eth_dev);
+	adapter->repr_ctxt.vf_rep_eth_dev = NULL;
+
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_ethdev_repr.h b/drivers/net/sxe2/sxe2_ethdev_repr.h
new file mode 100644
index 0000000000..71a666337f
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SX2_ETHDEV_REPR_H__
+#define __SX2_ETHDEV_REPR_H__
+#include <rte_compat.h>
+#include <rte_kvargs.h>
+#include <rte_time.h>
+#include <ethdev_driver.h>
+#include <ethdev_pci.h>
+#include <rte_tm_driver.h>
+#include <rte_io.h>
+#include <rte_ethdev.h>
+#include <rte_alarm.h>
+#include <rte_dev_info.h>
+
+#include "sxe2_vsi.h"
+#include "sxe2_irq.h"
+#include "sxe2_queue.h"
+struct sxe2_adapter;
+
+void sxe2_repr_all_close(struct rte_eth_dev *dev);
+
+int32_t sxe2_repr_dev_init(struct rte_eth_dev *dev,
+		       struct sxe2_adapter *parent_adapter,
+		       uint16_t repr_id);
+
+int32_t sxe2_switchdev_repr_devs_init(struct sxe2_adapter *adapter,
+				  struct rte_eth_devargs *req_eth_da);
+
+#endif /* __SX2_ETHDEV_REPR_H__ */
diff --git a/drivers/net/sxe2/sxe2_filter.c b/drivers/net/sxe2/sxe2_filter.c
index b2a726f77e..175b886aa3 100644
--- a/drivers/net/sxe2/sxe2_filter.c
+++ b/drivers/net/sxe2/sxe2_filter.c
@@ -9,6 +9,7 @@
 #include "sxe2_common_log.h"
 #include "sxe2_ethdev.h"
 #include "sxe2_cmd_chnl.h"
+#include "sxe2_switchdev.h"
 
 static struct sxe2_mac_filter *sxe2_uc_filter_find(struct sxe2_adapter *adapter,
 			struct rte_ether_addr *macaddr)
@@ -698,16 +699,96 @@ static int32_t sxe2_all_filter_hw_set(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+static int32_t sxe2_uplink_hw_clear(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (adapter->filter_ctxt.hw_uplink_config) {
+		if (adapter->dev_type == SXE2_DEV_T_PF) {
+			ret = sxe2_uplink_clear(adapter);
+			if (ret) {
+				PMD_DEV_LOG_ERR(adapter, DRV,
+						"Failed to clear uplink, ret:%d", ret);
+				goto l_end;
+			}
+			adapter->filter_ctxt.hw_uplink_config = false;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_uplink_hw_set(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (!adapter->filter_ctxt.hw_uplink_config) {
+		if (adapter->dev_type == SXE2_DEV_T_PF) {
+			ret = sxe2_uplink_set(adapter);
+			if (ret && ret != -EEXIST) {
+				PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set uplink, ret:%d", ret);
+				goto l_end;
+			}
+			adapter->filter_ctxt.hw_uplink_config = true;
+			ret = 0;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_repr_hw_clear(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (adapter->filter_ctxt.hw_repr_config) {
+		if (adapter->dev_type == SXE2_DEV_T_PF ||
+			adapter->dev_type == SXE2_DEV_T_PF_BOND) {
+			ret = sxe2_repr_clear(adapter);
+			if (ret) {
+				PMD_DEV_LOG_ERR(adapter, DRV, "Failed to clear repr, ret:%d", ret);
+				goto l_end;
+			}
+			adapter->filter_ctxt.hw_repr_config = false;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_repr_hw_set(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (!adapter->filter_ctxt.hw_repr_config) {
+		if (adapter->dev_type == SXE2_DEV_T_PF ||
+			adapter->dev_type == SXE2_DEV_T_PF_BOND) {
+			ret = sxe2_repr_set(adapter);
+			if (ret && ret != -EEXIST) {
+				PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set repr, ret:%d", ret);
+				goto l_end;
+			}
+			adapter->filter_ctxt.hw_repr_config = true;
+			ret = 0;
+		}
+	}
+l_end:
+	return ret;
+}
+
 int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter)
 {
 	int32_t ret = 0;
 
-	if (!adapter->flow_isolated && !adapter->switchdev_info.is_switchdev &&
-	    adapter->rule_started) {
+	if (!adapter->flow_isolated &&
+	    !adapter->switchdev_info.is_switchdev &&
+	    adapter->rule_started)
 		adapter->filter_ctxt.cur_l2_config = true;
-	} else {
+	else
 		adapter->filter_ctxt.cur_l2_config = false;
-	}
 
 	if (adapter->filter_ctxt.cur_l2_config !=
 	    adapter->filter_ctxt.hw_l2_config) {
@@ -724,6 +805,38 @@ int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+int32_t sxe2_switchdev_rule_update(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (!adapter->flow_isolated &&
+	    adapter->switchdev_info.is_switchdev) {
+		adapter->filter_ctxt.cur_uplink_config = true;
+		adapter->filter_ctxt.cur_repr_config = true;
+	} else {
+		adapter->filter_ctxt.cur_uplink_config = false;
+		adapter->filter_ctxt.cur_repr_config = false;
+	}
+
+	if (adapter->filter_ctxt.cur_uplink_config !=
+	    adapter->filter_ctxt.hw_uplink_config) {
+		if (adapter->filter_ctxt.cur_uplink_config)
+			ret = sxe2_uplink_hw_set(adapter);
+		else
+			ret = sxe2_uplink_hw_clear(adapter);
+	}
+
+	if (adapter->filter_ctxt.cur_repr_config !=
+	    adapter->filter_ctxt.hw_repr_config) {
+		if (adapter->filter_ctxt.cur_repr_config)
+			ret = sxe2_repr_hw_set(adapter);
+		else
+			ret = sxe2_repr_hw_clear(adapter);
+	}
+
+	return ret;
+}
+
 int32_t sxe2_filter_rule_stop(struct rte_eth_dev *dev)
 {
 	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
diff --git a/drivers/net/sxe2/sxe2_filter.h b/drivers/net/sxe2/sxe2_filter.h
index 6262e8c845..b2538ed22f 100644
--- a/drivers/net/sxe2/sxe2_filter.h
+++ b/drivers/net/sxe2/sxe2_filter.h
@@ -89,6 +89,8 @@ int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter);
 
 int32_t sxe2_filter_rule_stop(struct rte_eth_dev *dev);
 
+int32_t sxe2_switchdev_rule_update(struct sxe2_adapter *adapter);
+
 int32_t sxe2_filter_rule_start(struct rte_eth_dev *dev);
 
 int32_t sxe2_filter_init(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_flow.c b/drivers/net/sxe2/sxe2_flow.c
new file mode 100644
index 0000000000..6999cb0725
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow.c
@@ -0,0 +1,1337 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <sys/queue.h>
+#include <unistd.h>
+#include "sxe2_ethdev.h"
+#include "sxe2_flow.h"
+#include "sxe2_flow_parse_pattern.h"
+#include "sxe2_flow_parse_action.h"
+#include "sxe2_flow_parse_engine.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_flow_public.h"
+#include "sxe2_common_log.h"
+
+static int32_t sxe2_check_para(const struct rte_flow_attr *attr,
+			   const struct rte_flow_item pattern[],
+			   const struct rte_flow_action actions[],
+			   struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	if (!pattern) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+				NULL, "NULL pattern.");
+		ret = -rte_errno;
+		goto l_end;
+	}
+
+	if (!actions) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_NUM,
+				NULL, "NULL action.");
+		ret = -rte_errno;
+		goto l_end;
+	}
+
+	if (!attr) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR,
+				NULL, "NULL attribute.");
+		ret = -rte_errno;
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_valid_attr(const struct rte_flow_attr *attr, struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+
+	if (!attr->ingress) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
+				attr, "Only support ingress.");
+		ret = -rte_errno;
+		goto l_end;
+	}
+
+	if (attr->egress) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
+				attr, "Not support egress.");
+		ret = -rte_errno;
+		goto l_end;
+	}
+
+	if (attr->group >= 4) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
+				attr, "Not support group >= 4.");
+		ret = -rte_errno;
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_check_hdr_duplicate(struct sxe2_flow_item *item_new,
+					 struct sxe2_flow_item *item_exist)
+{
+	int32_t ret = 0;
+	uint16_t i = 0;
+	uint16_t size = sizeof(struct sxe2_flow_item);
+	union sxe2_flow_item_raw item_raw_new;
+	union sxe2_flow_item_raw item_raw_exist;
+	rte_memcpy(&item_raw_new.item, item_new, size);
+	rte_memcpy(&item_raw_exist.item, item_exist, size);
+
+	for (i = 0; i < size; i++) {
+		if (item_raw_new.raw[i] != item_raw_exist.raw[i])
+			goto l_end;
+	}
+	ret = -EEXIST;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_check_flow_duplicate(struct sxe2_flow *flow_new,
+					      struct sxe2_flow *flow_exist)
+{
+	int32_t ret = 0;
+	int32_t ret_mask1 = 0;
+	int32_t ret_mask2 = 0;
+	int32_t ret_spec1 = 0;
+	int32_t ret_spec2 = 0;
+
+	if (flow_new->engine_type != flow_exist->engine_type)
+		goto l_end;
+	if (flow_new->meta.flow_type != flow_exist->meta.flow_type)
+		goto l_end;
+	if (!sxe2_bitmap_equal(flow_new->flow_type, flow_exist->flow_type,
+			SXE2_EXPANSION_MAX))
+		goto l_end;
+	if (flow_new->meta.flow_prio != flow_exist->meta.flow_prio)
+		goto l_end;
+
+	ret_mask1 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_outer.item_mask,
+						  &flow_exist->pattern_outer.item_mask);
+	ret_mask2 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_inner.item_mask,
+						  &flow_exist->pattern_inner.item_mask);
+
+	ret_spec1 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_outer.item_spec,
+						  &flow_exist->pattern_outer.item_spec);
+	ret_spec2 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_inner.item_spec,
+						  &flow_exist->pattern_inner.item_spec);
+
+	if (flow_new->engine_type == SXE2_FLOW_ENGINE_FNAV) {
+		if (ret_mask1 == 0 || ret_mask2 == 0) {
+			ret = -EEXIST;
+			goto l_end;
+		}
+
+		if (ret_spec1 == -EEXIST && ret_spec2 == -EEXIST) {
+			ret = -EEXIST;
+			goto l_end;
+		}
+	} else {
+		if (ret_mask1 == -EEXIST && ret_mask2 == -EEXIST &&
+			ret_spec1 == -EEXIST && ret_spec2 == -EEXIST) {
+			ret = -EEXIST;
+			goto l_end;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_check_flow_list_duplicate(struct rte_eth_dev *dev,
+						   struct rte_flow *flow_list)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_flow *sxe2_flow_new = NULL;
+	struct rte_flow *rte_flow_exist = NULL;
+	struct sxe2_flow *sxe2_flow_exist = NULL;
+	TAILQ_FOREACH(sxe2_flow_new, &flow_list->sxe2_flow_list, next) {
+		TAILQ_FOREACH(rte_flow_exist, &adapter->flow_ctxt.rte_flow_list, next) {
+			TAILQ_FOREACH(sxe2_flow_exist, &rte_flow_exist->sxe2_flow_list, next) {
+				ret = sxe2_flow_check_flow_duplicate(sxe2_flow_new,
+								     sxe2_flow_exist);
+				if (ret != 0)
+					goto l_end;
+			}
+		}
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_check_function(struct rte_eth_dev *dev,
+				    struct rte_flow *flow_list,
+				    struct rte_flow_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+	struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+	int32_t ret = 0;
+
+	uint16_t flow_dst_vsi = UINT16_MAX;
+
+	if (adapter->dev_type == SXE2_DEV_T_VF) {
+		if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types)) {
+			flow_dst_vsi = flow->action.vsi.vsi_index;
+
+			if (adapter->vsi_ctxt.dpdk_vsi_id != flow_dst_vsi &&
+				adapter->vsi_ctxt.kernel_vsi_id != flow_dst_vsi) {
+				PMD_LOG_ERR(DRV, "Failed to redirect other function");
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to redirect other function");
+				ret = -ENOTSUP;
+				goto l_end;
+			}
+		}
+
+		if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI_LIST, flow->action.act_types)) {
+			PMD_LOG_ERR(DRV,
+				"Failed to redirect multiple driver or function");
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to redirect multiple driver or function");
+				ret = -ENOTSUP;
+				goto l_end;
+		}
+
+		if (!adapter->flow_isolated &&
+			flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+			PMD_LOG_ERR(DRV,
+				"Failed to switch engine rules in a non-flow-isolated state");
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to switch engine rules in a non-flow-isolated state");
+				ret = -ENOTSUP;
+				goto l_end;
+		}
+
+		if (adapter->switchdev_info.is_switchdev &&
+			flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+			PMD_LOG_ERR(DRV,
+				"Failed to switch engine rules in a switchdev mode state");
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to switch engine rules in a switchdev mode state");
+				ret = -ENOTSUP;
+				goto l_end;
+		}
+	}
+
+	if (adapter->is_dev_repr) {
+		if (flow->engine_type != SXE2_FLOW_ENGINE_SWITCH) {
+			PMD_LOG_ERR(DRV,
+				"Failed to config non switch engine rules in representor dev");
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to config non switch engine rules in representor dev");
+				ret = -ENOTSUP;
+				goto l_end;
+		}
+
+		if (sxe2_test_bit(SXE2_FLOW_ACTION_QUEUE, flow->action.act_types) ||
+			sxe2_test_bit(SXE2_FLOW_ACTION_Q_REGION, flow->action.act_types)) {
+			PMD_LOG_ERR(DRV,
+				"Failed to config queue rules in representor dev");
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to config queue rules in representor dev");
+				ret = -ENOTSUP;
+				goto l_end;
+		}
+	}
+
+	if (adapter->switchdev_info.is_switchdev &&
+		adapter->dev_type == SXE2_DEV_T_PF &&
+		!adapter->is_dev_repr &&
+		!adapter->flow_isolated) {
+		if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types)) {
+			if (flow->action.vsi.vsi_index == adapter->vsi_ctxt.dpdk_vsi_id) {
+				PMD_LOG_ERR(DRV,
+					"Failed to config rx fwd rule to current uplink dev");
+					rte_flow_error_set(error, ENOTSUP,
+						RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+						"Failed to config rx fwd rule to current uplink dev");
+					ret = -ENOTSUP;
+					goto l_end;
+			}
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_meta_proc(struct rte_eth_dev *dev,
+			       const struct rte_flow_attr *attr,
+			       struct rte_flow *flow_list,
+			       struct rte_flow_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+	struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+	int32_t ret = 0;
+
+	if (attr->priority >= 1) {
+		if (flow->engine_type != SXE2_FLOW_ENGINE_SWITCH) {
+			PMD_LOG_ERR(DRV, "Only support priority 0.");
+			rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+					attr, "Only support priority 0.");
+			ret = -rte_errno;
+			goto l_end;
+		} else if (!adapter->switchdev_info.is_switchdev) {
+			PMD_LOG_ERR(DRV, "Legacy mode only support priority 0.");
+			rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+					attr, "Legacy mode only priority 0.");
+			ret = -rte_errno;
+			goto l_end;
+		} else {
+			flow->meta.flow_prio = attr->priority;
+		}
+	}
+
+	flow->meta.flow_src_vsi = adapter->vsi_ctxt.dpdk_vsi_id;
+
+	if (adapter->is_dev_repr && adapter->repr_priv_data &&
+		adapter->repr_priv_data->parent_adapter) {
+		flow->meta.flow_rule_vsi =
+			adapter->repr_priv_data->parent_adapter->vsi_ctxt.dpdk_vsi_id;
+	} else {
+		flow->meta.flow_rule_vsi = adapter->vsi_ctxt.dpdk_vsi_id;
+	}
+
+	if (flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+		flow->meta.switch_pattern_dup_allow =
+			adapter->devargs.flow_dup_pattern_mode;
+
+		flow->meta.switch_src_direct = SXE2_FLOW_SW_DIRECT_RX;
+
+		if (adapter->switchdev_info.is_switchdev && adapter->is_dev_repr) {
+			flow->meta.switch_src_direct = SXE2_FLOW_SW_DIRECT_TX;
+			flow->meta.flow_src_vsi = adapter->repr_priv_data->repr_vf_vsi_id;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_src_split_proc(struct rte_eth_dev *dev,
+				    struct rte_flow *flow_list,
+				    struct rte_flow_error *error)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+	struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+	int32_t ret = 0;
+
+	int32_t idx = 0;
+	uint8_t flow_cnt = 0;
+	uint8_t flow_create_cnt = 0;
+	uint8_t flow_bond_num = 1;
+	uint16_t flow_src_vsi[SXE2_MAX_DRV_TYPE_CNT][SXE2_MAX_BOND_MEMBER_CNT];
+	uint16_t flow_dst_vsi = UINT16_MAX;
+	struct sxe2_flow *flow_new = NULL;
+
+	if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types))
+		flow_dst_vsi = flow->action.vsi.vsi_index;
+
+	for (idx = 0; idx < SXE2_MAX_BOND_MEMBER_CNT; idx++) {
+		flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] = UINT16_MAX;
+		flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+	}
+
+	flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][0] = adapter->vsi_ctxt.dpdk_vsi_id;
+	flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][0] = adapter->vsi_ctxt.kernel_vsi_id;
+	if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV ||
+		flow->engine_type == SXE2_FLOW_ENGINE_ACL) {
+		if (!adapter->devargs.func_flow_direct_en &&
+			adapter->dev_type != SXE2_DEV_T_PF_BOND) {
+			if (adapter->flow_isolated) {
+				for (idx = 0; idx < flow_bond_num; idx++) {
+					if (flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] !=
+								UINT16_MAX)
+						flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] =
+										UINT16_MAX;
+				}
+			} else {
+				for (idx = 0; idx < flow_bond_num; idx++)
+					flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+			}
+		}
+
+		for (idx = 0; idx < flow_bond_num; idx++) {
+			if (flow_dst_vsi == flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx])
+				flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+			if (flow_dst_vsi == flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx])
+				flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] = UINT16_MAX;
+		}
+	} else {
+		for (idx = 0; idx < flow_bond_num; idx++)
+			flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+	}
+
+	if (adapter->switchdev_info.is_switchdev && adapter->is_dev_repr) {
+		flow_bond_num = 1;
+		flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][0] =
+			adapter->repr_priv_data->repr_vf_u_vsi_id;
+		flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][0] =
+			adapter->repr_priv_data->repr_vf_k_vsi_id;
+	}
+
+	for (idx = 0; idx < flow_bond_num; idx++) {
+		if (flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] != UINT16_MAX)
+			flow_cnt++;
+		if (flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] != UINT16_MAX)
+			flow_cnt++;
+	}
+
+	if (flow_cnt == 0) {
+		PMD_LOG_ERR(DRV, "Failed to redirect same device.");
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"Failed to redirect same device");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	for (idx = 0; idx < flow_bond_num; idx++) {
+		if (flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] != UINT16_MAX) {
+			if (flow_create_cnt == 0) {
+				flow->meta.flow_src_vsi =
+					flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx];
+				flow_create_cnt++;
+			} else {
+				flow_new = rte_zmalloc("sxe2_flow", sizeof(*flow), 0);
+				if (!flow_new) {
+					rte_flow_error_set(error, ENOMEM,
+						   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+						   "Failed to alloc memory for flow rule");
+					ret = -ENOMEM;
+					goto l_end;
+				}
+				rte_memcpy(flow_new, flow, sizeof(struct sxe2_flow));
+				TAILQ_INSERT_TAIL(sxe2_flow_list, flow_new, next);
+				flow_new->meta.flow_src_vsi =
+						flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx];
+				flow_create_cnt++;
+			}
+		}
+		if (flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] != UINT16_MAX) {
+			if (flow_create_cnt == 0) {
+				flow->meta.flow_src_vsi =
+					flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx];
+				flow_create_cnt++;
+			} else {
+				flow_new = rte_zmalloc("sxe2_flow", sizeof(*flow), 0);
+				if (!flow_new) {
+					rte_flow_error_set(error, ENOMEM,
+						RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+						"Failed to alloc memory for flow rule");
+					ret = -ENOMEM;
+					goto l_end;
+				}
+				rte_memcpy(flow_new, flow, sizeof(struct sxe2_flow));
+				TAILQ_INSERT_TAIL(sxe2_flow_list, flow_new, next);
+				flow_new->meta.flow_src_vsi =
+					flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx];
+				flow_create_cnt++;
+			}
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_adjust_action(struct rte_eth_dev *dev __rte_unused,
+				   struct rte_flow *flow_list,
+				   struct rte_flow_error *error __rte_unused)
+{
+	struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+	struct sxe2_flow *flow = NULL;
+	int32_t ret = 0;
+	int32_t dest_num = 0;
+	int32_t pass_num = 0;
+	int32_t mark_num = 0;
+	int32_t count_num = 0;
+	int32_t drop_num = 0;
+
+	TAILQ_FOREACH(flow, sxe2_flow_list, next) {
+		if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV) {
+			dest_num = sxe2_test_bit(SXE2_FLOW_ACTION_Q_REGION,
+					    flow->action.act_types) +
+				   sxe2_test_bit(SXE2_FLOW_ACTION_QUEUE,
+					    flow->action.act_types);
+			pass_num = sxe2_test_bit(SXE2_FLOW_ACTION_PASSTHRU,
+					    flow->action.act_types);
+			mark_num = sxe2_test_bit(SXE2_FLOW_ACTION_MARK,
+					    flow->action.act_types);
+			count_num = sxe2_test_bit(SXE2_FLOW_ACTION_COUNT,
+					     flow->action.act_types);
+			drop_num = sxe2_test_bit(SXE2_FLOW_ACTION_DROP,
+					    flow->action.act_types);
+
+			if (dest_num) {
+				sxe2_clear_bit(SXE2_FLOW_ACTION_PASSTHRU,
+					  flow->action.act_types);
+				pass_num = 0;
+				sxe2_clear_bit(SXE2_FLOW_ACTION_TO_VSI,
+					  flow->action.act_types);
+			}
+
+			if (pass_num)
+				flow->action.passthru.vsi_index = flow->meta.flow_src_vsi;
+
+			if (mark_num) {
+				if (dest_num == 0) {
+					flow->action.q_region.q_index = 0;
+					flow->action.q_region.region = 7;
+					flow->action.q_region.vsi_index = flow->meta.flow_src_vsi;
+					sxe2_set_bit(SXE2_FLOW_ACTION_Q_REGION,
+						flow->action.act_types);
+					dest_num++;
+				}
+				sxe2_clear_bit(SXE2_FLOW_ACTION_PASSTHRU,
+					flow->action.act_types);
+				pass_num = 0;
+			}
+			if (count_num) {
+				if (dest_num == 0 && drop_num == 0) {
+					if (pass_num == 0) {
+						sxe2_set_bit(SXE2_FLOW_ACTION_PASSTHRU,
+							flow->action.act_types);
+						flow->action.passthru.vsi_index =
+									flow->meta.flow_src_vsi;
+						pass_num++;
+					}
+				}
+			}
+			PMD_LOG_DEBUG(DRV, "dest_num: %d, pass_num: %d, mark_num: %d, count_num: "
+				"%d, drop_num: %d", dest_num, pass_num, mark_num, count_num,
+				drop_num);
+			PMD_LOG_DEBUG(DRV, "src_vsi: %d", flow->meta.flow_src_vsi);
+		}
+	}
+
+	return ret;
+}
+
+static int32_t sxe2_flow_check_item_empty(uint8_t *item, uint16_t size)
+{
+	uint16_t i = 0;
+
+	for (i = 0; i < size; i++) {
+		if (item[i] != 0)
+			return -1;
+	}
+	return 0;
+}
+
+static int32_t sxe2_flowlist_add_proto_type(struct rte_eth_dev *dev __rte_unused,
+					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);
+	struct sxe2_flow_pattern *pattern = &flow->pattern_outer;
+	int32_t ret = 0;
+
+	if (flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+		if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow->flow_type) &&
+		    sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.ipv4,
+			sizeof(pattern->item_mask.ipv4)) == 0) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, pattern->map_spec);
+			pattern->item_spec.eth.ether_type =
+				rte_cpu_to_be_16(SXE2_FLOW_ETH_TYPE_IPV4);
+			pattern->item_mask.eth.ether_type = 0xffff;
+		}
+		if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow->flow_type) &&
+		    sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.ipv6,
+			sizeof(pattern->item_mask.ipv6)) == 0) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, pattern->map_spec);
+			pattern->item_spec.eth.ether_type =
+				rte_cpu_to_be_16(SXE2_FLOW_ETH_TYPE_IPV6);
+			pattern->item_mask.eth.ether_type = 0xffff;
+		}
+
+		if (flow->meta.tunnel_type == SXE2_FLOW_TUNNEL_TYPE_NONE) {
+			if (sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow->flow_type) &&
+			    sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.udp,
+				sizeof(pattern->item_mask.udp)) == 0) {
+				if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4,
+					     flow->flow_type)) {
+					sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_spec);
+					pattern->item_spec.ipv4.protocol =
+						SXE2_FLOW_IP_PROTOCOL_UDP;
+					pattern->item_mask.ipv4.protocol = 0xff;
+				}
+				if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6,
+					     flow->flow_type)) {
+					ret = -EINVAL;
+					rte_flow_error_set(error, ENOENT,
+						RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+						"UDP after IPv6 must has pattern item.");
+					PMD_LOG_ERR(DRV,
+						"UDP after IPv6 must has pattern item.");
+					goto l_end;
+				}
+			}
+			if (sxe2_test_bit(SXE2_EXPANSION_OUTER_TCP, flow->flow_type) &&
+			    sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.tcp,
+				sizeof(pattern->item_mask.tcp)) == 0) {
+				if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4,
+					     flow->flow_type)) {
+					sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT,
+						pattern->map_spec);
+					pattern->item_spec.ipv4.protocol =
+						SXE2_FLOW_IP_PROTOCOL_TCP;
+					pattern->item_mask.ipv4.protocol = 0xff;
+				}
+				if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6,
+					     flow->flow_type)) {
+					ret = -EINVAL;
+					rte_flow_error_set(error, ENOENT,
+						RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+						"TCP after IPv6 must has pattern item.");
+					PMD_LOG_ERR(DRV,
+						"TCP after IPv6 must has pattern item.");
+					goto l_end;
+				}
+			}
+			if (sxe2_test_bit(SXE2_EXPANSION_OUTER_SCTP,
+				     flow->flow_type)) {
+				ret = -EINVAL;
+				rte_flow_error_set(error, ENOENT,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"SWITCH not support SCTP.");
+				PMD_LOG_ERR(DRV, "SWITCH not support SCTP.");
+				goto l_end;
+			}
+		}
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_tunnel_split_proc(struct rte_eth_dev *dev __rte_unused,
+				       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_list_t tunnel_flow_list;
+	struct sxe2_flow *sxe2_flow_exist = NULL;
+	struct sxe2_flow *sxe2_flow_new = NULL;
+	struct sxe2_flow_pattern *pattern = NULL;
+	int32_t ret = 0;
+
+	TAILQ_INIT(&tunnel_flow_list);
+
+	TAILQ_FOREACH(sxe2_flow_exist, sxe2_flow_list, next) {
+		if (sxe2_flow_exist->engine_type != SXE2_FLOW_ENGINE_SWITCH)
+			continue;
+		if (sxe2_test_bit(SXE2_FLOW_FLD_ID_IPV4_PROT,
+				sxe2_flow_exist->pattern_outer.map_spec)) {
+			pattern = &sxe2_flow_exist->pattern_outer;
+			if ((pattern->item_spec.ipv4.protocol &
+				pattern->item_mask.ipv4.protocol) ==
+				(SXE2_FLOW_IP_PROTOCOL_GRE &
+				pattern->item_mask.ipv4.protocol)) {
+				sxe2_flow_new = rte_zmalloc("sxe2_flow",
+					sizeof(struct sxe2_flow), 0);
+				if (!sxe2_flow_new) {
+					rte_flow_error_set(error, ENOMEM,
+						RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+						"Failed to alloc memory for flow rule");
+					ret = -ENOMEM;
+					goto l_end;
+				}
+				rte_memcpy(sxe2_flow_new, sxe2_flow_exist,
+					sizeof(struct sxe2_flow));
+				pattern = &sxe2_flow_new->pattern_outer;
+				sxe2_flow_new->meta.tunnel_type =
+					SXE2_FLOW_TUNNEL_TYPE_GRE;
+				sxe2_set_bit(SXE2_FLOW_HDR_GRE, pattern->hdrs);
+				pattern->item_spec.ipv4.protocol =
+					SXE2_FLOW_IP_PROTOCOL_GRE;
+				pattern->item_mask.ipv4.protocol = 0xff;
+				TAILQ_INSERT_TAIL(&tunnel_flow_list, sxe2_flow_new, next);
+			}
+		}
+	}
+	TAILQ_FOREACH(sxe2_flow_exist, &tunnel_flow_list, next)
+		TAILQ_INSERT_TAIL(sxe2_flow_list, sxe2_flow_exist, next);
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_post_proc(struct rte_eth_dev *dev,
+			       const struct rte_flow_attr *attr,
+			       struct rte_flow *flow_list,
+			       struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+
+	ret = sxe2_flowlist_add_proto_type(dev, flow_list, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_check_function(dev, flow_list, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_meta_proc(dev, attr, flow_list, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_src_split_proc(dev, flow_list, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_adjust_action(dev, flow_list, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_tunnel_split_proc(dev, flow_list, error);
+	if (ret)
+		goto l_end;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_validate_with_flow(struct rte_eth_dev *dev,
+					struct rte_flow *flow_list,
+					const struct rte_flow_attr *attr,
+					const struct rte_flow_item pattern[],
+					const struct rte_flow_action actions[],
+					struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_flow *flow = NULL;
+
+	ret = sxe2_check_para(attr, pattern, actions, error);
+	if (ret != 0)
+		goto l_end;
+
+	ret = sxe2_flow_valid_attr(attr, error);
+	if (ret != 0)
+		goto l_end;
+
+	flow = rte_zmalloc("sxe2_flow", sizeof(*flow), 0);
+	if (!flow) {
+		rte_flow_error_set(error, ENOMEM,
+				RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				"Failed to alloc memory for flow rule");
+		PMD_LOG_ERR(DRV, "Failed to alloc memory for flow rule.");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	TAILQ_INSERT_TAIL(&flow_list->sxe2_flow_list, flow, next);
+	flow->create_err = -1;
+
+	ret = sxe2_flow_parse_pattern(dev, pattern, error, flow);
+	if (ret != 0)
+		goto l_end;
+
+	ret = sxe2_flow_parse_engine(dev, attr, actions, error, flow);
+	if (ret != 0)
+		goto l_end;
+
+	ret = sxe2_flow_parse_action(dev, actions, error, flow);
+	if (ret != 0)
+		goto l_end;
+
+	ret = sxe2_flow_post_proc(dev, attr, flow_list, error);
+	if (ret != 0)
+		goto l_end;
+
+	ret = sxe2_flow_check_flow_list_duplicate(dev, flow_list);
+	if (ret != 0) {
+		rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_ITEM,
+				NULL, "Duplicate flow.");
+		PMD_LOG_ERR(DRV, "Duplicate flow.");
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+static const char *sxe2_flow_convert_ret_to_flow_msg(int32_t ret)
+{
+	const char *msg = NULL;
+	if (ret > 0)
+		ret = -ret;
+	switch (ret) {
+	case -ENOMEM:
+		msg = "no memory";
+		break;
+	case -ENOTSUP:
+		msg = "not support";
+		break;
+	case -EEXIST:
+		msg = "rule already exist";
+		break;
+	case -ETIMEDOUT:
+		msg = "timeout";
+		break;
+	case -EINVAL:
+		msg = "invalid parameter";
+		break;
+	case -ENOSPC:
+		msg = "no space";
+		break;
+	case -ENOENT:
+		msg = "no such rule";
+		break;
+	default:
+		msg = "unknown error";
+		break;
+	}
+	return msg;
+}
+
+static int32_t sxe2_flow_rte_list_free(struct sxe2_adapter *adapter,
+				   struct rte_flow **flow_ptr,
+				   struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	int32_t ret1 = 0;
+	struct rte_flow *flow = *flow_ptr;
+	struct rte_flow *flow_temp = NULL;
+	struct sxe2_flow *hw_flow = NULL;
+	struct sxe2_flow *hw_flow_temp = NULL;
+	struct sxe2_fnav_cid_mgr *mgr = NULL;
+	rte_spinlock_lock(&adapter->flow_ctxt.flow_list_lock);
+	TAILQ_FOREACH(flow_temp, &adapter->flow_ctxt.rte_flow_list, next) {
+		if (flow_temp == flow)
+			TAILQ_REMOVE(&adapter->flow_ctxt.rte_flow_list, flow, next);
+	}
+
+	TAILQ_FOREACH_SAFE(hw_flow, &flow->sxe2_flow_list, next, hw_flow_temp) {
+		if (hw_flow->create_err == 0) {
+			if (sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, hw_flow->action.act_types)) {
+				ret = sxe2_flow_query_mgr(adapter, hw_flow, &mgr, error);
+				if (ret) {
+					PMD_LOG_ERR(DRV,
+						"Failed to query flow count, flow id: %u, ret: %d.",
+						hw_flow->flow_id, ret);
+					rte_flow_error_set(error, EIO,
+						RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+						"Failed to query flow count");
+					ret1 = ret;
+				}
+			}
+
+			ret = sxe2_drv_flow_filter_del(adapter, hw_flow);
+			if (ret) {
+				PMD_LOG_ERR(DRV,
+					"Failed to delete flow filter, ret: %d:%s",
+					ret, sxe2_flow_convert_ret_to_flow_msg(ret));
+				rte_flow_error_set(error, EIO,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to delete flow filter");
+				ret1 = ret;
+			}
+
+			if (sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, hw_flow->action.act_types)) {
+				ret = sxe2_flow_free_mgr(adapter, hw_flow,
+							 &mgr, error);
+				if (ret)
+					ret1 = ret;
+			}
+		}
+
+		TAILQ_REMOVE(&flow->sxe2_flow_list, hw_flow, next);
+		rte_free(hw_flow);
+	}
+	rte_free(flow);
+	*flow_ptr = NULL;
+	rte_spinlock_unlock(&adapter->flow_ctxt.flow_list_lock);
+
+	return ret1;
+}
+
+static int32_t sxe2_flow_validate(struct rte_eth_dev *dev,
+			      const struct rte_flow_attr *attr,
+			      const struct rte_flow_item pattern[],
+			      const struct rte_flow_action actions[],
+			      struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct rte_flow *flow_list = NULL;
+	struct sxe2_flow *hw_flow = NULL;
+	struct sxe2_flow *hw_flow_temp = NULL;
+	flow_list = rte_zmalloc("rte_flow_va", sizeof(*flow_list), 0);
+	if (!flow_list) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to alloc memory for flow rule");
+		PMD_LOG_ERR(DRV, "Failed to alloc memory for flow rule.");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	TAILQ_INIT(&flow_list->sxe2_flow_list);
+
+	ret = sxe2_flow_validate_with_flow(dev, flow_list, attr, pattern, actions, error);
+	if (ret != 0)
+		goto l_free;
+l_free:
+
+	TAILQ_FOREACH_SAFE(hw_flow, &flow_list->sxe2_flow_list, next, hw_flow_temp) {
+		TAILQ_REMOVE(&flow_list->sxe2_flow_list, hw_flow, next);
+		rte_free(hw_flow);
+	}
+	rte_free(flow_list);
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_isolate(struct rte_eth_dev *dev,
+				 int32_t enable,
+				 struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (dev->data->dev_started) {
+		rte_flow_error_set(error, EBUSY,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				   NULL,
+				   "port must be stopped first");
+		ret = -EBUSY;
+		goto l_end;
+	}
+
+	if (adapter->is_dev_repr) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"representor dev cannot change isolated mode ");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (enable == adapter->flow_isolated)
+		goto l_end;
+
+	if (adapter->dev_type == SXE2_DEV_T_VF &&
+		adapter->switchdev_info.is_switchdev) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"isolated mode cannot be change when port in switch dev mode");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	rte_spinlock_lock(&adapter->flow_ctxt.flow_list_lock);
+	if (!TAILQ_EMPTY(&adapter->flow_ctxt.rte_flow_list))
+		PMD_DEV_LOG_WARN(adapter, DRV,
+			"The configured flow item may not take effect.");
+	rte_spinlock_unlock(&adapter->flow_ctxt.flow_list_lock);
+
+	adapter->flow_isolated = !!enable;
+
+	ret = sxe2_l2_rule_update(adapter);
+	if (ret != 0)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+	ret = sxe2_switchdev_rule_update(adapter);
+	if (ret != 0)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update switchdev rule");
+
+l_end:
+	if (ret == 0)
+		adapter->flow_isolate_cfg = !!enable;
+	return ret;
+}
+
+static struct rte_flow *sxe2_flow_create(struct rte_eth_dev *dev,
+					 const struct rte_flow_attr *attr,
+					 const struct rte_flow_item pattern[],
+					 const struct rte_flow_action action[],
+					 struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_flow *flow_list = NULL;
+	struct sxe2_flow *flow = NULL;
+
+	flow_list = rte_zmalloc("sxe2_flow_create", sizeof(*flow_list), 0);
+	if (!flow_list) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to alloc memory for flow rule");
+		PMD_LOG_ERR(DRV, "Failed to alloc memory for flow rule.");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	TAILQ_INIT(&flow_list->sxe2_flow_list);
+
+	ret = sxe2_flow_validate_with_flow(dev, flow_list, attr, pattern, action, error);
+	if (ret != 0)
+		goto l_free_flow;
+
+	TAILQ_FOREACH(flow, &flow_list->sxe2_flow_list, next) {
+		ret = sxe2_fnav_get_filter_cid(adapter, flow);
+		if (ret != 0) {
+			PMD_LOG_ERR(DRV, "fnav get stats id failed, ret:%d", ret);
+			rte_flow_error_set(error, EIO,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to add fnav rule:alloc cid failed.");
+			goto l_free_flow;
+		}
+		ret = sxe2_drv_flow_filter_add(adapter, flow);
+		if (ret) {
+			rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "Failed to add flow filter to hw.");
+			PMD_LOG_ERR(DRV, "Failed to add flow filter to hw.ret:%d:%s",
+				ret, sxe2_flow_convert_ret_to_flow_msg(ret));
+			goto l_free_flow;
+		}
+	}
+
+	TAILQ_INSERT_TAIL(&adapter->flow_ctxt.rte_flow_list, flow_list, next);
+	goto l_end;
+l_free_flow:
+	(void)sxe2_flow_rte_list_free(adapter, &flow_list, error);
+l_end:
+	return flow_list;
+}
+
+static int32_t sxe2_flow_destroy(struct rte_eth_dev *dev,
+			     struct rte_flow *flow,
+			     struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	ret = sxe2_flow_rte_list_free(adapter, &flow, error);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Failed to destroy flow.ret:%d.", ret);
+	return ret;
+}
+
+static int32_t sxe2_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_flow *flow = NULL;
+	struct rte_flow *tmp_flow = NULL;
+	struct rte_flow_list_t *flow_list = &adapter->flow_ctxt.rte_flow_list;
+	TAILQ_FOREACH_SAFE(flow, flow_list, next, tmp_flow) {
+		ret = sxe2_flow_destroy(dev, flow, error);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "Failed to flush flows.ret:%d.", ret);
+
+			if (ret != -EAGAIN)
+				ret = -EINVAL;
+			goto l_end;
+		}
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_fnav_get_filter_cid(struct sxe2_adapter *adapter, struct sxe2_flow *flow)
+{
+	int32_t ret = 0;
+	struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+				&adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+	uint32_t stat_index;
+	uint32_t user_id;
+	uint32_t driver_id;
+	struct sxe2_fnav_cid_mgr *temp = NULL;
+	struct sxe2_fnav_cid_mgr *mgr = NULL;
+
+	if (sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, flow->action.act_types)) {
+		user_id = flow->action.count.user_id;
+		driver_id = flow->action.count.driver_id;
+
+		TAILQ_FOREACH(temp, cid_mgr_list, next) {
+			if (temp->user_id == user_id &&
+				temp->driver_id == driver_id) {
+				mgr = temp;
+				break;
+			}
+		}
+		if (mgr == NULL) {
+			mgr = rte_zmalloc("sxe2_fnav_cid_mgr",
+				sizeof(struct sxe2_fnav_cid_mgr), 0);
+			if (!mgr) {
+				PMD_LOG_ERR(DRV,
+					"Failed to alloc sxe2vf_fnav_cid_mgr memory.");
+				ret = -ENOMEM;
+				goto l_end;
+			}
+
+			ret = sxe2_drv_flow_fnav_get_stat_id(adapter, &stat_index);
+			if (ret) {
+				PMD_LOG_ERR(DRV, "Failed to alloc fw count id.");
+				rte_free(mgr);
+				goto l_end;
+			}
+
+			TAILQ_INSERT_TAIL(cid_mgr_list, mgr, next);
+			mgr->user_id = user_id;
+			mgr->driver_id = driver_id;
+			mgr->stat_index = stat_index;
+			mgr->count_type = adapter->flow_ctxt.hw_res.count_type;
+		}
+		flow->action.count.stat_index = mgr->stat_index;
+		flow->action.count.stat_ctrl = mgr->count_type;
+	}
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_flow_free_mgr(struct sxe2_adapter *adapter,
+		       struct sxe2_flow *flow,
+		       struct sxe2_fnav_cid_mgr **mgr_ptr,
+		       struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+				&adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+	struct sxe2_fnav_cid_mgr *mgr = *mgr_ptr;
+	uint32_t user_id = flow->action.count.user_id;
+	if (user_id == 0) {
+		TAILQ_REMOVE(cid_mgr_list, mgr, next);
+		ret = sxe2_drv_flow_fnav_free_stat(adapter, mgr->stat_index);
+		if (ret) {
+			rte_flow_error_set(error, EIO,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Failed to free flow count.");
+			PMD_LOG_ERR(DRV,
+				"Failed to free flow count, flow id: %u, ret: %d.",
+				flow->flow_id, ret);
+		}
+		rte_free(mgr);
+		*mgr_ptr = NULL;
+	}
+	return ret;
+}
+
+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 ret = 0;
+	struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+				&adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+	struct sxe2_fnav_cid_mgr *temp = NULL;
+	struct sxe2_fnav_cid_mgr *mgr = NULL;
+	uint32_t user_id = flow->action.count.user_id;
+	uint32_t driver_id = flow->action.count.driver_id;
+
+	TAILQ_FOREACH(temp, cid_mgr_list, next) {
+		if (temp->user_id == user_id &&
+			temp->driver_id == driver_id) {
+			mgr = temp;
+			break;
+		}
+	}
+	if (!mgr) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"fnav flow query count invalid user_id or driver_id.");
+		PMD_LOG_ERR(DRV,
+			"fnav flow query count invalid user_id or driver_id.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	ret = sxe2_drv_flow_fnav_query_stat(adapter, mgr);
+	if (ret) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+			"Failed to query flow count.");
+		PMD_LOG_ERR(DRV,
+			"Failed to query flow count, flow id: %u, ret: %d.",
+			flow->flow_id, ret);
+		goto l_end;
+	}
+	*mgr_ptr = mgr;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_query_count(struct sxe2_adapter *adapter,
+				 struct sxe2_flow *flow,
+				 struct rte_flow_query_count *count,
+				 struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_fnav_cid_mgr *mgr = NULL;
+	switch (flow->action.count.stat_ctrl) {
+	case SXE2_FNAV_STAT_ENA_NONE:
+		count->hits_set = 0;
+		count->bytes_set = 0;
+		break;
+	case SXE2_FNAV_STAT_ENA_PKTS:
+		count->hits_set = 1;
+		count->bytes_set = 0;
+		break;
+	case SXE2_FNAV_STAT_ENA_BYTES:
+		count->hits_set = 0;
+		count->bytes_set = 1;
+		break;
+	case SXE2_FNAV_STAT_ENA_ALL:
+		count->hits_set = 1;
+		count->bytes_set = 1;
+		break;
+	default:
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (!sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, flow->action.act_types)) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"this flow don't have count action.");
+		PMD_LOG_ERR(DRV, "this flow don't have count action.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	ret = sxe2_flow_query_mgr(adapter, flow, &mgr, error);
+	if (ret) {
+		PMD_LOG_ERR(DRV,
+			"Failed to query flow count, flow id: %u, ret: %d.",
+			flow->flow_id, ret);
+		goto l_end;
+	}
+	count->hits = mgr->hits;
+	count->bytes = mgr->bytes;
+	if (count->reset) {
+		mgr->hits = 0;
+		mgr->bytes = 0;
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_query(struct rte_eth_dev *dev,
+			   struct rte_flow *flow_list,
+			   const struct rte_flow_action *actions,
+			   void *data,
+			   struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct rte_flow_query_count *count = data;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_flow *flow = NULL;
+
+	if (!flow_list) {
+		ret = -EINVAL;
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
+				NULL, "Invalid flow");
+		PMD_LOG_ERR(DRV, "Invalid flow to query flow.");
+		goto l_end;
+	}
+
+	rte_spinlock_lock(&adapter->flow_ctxt.flow_list_lock);
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_VOID:
+			break;
+		case RTE_FLOW_ACTION_TYPE_COUNT:
+			flow = TAILQ_FIRST(&flow_list->sxe2_flow_list);
+			ret = sxe2_flow_query_count(adapter, flow, count, error);
+			if (ret) {
+				PMD_LOG_ERR(DRV,
+					"Failed to query flow count, flow id: %u, ret: %d.",
+					flow->flow_id, ret);
+				goto l_end_unlock;
+			}
+			break;
+		default:
+			rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					actions,
+					"action not supported");
+			PMD_LOG_ERR(DRV,
+					"Failed to query flow action type:%d.",
+					actions->type);
+			ret = -ENOTSUP;
+			goto l_end_unlock;
+		}
+	}
+
+l_end_unlock:
+	rte_spinlock_unlock(&adapter->flow_ctxt.flow_list_lock);
+
+l_end:
+	return ret;
+}
+
+const struct rte_flow_ops sxe2_flow_ops = {
+	.validate = sxe2_flow_validate,
+	.create = sxe2_flow_create,
+	.destroy = sxe2_flow_destroy,
+	.flush = sxe2_flow_flush,
+	.query = sxe2_flow_query,
+	.isolate = sxe2_flow_isolate,
+};
+
+int32_t sxe2_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops)
+{
+	int32_t ret = 0;
+
+	if (dev == NULL) {
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	*ops = &sxe2_flow_ops;
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_flow_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+	TAILQ_INIT(&adapter->flow_ctxt.rte_flow_list);
+	TAILQ_INIT(&adapter->flow_ctxt.hw_res.fnav_cid_mgr_list);
+	if (adapter->devargs.fnav_stat_type)
+		adapter->flow_ctxt.hw_res.count_type =
+			adapter->devargs.fnav_stat_type;
+	else
+		adapter->flow_ctxt.hw_res.count_type = SXE2_FNAV_STAT_ENA_ALL;
+
+	adapter->flow_ctxt.fnav_inited = 1;
+	rte_spinlock_init(&adapter->flow_ctxt.flow_list_lock);
+	return ret;
+}
+
+int32_t sxe2_flow_uninit(struct rte_eth_dev *dev)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_flow_error error;
+	struct sxe2_fnav_cid_mgr *mgr = NULL;
+	struct sxe2_fnav_cid_mgr *temp = NULL;
+	struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+						&adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+
+	ret = sxe2_flow_flush(dev, &error);
+	if (ret)
+		PMD_LOG_ERR(DRV, "Failed to flush flow, ret: %d.", ret);
+
+	TAILQ_FOREACH_SAFE(mgr, cid_mgr_list, next, temp) {
+		TAILQ_REMOVE(cid_mgr_list, mgr, next);
+		ret = sxe2_drv_flow_fnav_free_stat(adapter, mgr->stat_index);
+		if (ret)
+			PMD_LOG_ERR(DRV,
+				"Failed to free fnav stat id, ret: %d.", ret);
+		rte_free(mgr);
+	}
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow.h b/drivers/net/sxe2/sxe2_flow.h
new file mode 100644
index 0000000000..9970fddcf0
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_FLOW_H__
+#define __SXE2_FLOW_H__
+#include <rte_flow_driver.h>
+#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);
+
+int32_t sxe2_flow_uninit(struct rte_eth_dev *dev);
+
+int32_t sxe2_fnav_get_filter_cid(struct sxe2_adapter *adapter, struct sxe2_flow *flow);
+
+int32_t sxe2_flow_free_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_query_mgr(struct sxe2_adapter *adapter,
+			struct sxe2_flow *flow,
+			struct sxe2_fnav_cid_mgr **mgr_ptr,
+			struct rte_flow_error *error);
+#endif /* __SXE2_FLOW_H__ */
diff --git a/drivers/net/sxe2/sxe2_flow_parse_action.c b/drivers/net/sxe2/sxe2_flow_parse_action.c
new file mode 100644
index 0000000000..a9559e2d7e
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_action.c
@@ -0,0 +1,1182 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_flow_parse_action.h"
+#include "sxe2_common_log.h"
+#include "sxe2_flow_public.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_vsi.h"
+
+
+static int32_t sxe2_flow_check_rss_action_attr(const struct rte_flow_action_rss *rss,
+					   struct rte_flow_error *error)
+{
+	int32_t ret = ENOTSUP;
+	switch (rss->func) {
+	case RTE_ETH_HASH_FUNCTION_DEFAULT:
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+	case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ:
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		break;
+	default:
+		PMD_LOG_ERR(DRV, "RSS hash function[%d] not support.", rss->func);
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (rss->level > 2)
+		rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"RSS  level is could not be greater than 2");
+	if (rss->key_len)
+		rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"a nonzero RSS key_len is not supported");
+	if (rss->queue_num)
+		rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"a non-NULL RSS queue is not supported");
+	ret = 0;
+l_end:
+	return ret;
+}
+
+
+static int32_t sxe2_flow_set_rss_action_func(enum rte_eth_hash_function rss_func,
+					 uint64_t rss_type,
+					 struct sxe2_flow *flow,
+					 struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	if (rss_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (flow->has_hdr) {
+			ret = -EINVAL;
+			rte_flow_error_set(error, -EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Failed to cfg Simple XOR hash with not empty pattern");
+			PMD_LOG_ERR(DRV, "Failed to cfg Simple XOR hash with not empty pattern.");
+			goto l_end;
+		}
+	} else {
+		if (!flow->has_hdr) {
+			ret = -EINVAL;
+			rte_flow_error_set(error, -EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Failed to cfg Simple hash with empty pattern");
+			PMD_LOG_ERR(DRV, "Failed to cfg Simple hash with empty pattern.");
+			goto l_end;
+		}
+	}
+
+	if (rss_func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+		if (rss_type & (RTE_ETH_RSS_L3_SRC_ONLY |
+					RTE_ETH_RSS_L3_DST_ONLY |
+					RTE_ETH_RSS_L4_SRC_ONLY |
+					RTE_ETH_RSS_L4_DST_ONLY)) {
+			ret = -EINVAL;
+			rte_flow_error_set(error, -EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Failed to cfg symm func rss_type l3/l4 only.");
+			PMD_LOG_ERR(DRV, "Failed to cfg symm func rss_type l3/l4 only.");
+			goto l_end;
+		}
+
+		if (!(rss_type & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 |
+					RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_FRAG_IPV6 |
+					RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+					RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+					RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+					RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+					RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+					RTE_ETH_RSS_NONFRAG_IPV6_SCTP))) {
+			ret = -EINVAL;
+			rte_flow_error_set(error, -EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Failed to cfg symm func unsupported rss_type.");
+			PMD_LOG_ERR(DRV, "Failed to cfg symm func unsupported rss_type.");
+			goto l_end;
+		}
+		flow->action.rss.func = SXE2_RSS_HASH_FUNC_SYM_TOEPLITZ;
+	}
+	if (rss_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
+		flow->action.rss.func = SXE2_RSS_HASH_FUNC_XOR;
+	if (rss_func == RTE_ETH_HASH_FUNCTION_DEFAULT)
+		flow->action.rss.func = SXE2_RSS_HASH_FUNC_TOEPLITZ;
+	if (rss_func == RTE_ETH_HASH_FUNCTION_TOEPLITZ)
+		flow->action.rss.func = SXE2_RSS_HASH_FUNC_TOEPLITZ;
+l_end:
+	return ret;
+}
+
+
+static uint64_t sxe2_hash_invalid_comb[] = {
+	RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_UDP,
+	RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP,
+	RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_SCTP,
+	RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_UDP,
+	RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_TCP,
+	RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_SCTP,
+	RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER,
+	RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER,
+	RTE_ETH_RSS_L3_PRE32 | RTE_ETH_RSS_L3_PRE48 | RTE_ETH_RSS_L3_PRE64,
+};
+
+struct sxe2_rss_attr_type {
+	uint64_t attr;
+	uint64_t type;
+};
+
+static struct sxe2_rss_attr_type sxe2_rss_attr_valid_type[] = {
+	{RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY, RTE_ETH_RSS_ETH},
+	{RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY, SXE2_VALID_RSS_L3},
+	{RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY, SXE2_VALID_RSS_L4},
+
+	{RTE_ETH_RSS_L3_PRE32, SXE2_VALID_RSS_IPV6},
+	{RTE_ETH_RSS_L3_PRE48, SXE2_VALID_RSS_IPV6},
+	{RTE_ETH_RSS_L3_PRE64, SXE2_VALID_RSS_IPV6},
+	{SXE2_INVALID_RSS_ATTR, 0}
+};
+
+
+static void sxe2_flow_action_pre(struct sxe2_flow *flow)
+{
+	flow->action.vsi.vsi_index = UINT16_MAX;
+	flow->action.vsi_list.vsi_cnt = 0;
+	sxe2_bitmap_zero(flow->action.vsi_list.vsi_list_map, SXE2_VSI_MAX);
+}
+
+static void sxe2_flow_action_post(struct sxe2_flow *flow, uint8_t action_num[])
+{
+	if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types))
+		action_num[SXE2_FLOW_ACTION_TO_VSI] = 1;
+
+	if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI_LIST, flow->action.act_types))
+		action_num[SXE2_FLOW_ACTION_TO_VSI_LIST] = 1;
+}
+
+
+static void sxe2_flow_action_vsi_merge(struct sxe2_flow *flow, uint16_t add_vsi_id)
+{
+	if (flow->action.vsi_list.vsi_cnt == 0) {
+		if (flow->action.vsi.vsi_index == UINT16_MAX) {
+			flow->action.vsi.vsi_index = add_vsi_id;
+			sxe2_set_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types);
+			goto l_end;
+		}
+
+		if (flow->action.vsi.vsi_index == add_vsi_id)
+			goto l_end;
+
+		sxe2_set_bit(flow->action.vsi.vsi_index, flow->action.vsi_list.vsi_list_map);
+		sxe2_set_bit(add_vsi_id, flow->action.vsi_list.vsi_list_map);
+		flow->action.vsi_list.vsi_cnt = 2;
+		flow->action.vsi.vsi_index = UINT16_MAX;
+		sxe2_clear_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types);
+		sxe2_set_bit(SXE2_FLOW_ACTION_TO_VSI_LIST, flow->action.act_types);
+	}
+
+	if (sxe2_test_bit(add_vsi_id, flow->action.vsi_list.vsi_list_map))
+		goto l_end;
+
+	sxe2_set_bit(add_vsi_id, flow->action.vsi_list.vsi_list_map);
+	flow->action.vsi_list.vsi_cnt++;
+
+l_end:
+	return;
+}
+
+
+static int32_t sxe2_flow_vsi_get_ethdev(struct rte_eth_dev *dev,
+				uint16_t dev_port_id, uint16_t *vsi_index)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_eth_dev *dst_dev;
+	struct sxe2_adapter *dst_adapter;
+	int32_t ret = 0;
+
+	dst_dev = &rte_eth_devices[dev_port_id];
+	if (!dst_dev->data) {
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (!sxe2_ethdev_check(dst_dev)) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "dst dev is not sxe2 ethdev.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	dst_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dst_dev);
+	if (!dst_adapter) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "dst dev adapter is null.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (adapter->dev_info.pci.serial_number != dst_adapter->dev_info.pci.serial_number) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "dst dev sn is miss match current dev.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (adapter->dev_type != SXE2_DEV_T_PF_BOND) {
+		if (adapter->pf_idx != dst_adapter->pf_idx) {
+			PMD_DEV_LOG_ERR(adapter, DRV, "dst dev pf id is miss match current dev.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+
+	if (dst_adapter->is_dev_repr) {
+		if (dst_adapter->repr_priv_data == NULL) {
+			PMD_DEV_LOG_ERR(adapter, DRV, "dst dev repr data is null.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		*vsi_index = dst_adapter->repr_priv_data->repr_vf_vsi_id;
+	} else {
+		*vsi_index = dst_adapter->vsi_ctxt.dpdk_vsi_id;
+	}
+
+l_end:
+	return ret;
+}
+static int32_t sxe2_flow_check_rss_action_type_with_pattern(struct sxe2_flow_pattern *pattern,
+							uint64_t rss_type)
+{
+	uint64_t rss_type_allow = pattern->rss_type_allow;
+	int32_t ret = -EINVAL;
+
+	if ((rss_type & rss_type_allow) != rss_type)
+		goto l_end;
+
+	if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, pattern->hdrs) &&
+		!sxe2_test_bit(SXE2_FLOW_HDR_QINQ, pattern->hdrs)) {
+		if ((rss_type & RTE_ETH_RSS_C_VLAN) != 0 &&
+			(rss_type & RTE_ETH_RSS_S_VLAN) == 0)
+			goto l_end;
+	}
+	ret = 0;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_check_rss_action_type_valid(uint64_t rss_type)
+{
+	struct sxe2_rss_attr_type *attr_type;
+	uint32_t i;
+	int32_t ret = -EINVAL;
+
+	for (i = 0; i < RTE_DIM(sxe2_hash_invalid_comb); i++) {
+		if (rte_popcount64(rss_type & sxe2_hash_invalid_comb[i]) > 1) {
+			PMD_LOG_ERR(DRV, "Error rss_type invalid comb[%d].", i);
+			goto l_end;
+		}
+	}
+
+	for (i = 0; i < RTE_DIM(sxe2_rss_attr_valid_type); i++) {
+		attr_type = &sxe2_rss_attr_valid_type[i];
+		if ((attr_type->attr & rss_type) &&
+				!(attr_type->type & rss_type)) {
+			PMD_LOG_ERR(DRV, "Rss_type valid_comb[%d] check error.", i);
+			goto l_end;
+		}
+	}
+
+	ret = 0;
+l_end:
+	return ret;
+}
+
+
+static void sxe2_flow_set_rss_action_type_l234(BITMAP_TYPE *hdr,
+					       BITMAP_TYPE *fld,
+					       uint64_t rss_type)
+{
+	if (rss_type & RTE_ETH_RSS_ETH) {
+		if (rss_type & RTE_ETH_RSS_L2_SRC_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, fld);
+		} else if (rss_type & RTE_ETH_RSS_L2_DST_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, fld);
+		} else {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, fld);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, fld);
+		}
+	}
+	if (rss_type & RTE_ETH_RSS_L2_PAYLOAD) {
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, fld);
+		sxe2_set_bit(SXE2_FLOW_HDR_ETH_NON_IP, hdr);
+	}
+
+	if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, hdr)) {
+		if (rss_type & RTE_ETH_RSS_S_VLAN)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, fld);
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_QINQ, hdr)) {
+		if (rss_type & RTE_ETH_RSS_C_VLAN)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, fld);
+	}
+
+	if (rss_type & (RTE_ETH_RSS_IPV4 |
+				RTE_ETH_RSS_NONFRAG_IPV4_OTHER |
+				RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+				RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+				RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+				RTE_ETH_RSS_FRAG_IPV4 |
+				RTE_ETH_RSS_IPV4_CHKSUM)) {
+		if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, fld);
+		} else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, fld);
+		} else {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, fld);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, fld);
+		}
+
+		if (rss_type & RTE_ETH_RSS_NONFRAG_IPV4_OTHER)
+			sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, hdr);
+		if (rss_type & RTE_ETH_RSS_FRAG_IPV4) {
+			sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, hdr);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_ID, fld);
+		}
+
+		if (rss_type & RTE_ETH_RSS_IPV4_CHKSUM)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_CHKSUM, fld);
+	}
+
+	if (rss_type & (RTE_ETH_RSS_IPV6 |
+				RTE_ETH_RSS_FRAG_IPV6 |
+				RTE_ETH_RSS_NONFRAG_IPV6_OTHER |
+				RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+				RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+				RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+		if (rss_type & RTE_ETH_RSS_L3_PRE32) {
+			if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_SA, fld);
+			} else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_DA, fld);
+			} else {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_SA, fld);
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_DA, fld);
+			}
+		} else if (rss_type & RTE_ETH_RSS_L3_PRE48) {
+			if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_SA, fld);
+			} else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_DA, fld);
+			} else {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_SA, fld);
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_DA, fld);
+			}
+		} else if (rss_type & RTE_ETH_RSS_L3_PRE64) {
+			if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_SA, fld);
+			} else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_DA, fld);
+			} else {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_SA, fld);
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_DA, fld);
+			}
+		} else {
+			if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, fld);
+			} else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, fld);
+			} else {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, fld);
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, fld);
+			}
+		}
+		if (rss_type & RTE_ETH_RSS_FRAG_IPV6) {
+			sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, hdr);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_ID, fld);
+		}
+		if (rss_type & RTE_ETH_RSS_NONFRAG_IPV6_OTHER)
+			sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, hdr);
+	}
+
+	if (rss_type & (RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+				RTE_ETH_RSS_NONFRAG_IPV6_TCP)) {
+		if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, fld);
+		} else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, fld);
+		} else {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, fld);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, fld);
+		}
+		if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_CHKSUM, fld);
+	}
+
+	if (rss_type & (RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+				RTE_ETH_RSS_NONFRAG_IPV6_UDP)) {
+		if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, fld);
+		} else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, fld);
+		} else {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, fld);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, fld);
+		}
+		if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_CHKSUM, fld);
+	}
+
+	if (rss_type & (RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+				RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+		if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, fld);
+		} else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY) {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, fld);
+		} else {
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, fld);
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, fld);
+		}
+		if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_CHKSUM, fld);
+	}
+}
+
+
+static int32_t sxe2_flow_set_rss_action_hdr_type(struct sxe2_flow *flow,
+		bool is_inner)
+{
+	struct sxe2_flow_action_rss *rss = &flow->action.rss;
+	BITMAP_TYPE *hdr = rss->hdr_out;
+	int32_t ret = 0;
+
+	rss->hdr_type = SXE2_RSS_ANY_HEADERS;
+	if (!is_inner) {
+		rss->hdr_type = SXE2_RSS_OUTER_HEADERS;
+		goto l_end;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, hdr)) {
+		if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, hdr)) {
+			if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GRE;
+			} else if (sxe2_test_bit(SXE2_FLOW_HDR_GENEVE, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GENEVE;
+			} else if (sxe2_test_bit(SXE2_FLOW_HDR_VXLAN, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_VXLAN;
+			} else if (sxe2_test_bit(SXE2_FLOW_HDR_GTPU, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GTPU;
+			}
+		} else {
+			if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_GRE;
+			} else {
+				rss->hdr_type = SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4;
+			}
+		}
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, hdr)) {
+		if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, hdr)) {
+			if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GRE;
+			} else if (sxe2_test_bit(SXE2_FLOW_HDR_GENEVE, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GENEVE;
+			} else if (sxe2_test_bit(SXE2_FLOW_HDR_VXLAN, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_VXLAN;
+			} else if (sxe2_test_bit(SXE2_FLOW_HDR_GTPU, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GTPU;
+			}
+		} else {
+			if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+				rss->hdr_type =
+					SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_GRE;
+			} else {
+				rss->hdr_type = SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6;
+			}
+		}
+	}
+
+l_end:
+	if (rss->hdr_type == SXE2_RSS_ANY_HEADERS) {
+		ret = -EINVAL;
+		PMD_LOG_ERR(DRV, "Unsupported rss hdr type.");
+	}
+	return ret;
+}
+
+static int32_t sxe2_flow_set_rss_action_level(uint32_t level,
+		struct sxe2_flow *flow, struct rte_flow_error *error)
+{
+	bool is_inner = false;
+	struct sxe2_flow_action_rss *rss = &flow->action.rss;
+	int32_t ret = 0;
+
+	if (flow->meta.tunnel_type != SXE2_FLOW_TUNNEL_TYPE_NONE) {
+		if (level == 0 || level == 2)
+			is_inner = true;
+		else if (level == 1)
+			is_inner = false;
+	} else {
+		if (level == 2) {
+			ret = -EINVAL;
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"RSS hash level 2 is not allowed no tunnel flow.");
+			PMD_LOG_ERR(DRV, "RSS hash level 2 is not allowed no tunnel flow.");
+			goto l_end;
+		}
+		is_inner = false;
+	}
+	rss->is_inner = is_inner;
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_set_rss_action_type(uint64_t rss_type,
+		struct sxe2_flow *flow, struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+	struct sxe2_flow_pattern *pattern = NULL;
+	struct sxe2_flow_action_rss *rss = &flow->action.rss;
+	BITMAP_TYPE *hdr;
+	BITMAP_TYPE *fld;
+	bool is_inner = rss->is_inner;
+
+	ret = sxe2_flow_check_rss_action_type_valid(rss_type);
+	if (ret) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"RSS hash type has invalid combination.");
+		PMD_LOG_ERR(DRV, "RSS hash type has invalid combination.");
+		goto l_end;
+	}
+
+	pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	ret = sxe2_flow_check_rss_action_type_with_pattern(pattern,
+			rss_type);
+	if (ret) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"RSS hash type is not allowed by pattern.");
+		PMD_LOG_ERR(DRV, "RSS hash type is not allowed by pattern.");
+		goto l_end;
+	}
+
+	sxe2_bitmap_copy(rss->hdr_out, flow->pattern_outer.hdrs,
+			SXE2_FLOW_HDR_MAX);
+	sxe2_bitmap_copy(rss->hdr_in, flow->pattern_inner.hdrs,
+			SXE2_FLOW_HDR_MAX);
+	hdr = is_inner ? rss->hdr_in : rss->hdr_out;
+	fld = rss->fld;
+	sxe2_flow_set_rss_action_type_l234(hdr, fld, rss_type);
+
+	ret = sxe2_flow_set_rss_action_hdr_type(flow, is_inner);
+	if (ret) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Unsupported rss hdr type.");
+		PMD_LOG_ERR(DRV, "Unsupported rss hdr type.");
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_action_rss(const struct rte_flow_action *action,
+				      struct rte_flow_error *error,
+				      struct sxe2_flow *flow)
+{
+	const struct rte_flow_action_rss *rss = action->conf;
+	int32_t ret = 0;
+	uint64_t rss_type = rss->types;
+	enum rte_eth_hash_function rss_func = rss->func;
+	uint32_t level = rss->level;
+
+	rss_type = rte_eth_rss_hf_refine(rss_type);
+
+	ret = sxe2_flow_check_rss_action_attr(rss, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_set_rss_action_func(rss_func, rss_type, flow, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_set_rss_action_level(level, flow, error);
+	if (ret)
+		goto l_end;
+
+	ret = sxe2_flow_set_rss_action_type(rss_type, flow, error);
+	if (ret)
+		goto l_end;
+	sxe2_set_bit(SXE2_FLOW_ACTION_RSS, flow->action.act_types);
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_action_qregion(struct rte_eth_dev *dev,
+		const struct rte_flow_action *action,
+		struct rte_flow_error *error, struct sxe2_flow *flow)
+{
+	int32_t ret = 0;
+	uint8_t i = 0;
+	const struct rte_flow_action_rss *rss = action->conf;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (rss->types != 0 || rss->key_len != 0) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Queue region not support rss types or key.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (rss->queue_num <= 1) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Queue region size can't be 0 or 1.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	for (i = 0; i < rss->queue_num - 1; i++) {
+		if (rss->queue[i + 1] != rss->queue[i] + 1) {
+			rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+					action, "Queue index for queue region is not continuous.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+	if (rss->queue[rss->queue_num - 1] >= adapter->dev_info.dev_data->nb_rx_queues) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Queue index for queue region is out of range.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (!(rte_is_power_of_2(rss->queue_num))) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Queue region size must be power of 2.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	flow->action.q_region.vsi_index = adapter->vsi_ctxt.dpdk_vsi_id;
+	flow->action.q_region.q_index = rss->queue[0];
+	flow->action.q_region.region = (uint8_t)rte_log2_u32(rss->queue_num);
+	sxe2_set_bit(SXE2_FLOW_ACTION_Q_REGION, flow->action.act_types);
+l_end:
+	return ret;
+}
+
+
+static int32_t sxe2_flow_parse_action_queue(struct rte_eth_dev *dev,
+					const struct rte_flow_action *action,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow)
+{
+	int32_t ret = 0;
+	const struct rte_flow_action_queue *queue = action->conf;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (queue->index >= adapter->dev_info.dev_data->nb_rx_queues) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+			action, "Invalid queue index.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	flow->action.queue.vsi_index = adapter->vsi_ctxt.dpdk_vsi_id;
+	flow->action.queue.q_index = queue->index;
+	sxe2_set_bit(SXE2_FLOW_ACTION_QUEUE, flow->action.act_types);
+l_end:
+	return ret;
+}
+
+
+static int32_t sxe2_flow_parse_action_represented_port(struct rte_eth_dev *dev,
+						   const struct rte_flow_action *action,
+						   struct rte_flow_error *error,
+						   struct sxe2_flow *flow)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	const struct rte_flow_action_ethdev *action_ethdev_conf;
+	const struct rte_eth_dev *dst_repr_dev;
+	uint16_t dst_repr_vsi_id;
+	uint16_t dst_backer_port_id;
+	uint16_t src_backer_port_id;
+	int32_t ret = 0;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Represented port action only support in switchdev mode.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (adapter->dev_type == SXE2_DEV_T_VF) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Failed to cfg vf dev type.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	action_ethdev_conf = action->conf;
+	if (!rte_eth_dev_is_valid_port(action_ethdev_conf->port_id)) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Invalid port for represented port action.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	dst_repr_dev = &rte_eth_devices[action_ethdev_conf->port_id];
+	if (!dst_repr_dev->data) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Invalid port for represented port action.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	dst_backer_port_id = dst_repr_dev->data->backer_port_id;
+	if (adapter->is_dev_repr)
+		src_backer_port_id = dev->data->backer_port_id;
+	else
+		src_backer_port_id = adapter->dev_port_id;
+
+	if (src_backer_port_id != dst_backer_port_id) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Represented port action only support to cfg port in same device.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_flow_vsi_get_ethdev(dev, action_ethdev_conf->port_id, &dst_repr_vsi_id);
+	if (ret != 0) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION,
+			action, "Port representor action port dev invalid.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	sxe2_flow_action_vsi_merge(flow, dst_repr_vsi_id);
+l_end:
+	return ret;
+}
+
+
+static int32_t sxe2_flow_parse_action_port_representor(struct rte_eth_dev *dev,
+						   const struct rte_flow_action *action,
+						   struct rte_flow_error *error,
+						   struct sxe2_flow *flow)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	const struct rte_flow_action_ethdev *action_ethdev_conf;
+	uint16_t dst_vsi_id;
+	int32_t ret = 0;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Port representor action only support in switchdev mode.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (adapter->dev_type == SXE2_DEV_T_VF) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Cfg rule dev type is vf.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (!adapter->is_dev_repr) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Cfg rule dev type is not repr.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	action_ethdev_conf = action->conf;
+	if (!action_ethdev_conf || !rte_eth_dev_is_valid_port(action_ethdev_conf->port_id)) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Invalid port for port representor action.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (dev->data->backer_port_id != action_ethdev_conf->port_id) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Invalid port for port representor.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_flow_vsi_get_ethdev(dev, action_ethdev_conf->port_id, &dst_vsi_id);
+	if (ret != 0) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION,
+			action, "Port representor action port dev invalid.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	sxe2_flow_action_vsi_merge(flow, dst_vsi_id);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_flow_parse_action_port_id(struct rte_eth_dev *dev,
+				   const struct rte_flow_action *action,
+				   struct rte_flow_error *error,
+				   struct sxe2_flow *flow)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	const struct rte_flow_action_port_id *action_port_id_conf;
+	uint16_t dst_port_id;
+	uint16_t dst_vsi_id;
+	int32_t ret = 0;
+
+	action_port_id_conf = (const struct rte_flow_action_port_id *)action->conf;
+	dst_port_id = action_port_id_conf->original ?
+			adapter->dev_port_id : action_port_id_conf->id;
+
+	if (!rte_eth_dev_is_valid_port(dst_port_id)) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				action, "Invalid port id.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	ret = sxe2_flow_vsi_get_ethdev(dev, dst_port_id, &dst_vsi_id);
+	if (ret != 0) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, action,
+			"Failed to cfg port dev invalid.");
+		goto l_end;
+	}
+
+	sxe2_flow_action_vsi_merge(flow, dst_vsi_id);
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_action_send_to_kernel(struct rte_eth_dev *dev,
+			const struct rte_flow_action *action, struct rte_flow_error *error,
+			struct sxe2_flow *flow)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	int32_t ret = 0;
+
+	if (adapter->vsi_ctxt.kernel_vsi_id == UINT16_MAX) {
+		rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, action,
+			"Failed to cfg send to kernel action without kernel vsi.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	sxe2_flow_action_vsi_merge(flow, adapter->vsi_ctxt.kernel_vsi_id);
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_flow_check_actions(struct rte_eth_dev *dev __rte_unused, struct sxe2_flow *flow,
+				   uint8_t action_num[], struct rte_flow_error *error)
+{
+	enum sxe2_flow_engine_type engine_type = flow->engine_type;
+	int32_t ret = 0;
+	int32_t dest_num = action_num[SXE2_FLOW_ACTION_Q_REGION] +
+			   action_num[SXE2_FLOW_ACTION_QUEUE];
+	int32_t vsi_num = action_num[SXE2_FLOW_ACTION_TO_VSI];
+	int32_t vsi_list_num = action_num[SXE2_FLOW_ACTION_TO_VSI_LIST];
+	int32_t pass_num = action_num[SXE2_FLOW_ACTION_PASSTHRU];
+	int32_t drop_num = action_num[SXE2_FLOW_ACTION_DROP];
+	int32_t mark_num = action_num[SXE2_FLOW_ACTION_MARK];
+	int32_t count_num = action_num[SXE2_FLOW_ACTION_COUNT];
+	int32_t rss_num = action_num[SXE2_FLOW_ACTION_RSS];
+	int32_t fwd_num = dest_num + vsi_num + vsi_list_num;
+	int32_t total_num = dest_num + vsi_num + vsi_list_num + pass_num +
+			drop_num + mark_num + count_num + rss_num;
+
+	if (pass_num > 1 || drop_num > 1 || mark_num > 1 ||
+			count_num > 1 || rss_num > 1 || dest_num > 1 ||
+			vsi_num > 1 || vsi_list_num > 1) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"ecah action can only be used once.");
+		PMD_LOG_ERR(DRV, "ecah action can only be used once.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (vsi_list_num && engine_type != SXE2_FLOW_ENGINE_SWITCH) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"VSI_LIST action is only supported for switch engine.");
+		PMD_LOG_ERR(DRV, "VSI_LIST action is only supported for switch engine.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (drop_num) {
+		if (total_num > drop_num + count_num) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Drop action can't be used with other actions unless count.");
+			PMD_LOG_ERR(DRV,
+				"Drop action can't be used with other actions unless count.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+
+	if (fwd_num > 1) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Only supports one type of forwarding action.");
+		PMD_LOG_ERR(DRV, "Only supports one type of forwarding action.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (vsi_list_num) {
+		if (total_num > vsi_list_num) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"VSI_LIST action can't be used with other actions.");
+			PMD_LOG_ERR(DRV,
+				"VSI_LIST action can't be used with other actions.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+
+	if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+		if (vsi_num) {
+			flow->action.q_region.q_index = 0;
+			flow->action.q_region.region = 7;
+			flow->action.q_region.vsi_index = flow->action.vsi.vsi_index;
+			sxe2_set_bit(SXE2_FLOW_ACTION_Q_REGION, flow->action.act_types);
+			dest_num++;
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+
+int32_t sxe2_flow_parse_action(struct rte_eth_dev *dev,
+			const struct rte_flow_action actions[],
+			struct rte_flow_error *error,
+			struct sxe2_flow *flow)
+{
+	int32_t ret = 0;
+	const struct rte_flow_action *action;
+	const struct rte_flow_action_count *act_count;
+	const struct rte_flow_action_mark *act_mark;
+	uint8_t action_num[SXE2_FLOW_ACTION_MAX] = {0};
+	enum sxe2_flow_engine_type engine_type = flow->engine_type;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	sxe2_flow_action_pre(flow);
+
+	for (action = actions; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
+		switch (action->type) {
+		case RTE_FLOW_ACTION_TYPE_VOID:
+			break;
+		case RTE_FLOW_ACTION_TYPE_PASSTHRU:
+			if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				sxe2_set_bit(SXE2_FLOW_ACTION_PASSTHRU, flow->action.act_types);
+				action_num[SXE2_FLOW_ACTION_PASSTHRU]++;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"Passthru action is not supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"Passthru action is not supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_DROP:
+			if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+				engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+				engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				sxe2_set_bit(SXE2_FLOW_ACTION_DROP, flow->action.act_types);
+				action_num[SXE2_FLOW_ACTION_DROP]++;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"Drop action is not supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"Drop action is not supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_MARK:
+			if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				sxe2_set_bit(SXE2_FLOW_ACTION_MARK, flow->action.act_types);
+				act_mark = action->conf;
+				flow->action.mark.mark_id = act_mark->id;
+				action_num[SXE2_FLOW_ACTION_MARK]++;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"Mark action is not supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"Mark action is not supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_COUNT:
+			if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				sxe2_set_bit(SXE2_FLOW_ACTION_COUNT, flow->action.act_types);
+				act_count = action->conf;
+				flow->action.count.user_id = act_count->id;
+				flow->action.count.driver_id = 0;
+				if (flow->action.count.user_id == 0)
+					flow->action.count.driver_id =
+						++adapter->flow_ctxt.hw_res.global_index;
+				action_num[SXE2_FLOW_ACTION_COUNT]++;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"Count action is not supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"Count action is not supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_RSS:
+			if (engine_type == SXE2_FLOW_ENGINE_RSS) {
+				ret = sxe2_flow_parse_action_rss(action, error, flow);
+				if (ret != 0)
+					goto l_end;
+				action_num[SXE2_FLOW_ACTION_RSS]++;
+			} else if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+				engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+				engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				ret = sxe2_flow_parse_action_qregion(dev, action, error, flow);
+				if (ret != 0)
+					goto l_end;
+				action_num[SXE2_FLOW_ACTION_Q_REGION]++;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"RSS action is only supported for RSS flow.");
+				PMD_LOG_ERR(DRV,
+					"RSS action is only supported for RSS flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_QUEUE:
+			if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+				engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+				engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				ret = sxe2_flow_parse_action_queue(dev, action, error, flow);
+				if (ret != 0)
+					goto l_end;
+				action_num[SXE2_FLOW_ACTION_QUEUE]++;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"Queue action is not supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"Queue action is not supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
+			if (engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+				ret = sxe2_flow_parse_action_represented_port(dev,
+					action, error, flow);
+				if (ret != 0)
+					goto l_end;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"REPRESENTED PORT action is only supported for SWITCH flow.");
+				PMD_LOG_ERR(DRV,
+					"REPRESENTED PORT action is only supported for SWITCH flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR:
+			if (engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+				ret = sxe2_flow_parse_action_port_representor(dev,
+					action, error, flow);
+				if (ret != 0)
+					goto l_end;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"PORT REPRESENTOR action is only supported for SWITCH flow.");
+				PMD_LOG_ERR(DRV,
+					"PORT REPRESENTOR action is only supported for SWITCH flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			if (engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+				engine_type == SXE2_FLOW_ENGINE_ACL ||
+				engine_type == SXE2_FLOW_ENGINE_FNAV) {
+				ret = sxe2_flow_parse_action_port_id(dev, action,
+						error, flow);
+				if (ret != 0)
+					goto l_end;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"PORT ID action is only supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"PORT ID action is only supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_SEND_TO_KERNEL:
+			if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+				engine_type == SXE2_FLOW_ENGINE_FNAV ||
+				engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+				ret = sxe2_flow_parse_action_send_to_kernel(dev,
+						action, error, flow);
+				if (ret != 0)
+					goto l_end;
+			} else {
+				rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION, action,
+					"SEND TO KERNEL action is only supported for this flow.");
+				PMD_LOG_ERR(DRV,
+					"SEND TO KERNEL action is only supported for this flow.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			break;
+		default:
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, actions,
+				"Invalid action.");
+			PMD_LOG_ERR(DRV, "Invalid action type:%d", actions->type);
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+
+	sxe2_flow_action_post(flow, action_num);
+
+	ret = sxe2_flow_check_actions(dev, flow, action_num, error);
+	if (ret != 0)
+		goto l_end;
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow_parse_action.h b/drivers/net/sxe2/sxe2_flow_parse_action.h
new file mode 100644
index 0000000000..479d10a522
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_action.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_FLOW_PARSE_ACTION_H_
+#define SXE2_FLOW_PARSE_ACTION_H_
+#include <rte_flow_driver.h>
+
+#include "sxe2_osal.h"
+#include "sxe2_flow_define.h"
+
+
+int32_t sxe2_flow_parse_action(struct rte_eth_dev *dev,
+			const struct rte_flow_action actions[],
+			struct rte_flow_error *error,
+			struct sxe2_flow *flow);
+
+int32_t sxe2_flow_parse_action_port_id(struct rte_eth_dev *dev,
+			const struct rte_flow_action *action,
+			struct rte_flow_error *error,
+			struct sxe2_flow *flow);
+
+#endif /* SXE2_FLOW_PARSE_ACTION_H_ */
diff --git a/drivers/net/sxe2/sxe2_flow_parse_engine.c b/drivers/net/sxe2/sxe2_flow_parse_engine.c
new file mode 100644
index 0000000000..09de1b94c4
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_engine.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_flow_parse_engine.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_flow_public.h"
+#include "sxe2_flow_parse_action.h"
+#include "sxe2_common_log.h"
+
+static int32_t sxe2_flow_parse_engine_chk(struct sxe2_flow *flow,
+		struct rte_flow_error *error)
+{
+	int32_t ret = 0;
+
+	if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV) {
+		if (flow->has_mask) {
+			ret = -EINVAL;
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM_MASK, NULL,
+				"FNAV flow doesn't support mask");
+			PMD_LOG_ERR(DRV, "FNAV flow doesn't support mask");
+			goto l_end;
+		}
+		if (sxe2_test_bit(SXE2_FLOW_FLD_ID_S_VID,
+				flow->pattern_outer.map_spec) &&
+			sxe2_test_bit(SXE2_FLOW_FLD_ID_C_VID,
+				flow->pattern_outer.map_spec)) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				"Can't set double vid,please use tci.");
+			PMD_LOG_ERR(DRV,
+				"Can't set double vid,please use tci.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_flow_parse_engine(struct rte_eth_dev *dev,
+		const struct rte_flow_attr *attr,
+		const struct rte_flow_action actions[],
+		struct rte_flow_error *error,
+		struct sxe2_flow *flow)
+{
+	int32_t ret = 0;
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	const struct rte_flow_action *action;
+
+	if (flow->has_mask == 0 && flow->has_spec == 0) {
+		flow->engine_type = SXE2_FLOW_ENGINE_RSS;
+		goto l_end;
+	}
+
+	if (attr->group == 1) {
+		flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+		goto l_end;
+	}
+	if (attr->group == 2) {
+		flow->engine_type = SXE2_FLOW_ENGINE_ACL;
+		goto l_end;
+	}
+	if (attr->group == 3) {
+		flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+		goto l_end;
+	}
+
+	if (adapter->is_dev_repr) {
+		flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+		goto l_end;
+	}
+
+	if (adapter->switchdev_info.is_switchdev &&
+	    adapter->dev_type == SXE2_DEV_T_VF) {
+		flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+		goto l_end;
+	}
+
+	for (action = actions; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
+		switch (action->type) {
+		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
+		case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR:
+		case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+			goto l_end;
+		default:
+			break;
+		}
+	}
+
+	if (adapter->switchdev_info.is_switchdev) {
+		flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+		goto l_end;
+	}
+
+	if (adapter->flow_isolated)
+		flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+	else
+		flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+
+l_end:
+	ret = sxe2_flow_parse_engine_chk(flow, error);
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow_parse_engine.h b/drivers/net/sxe2/sxe2_flow_parse_engine.h
new file mode 100644
index 0000000000..1485beecb4
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_engine.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_FLOW_PARSE_ENGINE_H_
+#define SXE2_FLOW_PARSE_ENGINE_H_
+#include "sxe2_osal.h"
+#include "sxe2_flow_define.h"
+
+int32_t sxe2_flow_parse_engine(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
+			const struct rte_flow_action actions[], struct rte_flow_error *error,
+			struct sxe2_flow *flow);
+#endif /* SXE2_FLOW_PARSE_ENGINE_H_ */
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.c b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
new file mode 100644
index 0000000000..189abb1a33
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
@@ -0,0 +1,1822 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_flow_parse_pattern.h"
+#include "rte_common.h"
+#include "rte_flow.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_flow_define.h"
+
+const struct sxe2_flow_expand_node sxe2_support_expansion[SXE2_EXPANSION_MAX] = {
+	[SXE2_EXPANSION_OUTER_ETH] = {
+		.type = RTE_FLOW_ITEM_TYPE_ETH,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "eth",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_VLAN,
+					      SXE2_EXPANSION_OUTER_IPV4,
+					      SXE2_EXPANSION_OUTER_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_OUTER_VLAN] = {
+		.type = RTE_FLOW_ITEM_TYPE_VLAN,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "vlan",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_QINQ,
+					      SXE2_EXPANSION_OUTER_IPV4,
+					      SXE2_EXPANSION_OUTER_IPV6,
+					      SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_QINQ] = {
+		.type = RTE_FLOW_ITEM_TYPE_VLAN,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "vlan",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_IPV4,
+					      SXE2_EXPANSION_OUTER_IPV6,
+					      SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_IPV4] = {
+		.type = RTE_FLOW_ITEM_TYPE_IPV4,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_IPIP,
+		.is_tunnel = false,
+		.name = "ipv4",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_UDP,
+					      SXE2_EXPANSION_OUTER_TCP,
+					      SXE2_EXPANSION_OUTER_SCTP,
+					      SXE2_EXPANSION_GRE,
+					      SXE2_EXPANSION_NVGRE,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_IPV6] = {
+		.type = RTE_FLOW_ITEM_TYPE_IPV6,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_IPIP,
+		.is_tunnel = false,
+		.name = "ipv6",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT,
+					      SXE2_EXPANSION_OUTER_UDP,
+					      SXE2_EXPANSION_OUTER_TCP,
+					      SXE2_EXPANSION_OUTER_SCTP,
+					      SXE2_EXPANSION_GRE,
+					      SXE2_EXPANSION_NVGRE,
+					      SXE2_EXPANSION_ETH,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT] = {
+		.type = RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "ipv6_frag_ext",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_UDP] = {
+		.type = RTE_FLOW_ITEM_TYPE_UDP,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "udp",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_VXLAN,
+					      SXE2_EXPANSION_VXLAN_GPE,
+					      SXE2_EXPANSION_GENEVE,
+					      SXE2_EXPANSION_GTPU,
+					      SXE2_EXPANSION_GRE,
+					      SXE2_EXPANSION_NVGRE,
+					      SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_TCP] = {
+		.type = RTE_FLOW_ITEM_TYPE_TCP,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "tcp",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_SCTP] = {
+		.type = RTE_FLOW_ITEM_TYPE_SCTP,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "sctp",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_END),
+	},
+	[SXE2_EXPANSION_OUTER_END] = {
+		.type = RTE_FLOW_ITEM_TYPE_END,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+		.is_tunnel = false,
+		.name = "end",
+		.next = SXE2_FLOW_EXPAND_NEXT(0),
+	},
+	[SXE2_EXPANSION_VXLAN] = {
+		.type = RTE_FLOW_ITEM_TYPE_VXLAN,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_VXLAN,
+		.is_tunnel = true,
+		.name = "vxlan",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_VXLAN_GPE] = {
+		.type = RTE_FLOW_ITEM_TYPE_VXLAN_GPE,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_VXLAN,
+		.is_tunnel = true,
+		.name = "vxlan_gpe",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_GRE] = {
+		.type = RTE_FLOW_ITEM_TYPE_GRE,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GRE,
+		.is_tunnel = true,
+		.name = "gre",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_NVGRE] = {
+		.type = RTE_FLOW_ITEM_TYPE_NVGRE,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GRE,
+		.is_tunnel = true,
+		.name = "nvgre",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_GENEVE] = {
+		.type = RTE_FLOW_ITEM_TYPE_GENEVE,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GENEVE,
+		.is_tunnel = true,
+		.name = "geneve",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_GTPU] = {
+		.type = RTE_FLOW_ITEM_TYPE_GTPU,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GTPU,
+		.is_tunnel = true,
+		.name = "gtpu",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_ETH] = {
+		.type = RTE_FLOW_ITEM_TYPE_ETH,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "eth",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_VLAN,
+					      SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_VLAN] = {
+		.type = RTE_FLOW_ITEM_TYPE_VLAN,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "vlan",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_IPV4,
+					      SXE2_EXPANSION_IPV6,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_IPV4] = {
+		.type = RTE_FLOW_ITEM_TYPE_IPV4,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "ipv4",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_UDP,
+					      SXE2_EXPANSION_TCP,
+					      SXE2_EXPANSION_SCTP,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_IPV6] = {
+		.type = RTE_FLOW_ITEM_TYPE_IPV6,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "ipv6",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_UDP,
+					      SXE2_EXPANSION_TCP,
+					      SXE2_EXPANSION_SCTP,
+					      SXE2_EXPANSION_IPV6_FRAG_EXT,
+					      SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_UDP] = {
+		.type = RTE_FLOW_ITEM_TYPE_UDP,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "udp",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_TCP] = {
+		.type = RTE_FLOW_ITEM_TYPE_TCP,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "tcp",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_SCTP] = {
+		.type = RTE_FLOW_ITEM_TYPE_SCTP,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "sctp",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_IPV6_FRAG_EXT] = {
+		.type = RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "ipv6_frag_ext",
+		.next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+	},
+	[SXE2_EXPANSION_END] = {
+		.type = RTE_FLOW_ITEM_TYPE_END,
+		.tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+		.is_tunnel = true,
+		.name = "end",
+		.next = SXE2_FLOW_EXPAND_NEXT(0),
+	}
+};
+
+const char *sxe2_flow_type_name[SXE2_FLOW_TYPE_MAX] = {
+	[SXE2_FLOW_MAC_PAY] = "SXE2_FLOW_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_FRAG_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_UDP_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_TCP_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_SCTP_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_FRAG_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_UDP_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_TCP_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_SCTP_PAY] =
+	"SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_FRAG_PAY] =
+	"SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_SCTP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_FRAG_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_UDP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_TCP_PAY",
+	[SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_SCTP_PAY",
+};
+#define SXE2_FLOW_TYPE_NAME_MAX_LEN 128
+
+static int32_t sxe2_flow_get_flow_type(struct sxe2_flow *flow)
+{
+	int32_t ret = -EINVAL;
+	uint16_t i = 0;
+	uint16_t len = 0;
+	char flow_type_name[SXE2_FLOW_TYPE_NAME_MAX_LEN] = {0};
+	len = snprintf(flow_type_name, sizeof(flow_type_name), "SXE2_FLOW_");
+	i += len;
+	if (sxe2_test_bit(SXE2_FLOW_HDR_ETH, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"MAC_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"IPV4_");
+		i += len;
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"IPV6_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV_FRAG, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"FRAG_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"UDP_");
+		i += len;
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_TCP, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"TCP_");
+		i += len;
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_SCTP, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"SCTP_");
+		i += len;
+	}
+
+	if (sxe2_test_bit(SXE2_FLOW_HDR_VXLAN, flow->pattern_outer.hdrs) ||
+	    sxe2_test_bit(SXE2_FLOW_HDR_GENEVE, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"VXGEN_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"GRE_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_GTPU, flow->pattern_outer.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"GTPU_");
+		i += len;
+	}
+
+	if (sxe2_test_bit(SXE2_FLOW_HDR_ETH, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"MAC_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"VLAN_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"IPV4_");
+		i += len;
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"IPV6_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV_FRAG, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"FRAG_");
+		i += len;
+	}
+	if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"UDP_");
+		i += len;
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_TCP, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"TCP_");
+		i += len;
+	} else if (sxe2_test_bit(SXE2_FLOW_HDR_SCTP, flow->pattern_inner.hdrs)) {
+		len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+			"SCTP_");
+		i += len;
+	}
+
+	len = snprintf(flow_type_name + i, sizeof(flow_type_name), "PAY");
+	i += len;
+
+	for (i = 0; i < SXE2_FLOW_TYPE_MAX; i++) {
+		if (sxe2_flow_type_name[i] == NULL)
+			continue;
+		if (strcmp(flow_type_name, sxe2_flow_type_name[i]) == 0) {
+			flow->meta.flow_type = i;
+			ret = 0;
+			break;
+		}
+	}
+	if (ret != 0)
+		PMD_LOG_ERR(DRV,
+			"Unsupported flow type. %s is not supported.", flow_type_name);
+	return ret;
+}
+
+static int32_t sxe2_flow_is_expandable_item(const struct rte_flow_item *item)
+{
+	int32_t ret = -EINVAL;
+	switch (item->type) {
+	case RTE_FLOW_ITEM_TYPE_ETH:
+	case RTE_FLOW_ITEM_TYPE_VLAN:
+	case RTE_FLOW_ITEM_TYPE_IPV4:
+	case RTE_FLOW_ITEM_TYPE_IPV6:
+	case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
+	case RTE_FLOW_ITEM_TYPE_UDP:
+	case RTE_FLOW_ITEM_TYPE_TCP:
+	case RTE_FLOW_ITEM_TYPE_SCTP:
+	case RTE_FLOW_ITEM_TYPE_VXLAN:
+	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+	case RTE_FLOW_ITEM_TYPE_GRE:
+	case RTE_FLOW_ITEM_TYPE_NVGRE:
+	case RTE_FLOW_ITEM_TYPE_GENEVE:
+	case RTE_FLOW_ITEM_TYPE_GTPU:
+	case RTE_FLOW_ITEM_TYPE_VOID:
+	case RTE_FLOW_ITEM_TYPE_END:
+		ret = 0;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int32_t sxe2_flow_valid_next_expansion(enum sxe2_expansion *current,
+	const struct rte_flow_item *item,
+	enum sxe2_flow_tunnel_type *tunnel_type, BITMAP_TYPE *flow_type)
+{
+	int32_t ret = -EINVAL;
+	const struct rte_flow_item *next;
+	const enum sxe2_expansion *next_expansion = current;
+	const struct sxe2_flow_expand_node *node;
+	uint8_t len = 0;
+	char typelist[512] = {0};
+	char error[1024] = {0};
+	enum sxe2_flow_tunnel_type tunnel_type_now = SXE2_FLOW_TUNNEL_TYPE_NONE;
+	enum sxe2_flow_tunnel_type tunnel_type_next = SXE2_FLOW_TUNNEL_TYPE_NONE;
+	uint8_t is_tunnel_now = 0;
+	uint8_t is_tunnel_next = 0;
+
+	if (item->type != sxe2_support_expansion[*current].type) {
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	next = item;
+	do {
+		next++;
+		if (next->type == RTE_FLOW_ITEM_TYPE_VOID)
+			continue;
+		break;
+	} while (1);
+
+	node = &sxe2_support_expansion[*current];
+	next_expansion = node->next;
+	while (*next_expansion != 0) {
+		len = strlen(typelist);
+		snprintf(typelist + len, sizeof(typelist) - len,
+			"%s|", sxe2_support_expansion[*next_expansion].name);
+		if (sxe2_support_expansion[*next_expansion].type == next->type) {
+			ret = 0;
+			break;
+		}
+		next_expansion++;
+	}
+	if (ret != 0) {
+		snprintf(error, sizeof(error),
+			"The next item of %s only can be one of [%s].",
+			sxe2_support_expansion[*current].name, typelist);
+		PMD_LOG_ERR(INIT, "Invalid pattern sequence. %s", error);
+		goto l_end;
+	}
+	tunnel_type_now = sxe2_support_expansion[*current].tunnel_type;
+	tunnel_type_next = sxe2_support_expansion[*next_expansion].tunnel_type;
+	is_tunnel_now = sxe2_support_expansion[*current].is_tunnel;
+	is_tunnel_next = sxe2_support_expansion[*next_expansion].is_tunnel;
+
+
+	if (!is_tunnel_now && is_tunnel_next) {
+		if (tunnel_type_next == SXE2_FLOW_TUNNEL_TYPE_PARENT)
+			*tunnel_type = tunnel_type_now;
+		else
+			*tunnel_type = tunnel_type_next;
+	}
+
+l_end:
+	sxe2_set_bit(*current, flow_type);
+	*current = *next_expansion;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_eth(const struct rte_flow_item *item,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow,
+					enum sxe2_expansion next,
+					bool is_inner)
+{
+	const struct rte_flow_item_eth *eth_spec;
+	const struct rte_flow_item_eth *eth_mask;
+	const struct rte_ether_addr *dst_addr_mask;
+	const struct rte_ether_addr *src_addr_mask;
+	const struct rte_ether_addr *dst_addr_spec;
+	const struct rte_ether_addr *src_addr_spec;
+	rte_be16_t type_mask;
+	rte_be16_t type_spec;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	uint16_t ether_type;
+	eth_spec = item->spec;
+	eth_mask = item->mask;
+
+	if (eth_spec == NULL && eth_mask == NULL)
+		goto l_end;
+
+	dst_addr_mask = &eth_mask->hdr.dst_addr;
+	src_addr_mask = &eth_mask->hdr.src_addr;
+	dst_addr_spec = &eth_spec->hdr.dst_addr;
+	src_addr_spec = &eth_spec->hdr.src_addr;
+	type_mask = eth_mask->hdr.ether_type;
+	type_spec = eth_spec->hdr.ether_type;
+
+	if (eth_mask->has_vlan) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported eth mask has_vlan.");
+		PMD_LOG_ERR(DRV, "Unsupported eth mask has_vlan");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (!rte_is_zero_ether_addr(dst_addr_mask)) {
+		if (!rte_is_broadcast_ether_addr(dst_addr_mask))
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, pattern->map_mask);
+
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, pattern->map_spec);
+		rte_memcpy(pattern->item_spec.eth.dst_addr, dst_addr_spec,
+			RTE_ETHER_ADDR_LEN);
+		rte_memcpy(pattern->item_mask.eth.dst_addr, dst_addr_mask,
+			RTE_ETHER_ADDR_LEN);
+	}
+	if (!rte_is_zero_ether_addr(src_addr_mask)) {
+		if (!rte_is_broadcast_ether_addr(src_addr_mask))
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, pattern->map_mask);
+
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, pattern->map_spec);
+		rte_memcpy(pattern->item_spec.eth.src_addr, src_addr_spec,
+			RTE_ETHER_ADDR_LEN);
+		rte_memcpy(pattern->item_mask.eth.src_addr, src_addr_mask,
+			RTE_ETHER_ADDR_LEN);
+	}
+	if (type_mask != 0) {
+		if (type_mask != UINT16_MAX) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Unsupported eth ether_type mask");
+			PMD_LOG_ERR(DRV, "unsupported eth ether_type mask[0x%x].",
+				    type_mask);
+			ret = -EINVAL;
+			goto l_end;
+		}
+		if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Unsupported eth ether_type match with next item.");
+			PMD_LOG_ERR(DRV, "unsupported eth ether_type match with next item.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		ether_type = rte_be_to_cpu_16(type_spec);
+		if (ether_type == RTE_ETHER_TYPE_IPV4 ||
+				ether_type == RTE_ETHER_TYPE_IPV6) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Ether_type unsupported ipv4/ipv6(0x0800/0x86DD).");
+			PMD_LOG_ERR(DRV, "Ether_type unsupported ipv4/ipv6(0x0800/0x86DD).");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		if (ether_type == RTE_ETHER_TYPE_VLAN || ether_type == RTE_ETHER_TYPE_QINQ ||
+				ether_type == RTE_ETHER_TYPE_QINQ1) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Ether_type unsupported vlan(0x8100/0x88a8/0x9100).");
+			PMD_LOG_ERR(DRV, "Ether_type unsupported vlan(0x8100/0x88a8/0x9100).");
+			ret = -EINVAL;
+			goto l_end;
+		}
+
+		if (ether_type <= SXE2_FLOW_ETH_TYPE_MIN) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Ether_type need max 1500.");
+			PMD_LOG_ERR(DRV, "Ether_type need max 1500.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, pattern->map_spec);
+		pattern->item_spec.eth.ether_type = type_spec;
+		pattern->item_mask.eth.ether_type = type_mask;
+	}
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_ETH, pattern->hdrs);
+	pattern->rss_type_allow |= RTE_ETH_RSS_ETH;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L2_DST_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L2_SRC_ONLY;
+	if (next == SXE2_EXPANSION_OUTER_END || next == SXE2_EXPANSION_END)
+		pattern->rss_type_allow |= RTE_ETH_RSS_L2_PAYLOAD;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_vlan(const struct rte_flow_item *item,
+				struct rte_flow_error *error,
+				struct sxe2_flow *flow,
+				enum sxe2_expansion next __rte_unused,
+				bool is_inner)
+{
+	const struct rte_flow_item_vlan *vlan_spec;
+	const struct rte_flow_item_vlan *vlan_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	rte_be16_t vlan_tci_mask;
+	rte_be16_t vlan_tci_spec;
+	rte_be16_t eth_proto_mask;
+	rte_be16_t eth_proto_spec;
+	int32_t ret = 0;
+	vlan_spec = item->spec;
+	vlan_mask = item->mask;
+	bool is_qinq = false;
+
+	if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, pattern->hdrs))
+		is_qinq = true;
+
+	if (vlan_spec == NULL && vlan_mask == NULL)
+		goto l_end;
+
+	vlan_tci_mask = vlan_mask->hdr.vlan_tci;
+	vlan_tci_spec = vlan_spec->hdr.vlan_tci;
+	eth_proto_mask = vlan_mask->hdr.eth_proto;
+	eth_proto_spec = vlan_spec->hdr.eth_proto;
+
+	if (vlan_mask->has_more_vlan || vlan_mask->reserved) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported vlan mask has_qinq.");
+		PMD_LOG_ERR(DRV, "Unsupported vlan mask has_qinq");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (vlan_tci_mask) {
+		if (vlan_tci_spec == 0) {
+			rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "vlan id can't be 0.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+
+	if (eth_proto_mask) {
+		if (eth_proto_mask != UINT16_MAX) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Unsupported vlan ether_type mask");
+			PMD_LOG_ERR(DRV, "unsupported vlan ether_type mask.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		if (eth_proto_spec != RTE_BE16(0x8100) &&
+			eth_proto_spec != RTE_BE16(0x88a8) &&
+			eth_proto_spec != RTE_BE16(0x9100)) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "Unsupported vlan ether_type, only support 0x8100, 0x88a8 and 0x9100.");
+			PMD_LOG_ERR(DRV, "Unsupported vlan ether_type, only support 0x8100, 0x88a8 and 0x9100.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+	if (!is_qinq) {
+		if (vlan_tci_mask) {
+			if (vlan_tci_mask == RTE_BE16(0x0fff)) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_S_VID, pattern->map_spec);
+			} else if (vlan_tci_mask == UINT16_MAX) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, pattern->map_spec);
+			} else {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, pattern->map_mask);
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, pattern->map_spec);
+			}
+		}
+		if (eth_proto_mask)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TPID, pattern->map_spec);
+	} else {
+		if (vlan_tci_mask) {
+			if (vlan_tci_mask == RTE_BE16(0x0fff)) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_C_VID, pattern->map_spec);
+			} else if (vlan_tci_mask == UINT16_MAX) {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, pattern->map_spec);
+			} else {
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, pattern->map_mask);
+				sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, pattern->map_spec);
+			}
+		}
+		if (eth_proto_mask)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TPID, pattern->map_spec);
+	}
+	if (is_qinq) {
+		pattern->item_spec.qinq.type =  eth_proto_spec;
+		pattern->item_mask.qinq.type =  eth_proto_mask;
+		pattern->item_spec.qinq.vlan = vlan_tci_spec;
+		pattern->item_mask.qinq.vlan = vlan_tci_mask;
+	} else {
+		pattern->item_spec.vlan.type = eth_proto_spec;
+		pattern->item_mask.vlan.type = eth_proto_mask;
+		pattern->item_spec.vlan.vlan = vlan_tci_spec;
+		pattern->item_mask.vlan.vlan = vlan_tci_mask;
+	}
+l_end:
+	pattern->rss_type_allow |= RTE_ETH_RSS_S_VLAN;
+	pattern->rss_type_allow |= RTE_ETH_RSS_C_VLAN;
+	if (!is_qinq)
+		sxe2_set_bit(SXE2_FLOW_HDR_VLAN, pattern->hdrs);
+	else
+		sxe2_set_bit(SXE2_FLOW_HDR_QINQ, pattern->hdrs);
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_ipv4(const struct rte_flow_item *item,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow,
+					enum sxe2_expansion next,
+					bool is_inner)
+{
+	const struct rte_flow_item_ipv4 *ipv4_spec;
+	const struct rte_flow_item_ipv4 *ipv4_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	ipv4_spec = item->spec;
+	ipv4_mask = item->mask;
+
+	if (ipv4_mask == NULL && ipv4_spec == NULL)
+		goto l_end;
+
+	if (ipv4_mask->hdr.version_ihl || ipv4_mask->hdr.total_length ||
+			ipv4_mask->hdr.hdr_checksum || ipv4_mask->hdr.packet_id) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some IPv4 mask.");
+		PMD_LOG_ERR(DRV, "Unsupported some IPv4 mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (ipv4_mask->hdr.src_addr) {
+		if (ipv4_mask->hdr.src_addr != UINT32_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, pattern->map_spec);
+		pattern->item_spec.ipv4.saddr = ipv4_spec->hdr.src_addr;
+		pattern->item_mask.ipv4.saddr = ipv4_mask->hdr.src_addr;
+	}
+	if (ipv4_mask->hdr.dst_addr) {
+		if (ipv4_mask->hdr.dst_addr != UINT32_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, pattern->map_spec);
+		pattern->item_spec.ipv4.daddr = ipv4_spec->hdr.dst_addr;
+		pattern->item_mask.ipv4.daddr = ipv4_mask->hdr.dst_addr;
+	}
+
+	if (ipv4_mask->hdr.next_proto_id) {
+		if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "IPv4 proto id must be the last partten.");
+			PMD_LOG_ERR(DRV, "IPv4 proto id must be the last partten.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		if (ipv4_mask->hdr.next_proto_id != UINT8_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_spec);
+		pattern->item_spec.ipv4.protocol = ipv4_spec->hdr.next_proto_id;
+		pattern->item_mask.ipv4.protocol = ipv4_mask->hdr.next_proto_id;
+	}
+	if (ipv4_mask->hdr.time_to_live) {
+		if (ipv4_mask->hdr.time_to_live != UINT8_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TTL, pattern->map_mask);
+		if (ipv4_spec->hdr.time_to_live == 0) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "ipv4 ttl must be not 0.");
+			PMD_LOG_ERR(DRV, "ipv4 ttl must be not 0.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TTL, pattern->map_spec);
+		pattern->item_spec.ipv4.ttl = ipv4_spec->hdr.time_to_live;
+		pattern->item_mask.ipv4.ttl = ipv4_mask->hdr.time_to_live;
+	}
+	if (ipv4_mask->hdr.type_of_service) {
+		if (ipv4_mask->hdr.type_of_service != UINT8_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TOS, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TOS, pattern->map_spec);
+		pattern->item_spec.ipv4.tos = ipv4_spec->hdr.type_of_service;
+		pattern->item_mask.ipv4.tos = ipv4_mask->hdr.type_of_service;
+	}
+	if (ipv4_mask->hdr.fragment_offset) {
+		if (ipv4_spec->hdr.fragment_offset == rte_cpu_to_be_16(RTE_IPV4_HDR_MF_FLAG) &&
+			ipv4_mask->hdr.fragment_offset == rte_cpu_to_be_16(RTE_IPV4_HDR_MF_FLAG)) {
+			if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+				rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ITEM,
+						item, "IPv4 frag offset must be the last partten.");
+				PMD_LOG_ERR(DRV, "IPv4 frag offset must be the last partten.");
+				ret = -EINVAL;
+				goto l_end;
+			}
+			sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, pattern->hdrs);
+		} else {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported ipv4 fragment_offset cfg.");
+			PMD_LOG_ERR(DRV, "Unsupported ipv4 fragment_offset cfg.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs);
+	pattern->rss_type_allow |= RTE_ETH_RSS_IPV4;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_SRC_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_DST_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_IPV4_CHKSUM;
+	if (next == SXE2_EXPANSION_OUTER_END || next == SXE2_EXPANSION_END) {
+		pattern->rss_type_allow |= RTE_ETH_RSS_FRAG_IPV4;
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_OTHER;
+	}
+
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_ipv6(const struct rte_flow_item *item,
+				struct rte_flow_error *error,
+				struct sxe2_flow *flow,
+				enum sxe2_expansion next __rte_unused,
+				bool is_inner)
+{
+	const struct rte_flow_item_ipv6 *ipv6_spec;
+	const struct rte_flow_item_ipv6 *ipv6_mask;
+	uint32_t vtc_flow_mask;
+	uint32_t tc_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	ipv6_spec = item->spec;
+	ipv6_mask = item->mask;
+	uint8_t ipv6_addr_mask[16] = {
+		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+	};
+	uint8_t ipv6_addr_empty[16] = { 0 };
+
+	if (ipv6_mask == NULL && ipv6_spec == NULL)
+		goto l_end;
+
+	if (ipv6_mask->hdr.payload_len || ipv6_mask->has_hop_ext ||
+		ipv6_mask->has_route_ext || ipv6_mask->has_frag_ext ||
+		ipv6_mask->has_auth_ext || ipv6_mask->has_esp_ext ||
+		ipv6_mask->has_dest_ext || ipv6_mask->has_mobil_ext ||
+		ipv6_mask->has_hip_ext || ipv6_mask->has_shim6_ext) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some IPv6 mask");
+		PMD_LOG_ERR(DRV, "Unsupported some IPv6 mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (memcmp(&ipv6_mask->hdr.src_addr, ipv6_addr_empty,
+		   sizeof(ipv6_addr_empty)) != 0) {
+		if (memcmp(&ipv6_mask->hdr.src_addr, ipv6_addr_mask,
+			   sizeof(ipv6_addr_mask)) != 0)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, pattern->map_spec);
+		rte_memcpy(&pattern->item_spec.ipv6.saddr, &ipv6_spec->hdr.src_addr,
+			   sizeof(ipv6_spec->hdr.src_addr));
+		rte_memcpy(&pattern->item_mask.ipv6.saddr, &ipv6_mask->hdr.src_addr,
+			   sizeof(ipv6_mask->hdr.src_addr));
+	}
+	if (memcmp(&ipv6_mask->hdr.dst_addr, ipv6_addr_empty,
+		    sizeof(ipv6_addr_empty)) != 0) {
+		if (memcmp(&ipv6_mask->hdr.dst_addr, ipv6_addr_mask,
+			   sizeof(ipv6_addr_mask)) != 0)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, pattern->map_spec);
+		rte_memcpy(&pattern->item_spec.ipv6.daddr, &ipv6_spec->hdr.dst_addr,
+			   sizeof(ipv6_spec->hdr.dst_addr));
+		rte_memcpy(&pattern->item_mask.ipv6.daddr, &ipv6_mask->hdr.dst_addr,
+			   sizeof(ipv6_mask->hdr.dst_addr));
+	}
+	if (ipv6_mask->hdr.vtc_flow) {
+		vtc_flow_mask = rte_be_to_cpu_32(ipv6_mask->hdr.vtc_flow);
+		tc_mask = vtc_flow_mask & (SXE2_IPV6_TC_MASK << SXE2_IPV6_TC_SHIFT);
+		if (tc_mask != vtc_flow_mask) {
+			rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "ipv6 vtc_flow only support TC mask.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		if (tc_mask != (SXE2_IPV6_TC_MASK << SXE2_IPV6_TC_SHIFT))
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DSCP, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DSCP, pattern->map_spec);
+		pattern->item_spec.ipv6.pri_ver_flow = ipv6_spec->hdr.vtc_flow;
+		pattern->item_mask.ipv6.pri_ver_flow = ipv6_mask->hdr.vtc_flow;
+	}
+	if (ipv6_mask->hdr.proto) {
+		if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "IPv6 proto id must be the last partten.");
+			PMD_LOG_ERR(DRV, "IPv6 proto id must be the last partten.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		if (ipv6_mask->hdr.proto != UINT8_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, pattern->map_spec);
+		pattern->item_spec.ipv6.nexthdr = ipv6_spec->hdr.proto;
+		pattern->item_mask.ipv6.nexthdr = ipv6_mask->hdr.proto;
+	}
+	if (ipv6_mask->hdr.hop_limits) {
+		if (ipv6_mask->hdr.hop_limits != UINT8_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_TTL, pattern->map_mask);
+
+		if (ipv6_spec->hdr.hop_limits == 0) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					item, "ipv6 hop must be not 0.");
+			PMD_LOG_ERR(DRV, "ipv6 hop must be not 0.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_TTL, pattern->map_spec);
+		pattern->item_spec.ipv6.hop_limit = ipv6_spec->hdr.hop_limits;
+		pattern->item_mask.ipv6.hop_limit = ipv6_mask->hdr.hop_limits;
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs);
+	pattern->rss_type_allow |= RTE_ETH_RSS_IPV6;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_SRC_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_DST_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_PRE32;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_PRE48;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L3_PRE64;
+	if (next == SXE2_EXPANSION_OUTER_END || next == SXE2_EXPANSION_END)
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_OTHER;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_ipv6_frag_ext(const struct rte_flow_item *item,
+					 struct rte_flow_error *error,
+					 struct sxe2_flow *flow,
+					 enum sxe2_expansion next __rte_unused,
+					 bool is_inner)
+{
+	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_spec;
+	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	ipv6_frag_spec = item->spec;
+	ipv6_frag_mask = item->mask;
+
+	if (ipv6_frag_mask == NULL && ipv6_frag_spec == NULL)
+		goto l_end;
+
+	if (ipv6_frag_mask->hdr.reserved || ipv6_frag_mask->hdr.frag_data ||
+	    ipv6_frag_mask->hdr.id || ipv6_frag_mask->hdr.next_header) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some IPv6 frag ext mask");
+		PMD_LOG_ERR(DRV, "Unsupported some IPv6 frag ext mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, pattern->hdrs);
+	pattern->rss_type_allow |= RTE_ETH_RSS_FRAG_IPV6;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_tcp(const struct rte_flow_item *item,
+				struct rte_flow_error *error,
+				struct sxe2_flow *flow,
+				enum sxe2_expansion next __rte_unused,
+				bool is_inner)
+{
+	const struct rte_flow_item_tcp *tcp_spec;
+	const struct rte_flow_item_tcp *tcp_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	tcp_spec = item->spec;
+	tcp_mask = item->mask;
+
+	if (tcp_mask == NULL && tcp_spec == NULL)
+		goto l_end;
+
+	if (tcp_mask->hdr.sent_seq || tcp_mask->hdr.recv_ack ||
+	    tcp_mask->hdr.data_off || tcp_mask->hdr.tcp_flags ||
+	    tcp_mask->hdr.rx_win || tcp_mask->hdr.cksum ||
+	    tcp_mask->hdr.tcp_urp) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some TCP mask");
+		PMD_LOG_ERR(DRV, "Unsupported some TCP mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (tcp_mask->hdr.src_port) {
+		if (tcp_mask->hdr.src_port != UINT16_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, pattern->map_spec);
+		pattern->item_spec.tcp.source = tcp_spec->hdr.src_port;
+		pattern->item_mask.tcp.source = tcp_mask->hdr.src_port;
+	}
+	if (tcp_mask->hdr.dst_port) {
+		if (tcp_mask->hdr.dst_port != UINT16_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, pattern->map_spec);
+		pattern->item_spec.tcp.dest = tcp_spec->hdr.dst_port;
+		pattern->item_mask.tcp.dest = tcp_mask->hdr.dst_port;
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_TCP, pattern->hdrs);
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs))
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_TCP;
+	else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs))
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_TCP;
+
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_SRC_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_DST_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_CHKSUM;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_udp(const struct rte_flow_item *item,
+				struct rte_flow_error *error,
+				struct sxe2_flow *flow,
+				enum sxe2_expansion next __rte_unused,
+				bool is_inner)
+{
+	const struct rte_flow_item_udp *udp_spec;
+	const struct rte_flow_item_udp *udp_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	udp_spec = item->spec;
+	udp_mask = item->mask;
+
+	if (udp_mask == NULL && udp_spec == NULL)
+		goto l_end;
+
+	if (udp_mask->hdr.dgram_len || udp_mask->hdr.dgram_cksum) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some UDP mask");
+		PMD_LOG_ERR(DRV, "Unsupported some UDP mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (udp_mask->hdr.src_port) {
+		if (udp_mask->hdr.src_port != UINT16_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, pattern->map_spec);
+		pattern->item_spec.udp.source = udp_spec->hdr.src_port;
+		pattern->item_mask.udp.source = udp_mask->hdr.src_port;
+	}
+	if (udp_mask->hdr.dst_port) {
+		if (udp_mask->hdr.dst_port != UINT16_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, pattern->map_spec);
+		pattern->item_spec.udp.dest = udp_spec->hdr.dst_port;
+		pattern->item_mask.udp.dest = udp_mask->hdr.dst_port;
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_UDP, pattern->hdrs);
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs))
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_UDP;
+	else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs))
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_UDP;
+
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_SRC_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_DST_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_CHKSUM;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_sctp(const struct rte_flow_item *item,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow,
+					enum sxe2_expansion next __rte_unused,
+					bool is_inner)
+{
+	const struct rte_flow_item_sctp *sctp_spec;
+	const struct rte_flow_item_sctp *sctp_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	sctp_spec = item->spec;
+	sctp_mask = item->mask;
+
+	if (sctp_mask == NULL && sctp_spec == NULL)
+		goto l_end;
+
+	if (sctp_mask->hdr.cksum || sctp_mask->hdr.tag) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some SCTP mask");
+		PMD_LOG_ERR(DRV, "Unsupported some SCTP mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (sctp_mask->hdr.src_port) {
+		if (sctp_mask->hdr.src_port != UINT16_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, pattern->map_spec);
+		pattern->item_spec.sctp.src_port = sctp_spec->hdr.src_port;
+		pattern->item_mask.sctp.src_port = sctp_mask->hdr.src_port;
+	}
+	if (sctp_mask->hdr.dst_port) {
+		if (sctp_mask->hdr.dst_port != UINT16_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, pattern->map_spec);
+		pattern->item_spec.sctp.dst_port = sctp_spec->hdr.dst_port;
+		pattern->item_mask.sctp.dst_port = sctp_mask->hdr.dst_port;
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_SCTP, pattern->hdrs);
+	if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs))
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_SCTP;
+	else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs))
+		pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_SCTP;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_SRC_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_DST_ONLY;
+	pattern->rss_type_allow |= RTE_ETH_RSS_L4_CHKSUM;
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_geneve(const struct rte_flow_item *item,
+							struct rte_flow_error *error,
+							struct sxe2_flow *flow,
+							enum sxe2_expansion next __rte_unused,
+							bool is_inner)
+{
+	const struct rte_flow_item_geneve *geneve_spec;
+	const struct rte_flow_item_geneve *geneve_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	geneve_spec = item->spec;
+	geneve_mask = item->mask;
+
+	if (!(geneve_spec && geneve_mask))
+		goto l_end;
+
+	if (geneve_mask->protocol || geneve_mask->ver_opt_len_o_c_rsvd0 || geneve_mask->rsvd1) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some Geneve mask");
+		PMD_LOG_ERR(DRV, "Unsupported some Geneve mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (geneve_mask->vni[0] || geneve_mask->vni[1] || geneve_mask->vni[2]) {
+		if (strcmp((const char *)geneve_mask->vni, "\xFF\xFF\xFF") != 0)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_GENEVE_VNI, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_GENEVE_VNI, pattern->map_spec);
+		pattern->item_spec.geneve.vni = (geneve_spec->vni[2] << 16) |
+			(geneve_spec->vni[1] << 8) | geneve_spec->vni[0];
+		pattern->item_mask.geneve.vni = (geneve_mask->vni[2] << 16) |
+			(geneve_mask->vni[1] << 8) | geneve_mask->vni[0];
+	}
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_GENEVE, pattern->hdrs);
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_gtpu(const struct rte_flow_item *item,
+						struct rte_flow_error *error,
+						struct sxe2_flow *flow,
+						enum sxe2_expansion next __rte_unused,
+						bool is_inner)
+{
+	const struct rte_flow_item_gtp *gtpu_spec;
+	const struct rte_flow_item_gtp *gtpu_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	gtpu_spec = item->spec;
+	gtpu_mask = item->mask;
+
+	if (gtpu_mask == NULL && gtpu_spec == NULL)
+		goto l_end;
+
+	if (gtpu_mask->v_pt_rsv_flags || gtpu_mask->msg_type || gtpu_mask->msg_len) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some GTPU mask");
+		PMD_LOG_ERR(DRV, "Unsupported some GTPU mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (gtpu_mask->teid) {
+		if (gtpu_mask->teid != UINT32_MAX)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_GTPU_TEID, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_GTPU_TEID, pattern->map_spec);
+		pattern->item_spec.gtpu.teid = gtpu_spec->teid;
+		pattern->item_mask.gtpu.teid = gtpu_mask->teid;
+	}
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_GTPU, pattern->hdrs);
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_gre(const struct rte_flow_item *item,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow,
+					enum sxe2_expansion next __rte_unused,
+					bool is_inner)
+{
+	const struct rte_flow_item_gre *gre_spec;
+	const struct rte_flow_item_gre *gre_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	gre_spec = item->spec;
+	gre_mask = item->mask;
+
+	if (gre_mask == NULL && gre_spec == NULL)
+		goto l_end;
+
+	if (gre_mask->c_rsvd0_ver || gre_mask->protocol) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some GRE mask");
+		PMD_LOG_ERR(DRV, "Unsupported some GRE mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_GRE, pattern->hdrs);
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_nvgre(const struct rte_flow_item *item,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow,
+					enum sxe2_expansion next __rte_unused,
+					bool is_inner)
+{
+	const struct rte_flow_item_nvgre *nvgre_spec;
+	const struct rte_flow_item_nvgre *nvgre_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	nvgre_spec = item->spec;
+	nvgre_mask = item->mask;
+
+	if (nvgre_mask == NULL && nvgre_spec == NULL)
+		goto l_end;
+
+	if (nvgre_mask->c_k_s_rsvd0_ver || nvgre_mask->protocol || nvgre_mask->flow_id) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some NVGRE mask");
+		PMD_LOG_ERR(DRV, "Unsupported some NVGRE mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (nvgre_mask->tni[0] || nvgre_mask->tni[1] || nvgre_mask->tni[2]) {
+		if (strcmp((const char *)nvgre_mask->tni, "\xFF\xFF\xFF") != 0)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_NVGRE_TNI, pattern->map_mask);
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_NVGRE_TNI, pattern->map_spec);
+		pattern->item_spec.nvgre.tni =
+			(nvgre_spec->tni[2] << 16) |
+			(nvgre_spec->tni[1] << 8) |
+			(nvgre_spec->tni[0]);
+		pattern->item_mask.nvgre.tni =
+			(nvgre_mask->tni[2] << 16) |
+			(nvgre_mask->tni[1] << 8) |
+			(nvgre_mask->tni[0]);
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_GRE, pattern->hdrs);
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_vxlan(const struct rte_flow_item *item,
+					struct rte_flow_error *error,
+					struct sxe2_flow *flow,
+					enum sxe2_expansion next __rte_unused,
+					bool is_inner)
+{
+	const struct rte_flow_item_vxlan *vxlan_spec;
+	const struct rte_flow_item_vxlan *vxlan_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	vxlan_spec = item->spec;
+	vxlan_mask = item->mask;
+
+	if (vxlan_mask == NULL && vxlan_spec == NULL)
+		goto l_end;
+
+	if (vxlan_mask->flags ||
+	    vxlan_mask->rsvd1 ||
+	    vxlan_mask->rsvd0[0] ||
+	    vxlan_mask->rsvd0[1] ||
+	    vxlan_mask->rsvd0[2]) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some VXLAN mask");
+		PMD_LOG_ERR(DRV, "Unsupported some VXLAN mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (vxlan_mask->vni[0] || vxlan_mask->vni[1] || vxlan_mask->vni[2]) {
+		if (strcmp((const char *)vxlan_mask->vni, "\xFF\xFF\xFF") != 0)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_mask);
+
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_spec);
+		pattern->item_spec.vxlan.vni =
+			(vxlan_spec->vni[2] << 16) |
+			(vxlan_spec->vni[1] << 8) |
+			(vxlan_spec->vni[0]);
+		pattern->item_mask.vxlan.vni =
+			(vxlan_mask->vni[2] << 16) |
+			(vxlan_mask->vni[1] << 8) |
+			(vxlan_mask->vni[0]);
+	}
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_VXLAN, pattern->hdrs);
+	return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_vxlan_gpe(const struct rte_flow_item *item,
+					     struct rte_flow_error *error,
+					     struct sxe2_flow *flow,
+					     enum sxe2_expansion next __rte_unused,
+					     bool is_inner)
+{
+	const struct rte_flow_item_vxlan_gpe *vxlan_gpe_spec;
+	const struct rte_flow_item_vxlan_gpe *vxlan_gpe_mask;
+	struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+	int32_t ret = 0;
+	vxlan_gpe_spec = item->spec;
+	vxlan_gpe_mask = item->mask;
+
+	if (vxlan_gpe_mask == NULL && vxlan_gpe_spec == NULL)
+		goto l_end;
+
+	if (vxlan_gpe_mask->flags ||
+	    vxlan_gpe_mask->protocol ||
+	    vxlan_gpe_mask->rsvd1 ||
+	    vxlan_gpe_mask->rsvd0[0] ||
+	    vxlan_gpe_mask->rsvd0[1]) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM,
+				item, "Unsupported some VXLAN-GPE mask");
+		PMD_LOG_ERR(DRV, "Unsupported some VXLAN-GPE mask");
+		ret = -EINVAL;
+		goto l_end;
+	}
+	if (vxlan_gpe_mask->vni[0] || vxlan_gpe_mask->vni[1] || vxlan_gpe_mask->vni[2]) {
+		if (strcmp((const char *)vxlan_gpe_mask->vni, "\xFF\xFF\xFF") != 0)
+			sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_mask);
+
+		sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_spec);
+		pattern->item_spec.vxlan.vni =
+			(vxlan_gpe_spec->vni[2] << 16) |
+			(vxlan_gpe_spec->vni[1] << 8) |
+			(vxlan_gpe_spec->vni[0]);
+		pattern->item_mask.vxlan.vni =
+			(vxlan_gpe_mask->vni[2] << 16) |
+			(vxlan_gpe_mask->vni[1] << 8) |
+			(vxlan_gpe_mask->vni[0]);
+	}
+
+l_end:
+	sxe2_set_bit(SXE2_FLOW_HDR_VXLAN, pattern->hdrs);
+	return ret;
+}
+
+struct sxe2_flow_parse_pattern_ops sxe2_flow_parse_pattern_list[] = {
+	[SXE2_EXPANSION_OUTER_ETH] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_eth,
+	},
+	[SXE2_EXPANSION_OUTER_VLAN] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_vlan,
+	},
+	[SXE2_EXPANSION_OUTER_QINQ] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_vlan,
+	},
+	[SXE2_EXPANSION_OUTER_IPV4] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_ipv4,
+	},
+	[SXE2_EXPANSION_OUTER_IPV6] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_ipv6,
+	},
+	[SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_ipv6_frag_ext,
+	},
+	[SXE2_EXPANSION_OUTER_TCP] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_tcp,
+	},
+	[SXE2_EXPANSION_OUTER_UDP] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_udp,
+	},
+	[SXE2_EXPANSION_OUTER_SCTP] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_sctp,
+	},
+	[SXE2_EXPANSION_GENEVE] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_geneve,
+	},
+	[SXE2_EXPANSION_GTPU] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_gtpu,
+	},
+	[SXE2_EXPANSION_GRE] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_gre,
+	},
+	[SXE2_EXPANSION_NVGRE] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_nvgre,
+	},
+	[SXE2_EXPANSION_VXLAN] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_vxlan,
+	},
+	[SXE2_EXPANSION_VXLAN_GPE] = {
+		.is_inner = false,
+		.func = sxe2_flow_parse_pattern_vxlan_gpe,
+	},
+	[SXE2_EXPANSION_ETH] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_eth,
+	},
+	[SXE2_EXPANSION_VLAN] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_vlan,
+	},
+	[SXE2_EXPANSION_IPV4] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_ipv4,
+	},
+	[SXE2_EXPANSION_IPV6] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_ipv6,
+	},
+	[SXE2_EXPANSION_IPV6_FRAG_EXT] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_ipv6_frag_ext,
+	},
+	[SXE2_EXPANSION_TCP] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_tcp,
+	},
+	[SXE2_EXPANSION_UDP] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_udp,
+	},
+	[SXE2_EXPANSION_SCTP] = {
+		.is_inner = true,
+		.func = sxe2_flow_parse_pattern_sctp,
+	},
+
+};
+
+int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev __rte_unused,
+			    const struct rte_flow_item patterns[],
+			    struct rte_flow_error *error,
+			    struct sxe2_flow *flow)
+{
+	int32_t ret = 0;
+	const struct rte_flow_item *item = patterns;
+	enum sxe2_expansion now = SXE2_EXPANSION_OUTER_ETH;
+	enum sxe2_expansion next = SXE2_EXPANSION_OUTER_ETH;
+	enum sxe2_flow_tunnel_type tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE;
+	DECLARE_BITMAP(flow_type, SXE2_EXPANSION_MAX);
+	sxe2_bitmap_zero(flow_type, SXE2_EXPANSION_MAX);
+	sxe2_flow_parse_pattern_func_t func;
+	bool is_inner = false;
+
+	for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+		if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
+			continue;
+
+		if (item->last) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM, item,
+					"FANV not support range pattern.");
+			PMD_LOG_ERR(DRV, "flow not supported range pattern.");
+			ret = -EINVAL;
+			goto l_end;
+		}
+		ret = sxe2_flow_is_expandable_item(item);
+		if (ret != 0) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM, item,
+					"Unsupported item type.");
+			PMD_LOG_ERR(DRV, "Unsupported item type: %d", item->type);
+			goto l_end;
+		}
+		next = now;
+		ret = sxe2_flow_valid_next_expansion(&next, item,
+				&tunnel_type, flow_type);
+		if (ret != 0) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM, item,
+					"Invalid pattern sequence for rule.");
+			PMD_LOG_ERR(DRV, "Invalid pattern sequence for rule.");
+			goto l_end;
+		}
+
+		if ((item->spec != NULL && item->mask == NULL) ||
+		    (item->spec == NULL && item->mask != NULL)) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM, item,
+					"Invalid pattern spec miss macth mask for rule.");
+			PMD_LOG_ERR(DRV, "Invalid pattern spec miss macth mask for rule.");
+			goto l_end;
+		}
+
+		func = sxe2_flow_parse_pattern_list[now].func;
+		is_inner = sxe2_flow_parse_pattern_list[now].is_inner;
+		ret = func(item, error, flow, next, is_inner);
+		if (ret != 0)
+			goto l_end;
+		now = next;
+	}
+	if (sxe2_bitmap_weight(flow->pattern_outer.hdrs, SXE2_FLOW_HDR_MAX) > 0)
+		flow->has_hdr = 1;
+
+	if (sxe2_bitmap_weight(flow->pattern_inner.map_mask, SXE2_FLOW_FLD_ID_MAX) > 0 ||
+	   sxe2_bitmap_weight(flow->pattern_outer.map_mask, SXE2_FLOW_FLD_ID_MAX) > 0)
+		flow->has_mask = 1;
+
+	if (sxe2_bitmap_weight(flow->pattern_inner.map_spec, SXE2_FLOW_FLD_ID_MAX) > 0 ||
+	   sxe2_bitmap_weight(flow->pattern_outer.map_spec, SXE2_FLOW_FLD_ID_MAX) > 0)
+		flow->has_spec = 1;
+
+	flow->meta.tunnel_type = tunnel_type;
+	if (flow->has_hdr) {
+		ret = sxe2_flow_get_flow_type(flow);
+		if (ret != 0) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM,
+					NULL, "Unsupported flow type.");
+			goto l_end;
+		}
+	}
+	sxe2_bitmap_copy(flow->flow_type, flow_type, SXE2_EXPANSION_MAX);
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.h b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
new file mode 100644
index 0000000000..69d83a6ea6
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_FLOW_PARSE_PATTERN_H_
+#define SXE2_FLOW_PARSE_PATTERN_H_
+#include <rte_flow_driver.h>
+#include "sxe2_osal.h"
+#include "sxe2_flow_define.h"
+
+#define SXE2_FLOW_EXPAND_NEXT(...) \
+	((const enum sxe2_expansion []){ \
+		__VA_ARGS__, 0, \
+	})
+
+struct sxe2_flow_expand_node {
+	const enum rte_flow_item_type type;
+	const enum sxe2_flow_tunnel_type tunnel_type;
+	const uint8_t is_tunnel;
+	const enum sxe2_expansion *const next;
+	const char *const name;
+};
+
+typedef int32_t (*sxe2_flow_parse_pattern_func_t)(const struct rte_flow_item *item,
+					      struct rte_flow_error *error,
+					      struct sxe2_flow *flow,
+					      enum sxe2_expansion next,
+					      bool is_inner);
+
+struct sxe2_flow_parse_pattern_ops {
+	bool is_inner;
+	sxe2_flow_parse_pattern_func_t func;
+};
+
+int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev,
+			    const struct rte_flow_item patterns[],
+			    struct rte_flow_error *error,
+			    struct sxe2_flow *flow);
+
+#endif /* SXE2_FLOW_PARSE_PATTERN_H_ */
diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c
index fd9cd4b1ff..c26098ef3a 100644
--- a/drivers/net/sxe2/sxe2_irq.c
+++ b/drivers/net/sxe2/sxe2_irq.c
@@ -20,6 +20,7 @@
 #include "sxe2vf_regs.h"
 #include "sxe2_host_regs.h"
 #include "sxe2_cmd_chnl.h"
+#include "sxe2_switchdev.h"
 
 #define SXE2_INT_EVENT_OICR_ALL (SXE2_PF_INT_OICR_SWINT | \
 					SXE2_PF_INT_OICR_LAN_TX_ERR | \
@@ -59,6 +60,14 @@ static void sxe2_event_irq_common_handler(struct sxe2_adapter *adapter, uint64_t
 						     RTE_ETH_EVENT_INTR_LSC,
 						     NULL);
 	}
+	if (oicr & RTE_BIT32(SXE2_COM_SW_MODE_SWITCHDEV)) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "event notify switchdev");
+		(void)sxe2_switchdev_notify_callback(adapter, true);
+	}
+	if (oicr & RTE_BIT32(SXE2_COM_SW_MODE_LEGACY)) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "event notify legacy");
+		(void)sxe2_switchdev_notify_callback(adapter, false);
+	}
 }
 
 static uint32_t sxe2_event_intr_handle(void *param __rte_unused)
@@ -882,6 +891,42 @@ int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev)
 	return ret;
 }
 
+int32_t sxe2_repr_rxq_intr_enable(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	uint16_t rxq_cnt = dev->data->nb_rx_queues;
+	int32_t ret = 0;
+	uint16_t qid = adapter->repr_priv_data->repr_q_id;
+	uint32_t val;
+
+	if (!rxq_cnt)
+		goto l_end;
+
+	sxe2_pci_hw_irq_disable(adapter, qid);
+	sxe2_pci_hw_int_itr_set(adapter, qid, SXE2_ITR_INTERVAL_NORMAL);
+	ret = sxe2_drv_rxq_bind_irq(adapter, qid, qid);
+	if (ret != 0) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "RXQ[%u] bind IRQ[%u] failed.",
+				qid, qid);
+		goto l_end;
+	}
+	sxe2_pci_hw_irq_enable(adapter, qid);
+
+	val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, qid);
+	if ((val & SXE2VF_DYN_CTL_INTENABLE) == 0)
+		goto l_end;
+
+	sxe2_pci_hw_msix_disable(adapter, qid);
+	sxe2_pci_hw_irq_trigger(adapter, qid);
+	val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, qid);
+	sxe2_pci_hw_irq_clear_pba(adapter, qid);
+	val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, qid);
+	sxe2_pci_hw_msix_enable(adapter, qid);
+
+l_end:
+	return ret;
+}
+
 void sxe2_rxq_intr_disable(struct rte_eth_dev *dev)
 {
 	struct sxe2_adapter *adapter =
@@ -902,6 +947,15 @@ void sxe2_rxq_intr_disable(struct rte_eth_dev *dev)
 	return;
 }
 
+void sxe2_repr_rxq_intr_disable(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	uint16_t qid = adapter->repr_priv_data->repr_q_id;
+
+	sxe2_pci_hw_irq_disable(adapter, qid);
+	(void)sxe2_drv_rxq_unbind_irq(adapter, qid);
+}
+
 int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
 	struct sxe2_adapter *adapter =
diff --git a/drivers/net/sxe2/sxe2_irq.h b/drivers/net/sxe2/sxe2_irq.h
index 31216240e6..b56c2664b8 100644
--- a/drivers/net/sxe2/sxe2_irq.h
+++ b/drivers/net/sxe2/sxe2_irq.h
@@ -60,8 +60,12 @@ void sxe2_sw_irq_ctx_hw_cap_set(struct sxe2_adapter *adapter,
 
 int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev);
 
+int32_t sxe2_repr_rxq_intr_enable(struct rte_eth_dev *dev);
+
 void sxe2_rxq_intr_disable(struct rte_eth_dev *dev);
 
+void sxe2_repr_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);
diff --git a/drivers/net/sxe2/sxe2_queue.c b/drivers/net/sxe2/sxe2_queue.c
index 220cab6fce..afb2681b72 100644
--- a/drivers/net/sxe2/sxe2_queue.c
+++ b/drivers/net/sxe2/sxe2_queue.c
@@ -24,7 +24,11 @@ int32_t sxe2_queues_init(struct rte_eth_dev *dev)
 	struct sxe2_rx_queue *rxq;
 	uint16_t nb_rxq;
 
-	frame_size = dev->data->mtu + SXE2_ETH_OVERHEAD;
+	if (adapter->is_dev_repr)
+		frame_size = SXE2_FRAME_SIZE_MAX - SXE2_ETH_OVERHEAD;
+	else
+		frame_size = dev->data->mtu + SXE2_ETH_OVERHEAD;
+
 	for (nb_rxq = 0; nb_rxq < dev->data->nb_rx_queues; nb_rxq++) {
 		rxq = dev->data->rx_queues[nb_rxq];
 		if (!rxq)
diff --git a/drivers/net/sxe2/sxe2_stats.c b/drivers/net/sxe2/sxe2_stats.c
index 7ea2815fa3..2f8bb432c4 100644
--- a/drivers/net/sxe2/sxe2_stats.c
+++ b/drivers/net/sxe2/sxe2_stats.c
@@ -154,7 +154,12 @@ static int32_t sxe2_vsi_hw_stats_get_update(struct sxe2_adapter *adapter)
 
 	ret = sxe2_drv_get_vsi_stats(adapter);
 	if (ret) {
-		PMD_LOG_ERR(DRV, "get vsi stats failed, ret:%d.", ret);
+		if (adapter->is_dev_repr) {
+			PMD_LOG_WARN(DRV, "get repr vsi stats failed, ret:%d.", ret);
+			ret = 0;
+		} else {
+			PMD_LOG_ERR(DRV, "get vsi stats failed, ret:%d.", ret);
+		}
 		goto l_end;
 	}
 
@@ -231,7 +236,7 @@ static void sxe2_stats_update(struct sxe2_adapter *adapter)
 	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) {
+	if (adapter->dev_type != SXE2_DEV_T_VF  && !adapter->is_dev_repr) {
 		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;
@@ -364,7 +369,7 @@ int32_t sxe2_xstats_info_get(struct rte_eth_dev *dev,
 	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)
+	if (adapter->dev_type == SXE2_DEV_T_VF || adapter->is_dev_repr)
 		xstats_cnt = SXE2_XSTAT_CNT_VF;
 	else
 		xstats_cnt = SXE2_XSTAT_CNT_PF;
@@ -387,7 +392,7 @@ int32_t sxe2_xstats_info_get(struct rte_eth_dev *dev,
 		goto end;
 	}
 
-	if (adapter->dev_type == SXE2_DEV_T_VF) {
+	if (adapter->dev_type == SXE2_DEV_T_VF || adapter->is_dev_repr) {
 		sxe2_stats_update(adapter);
 		for (i = 0; i < xstats_cnt; i++) {
 			(void)sxe2_xstat_vf_offset_get(i, &offset);
@@ -431,7 +436,7 @@ int32_t sxe2_xstats_names_get(__rte_unused struct rte_eth_dev *dev,
 	int32_t ret = -1;
 	uint32_t xstats_cnt = 0;
 
-	if (adapter->dev_type == SXE2_DEV_T_VF) {
+	if (adapter->dev_type == SXE2_DEV_T_VF || adapter->is_dev_repr) {
 		field = sxe2_xstats_field_vf;
 		xstats_cnt = SXE2_XSTAT_CNT_VF;
 	} else {
@@ -476,7 +481,7 @@ int32_t sxe2_stats_hw_reset(struct rte_eth_dev *dev)
 		PMD_LOG_ERR(DRV, "reset vsi stats failed, ret:%d.", ret);
 		goto l_end;
 	}
-	if (adapter->dev_type != SXE2_DEV_T_VF) {
+	if (adapter->dev_type != SXE2_DEV_T_VF && !adapter->is_dev_repr) {
 		ret = sxe2_drv_mac_stats_reset(adapter);
 		if (ret) {
 			PMD_LOG_ERR(DRV, "reset mac stats failed, ret:%d.", ret);
diff --git a/drivers/net/sxe2/sxe2_switchdev.c b/drivers/net/sxe2/sxe2_switchdev.c
new file mode 100644
index 0000000000..44703cfb5c
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_switchdev.c
@@ -0,0 +1,332 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_os.h>
+#include <rte_tailq.h>
+#include "sxe2_osal.h"
+#include "sxe2_mac.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_switchdev.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_host_regs.h"
+
+int32_t sxe2_uplink_clear(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+		goto l_end;
+	}
+
+	ret = sxe2_drv_switchdev_uplink_config(adapter, false);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_uplink_set(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+		goto l_end;
+	}
+
+	ret = sxe2_drv_switchdev_uplink_config(adapter, true);
+l_end:
+	return ret;
+}
+
+int32_t sxe2_repr_clear(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	uint16_t repr_id = 0;
+	struct rte_eth_dev *repr_dev;
+	struct sxe2_adapter *repr_adapter;
+	struct sxe2_switchdev_repr_info repr_vf;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+		goto l_end;
+	}
+
+	for (repr_id = 0; repr_id < adapter->repr_ctxt.nb_repr_vf; repr_id++) {
+		repr_dev = adapter->repr_ctxt.vf_rep_eth_dev[repr_id];
+		if (!repr_dev)
+			continue;
+		repr_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(repr_dev);
+		if (repr_adapter &&
+		    repr_adapter->repr_priv_data &&
+		    repr_adapter->repr_priv_data->cp_vsi) {
+			memset(&repr_vf, 0, sizeof(struct sxe2_switchdev_repr_info));
+
+			repr_vf.repr_pf_id = repr_adapter->repr_priv_data->repr_pf_id;
+			repr_vf.repr_vf_id = repr_adapter->repr_priv_data->repr_vf_id;
+			repr_vf.cp_vsi_id = repr_adapter->repr_priv_data->cp_vsi->vsi_id;
+			repr_vf.repr_q_id = repr_adapter->repr_priv_data->repr_q_id;
+			ret = sxe2_drv_switchdev_repr_vf_config(adapter, &repr_vf,
+								false);
+		}
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_repr_set(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+	uint16_t repr_id = 0;
+	struct rte_eth_dev *repr_dev;
+	struct sxe2_adapter *repr_adapter;
+	struct sxe2_switchdev_repr_info repr_vf;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+		goto l_end;
+	}
+
+	for (repr_id = 0; repr_id < adapter->repr_ctxt.nb_repr_vf; repr_id++) {
+		repr_dev = adapter->repr_ctxt.vf_rep_eth_dev[repr_id];
+		if (!repr_dev)
+			continue;
+		repr_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(repr_dev);
+		if (repr_adapter &&
+		    repr_adapter->repr_priv_data &&
+		    repr_adapter->repr_priv_data->cp_vsi) {
+			memset(&repr_vf, 0, sizeof(struct sxe2_switchdev_repr_info));
+
+			repr_vf.repr_pf_id = repr_adapter->repr_priv_data->repr_pf_id;
+			repr_vf.repr_vf_id = repr_adapter->repr_priv_data->repr_vf_id;
+			repr_vf.cp_vsi_id = repr_adapter->repr_priv_data->cp_vsi->vsi_id;
+			repr_vf.repr_q_id = repr_adapter->repr_priv_data->repr_q_id;
+			ret = sxe2_drv_switchdev_repr_vf_config(adapter, &repr_vf, true);
+		}
+	}
+
+l_end:
+	return ret;
+}
+
+void sxe2_free_repr_info(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	if (adapter->repr_ctxt.vf_rep_eth_dev) {
+		rte_free(adapter->repr_ctxt.vf_rep_eth_dev);
+		adapter->repr_ctxt.vf_rep_eth_dev = NULL;
+	}
+
+	adapter->repr_ctxt.nb_repr_vf = 0;
+}
+
+static int32_t sxe2_switchdev_clear(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (!adapter->switchdev_info.is_switchdev) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+		goto l_end;
+	}
+
+	adapter->switchdev_info.is_switchdev = false;
+
+	if (!adapter->flow_isolate_cfg && adapter->flow_isolated)
+		adapter->flow_isolated = false;
+
+	ret = sxe2_l2_rule_update(adapter);
+	if (ret != 0)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+	ret = sxe2_switchdev_rule_update(adapter);
+	if (ret != 0)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update switchdev rule");
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_switchdev_set(struct sxe2_adapter *adapter)
+{
+	int32_t ret = 0;
+
+	if (adapter->switchdev_info.is_switchdev) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "Current mode switch dev");
+		goto l_end;
+	}
+
+	adapter->switchdev_info.is_switchdev = true;
+
+	if (adapter->flow_isolate_cfg && !adapter->flow_isolated)
+		adapter->flow_isolated = true;
+
+	ret = sxe2_l2_rule_update(adapter);
+	if (ret != 0)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+	ret = sxe2_switchdev_rule_update(adapter);
+	if (ret != 0)
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update switchdev rule");
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_switchdev_notify_callback(struct sxe2_adapter *adapter, bool set)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[adapter->dev_info.dev_data->port_id];
+	int32_t ret = 0;
+	bool cur_switchdev_set = false;
+
+	if (adapter->repr_ctxt.nb_repr_vf) {
+		PMD_DEV_LOG_WARN(adapter, DRV, "switch dev notify remove dev");
+		rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RMV, NULL);
+		goto l_end;
+	}
+
+	ret = sxe2_drv_switchdev_mode_get(adapter, &cur_switchdev_set);
+	if (ret) {
+		PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get switchdev mode");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	if (set != cur_switchdev_set) {
+		PMD_DEV_LOG_INFO(adapter, DRV, "current switchdev mode miss macth");
+		goto l_end;
+	}
+
+	if (set) {
+		ret = sxe2_switchdev_set(adapter);
+		if (ret != 0) {
+			PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set switchdev");
+			goto l_end;
+		}
+	} else {
+		ret = sxe2_switchdev_clear(adapter);
+		if (ret != 0) {
+			PMD_DEV_LOG_ERR(adapter, DRV, "Failed to clear switchdev");
+			goto l_end;
+		}
+	}
+l_end:
+	return ret;
+}
+
+int32_t sxe2_switchdev_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	PMD_DEV_LOG_INFO(adapter, INIT, "switchdev init");
+
+	if (adapter->switchdev_info.is_switchdev)
+		adapter->flow_isolated = true;
+
+	adapter->repr_priv_data = NULL;
+	adapter->repr_ctxt.nb_repr_vf = 0;
+
+	return 0;
+}
+
+int32_t sxe2_switchdev_uninit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	PMD_DEV_LOG_INFO(adapter, INIT, "switchdev uinit");
+
+	if (adapter->repr_priv_data) {
+		rte_free(adapter->repr_priv_data);
+		adapter->repr_priv_data = NULL;
+	}
+
+	return 0;
+}
+
+int32_t sxe2_switchdev_dev_info_init(struct rte_eth_dev *dev,
+			struct sxe2_adapter *parent_adapter)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_dev_info *dev_info = &adapter->dev_info;
+	struct sxe2_dev_info *parent_dev_info = &parent_adapter->dev_info;
+	struct sxe2_drv_dev_info_resp dev_info_resp = {0};
+	struct sxe2_drv_dev_fw_info_resp dev_fw_info_resp = {0};
+	int32_t ret = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	dev_info->pci = parent_dev_info->pci;
+	dev_info->pci.max_vfs = 0;
+
+	ret = sxe2_drv_dev_info_get(adapter, &dev_info_resp);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to get device info, ret=[%d]", ret);
+		goto l_end;
+	}
+
+	ret = sxe2_drv_dev_fw_info_get(adapter, &dev_fw_info_resp);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to get device fw info, ret=[%d]", ret);
+		goto l_end;
+	}
+	dev_info->fw.build_id = dev_fw_info_resp.build_id;
+	dev_info->fw.fix_version_id = dev_fw_info_resp.fix_version_id;
+	dev_info->fw.sub_version_id = dev_fw_info_resp.sub_version_id;
+	dev_info->fw.main_version_id = dev_fw_info_resp.main_version_id;
+
+	rte_ether_addr_copy((struct rte_ether_addr *)dev_info_resp.mac_addr,
+						(struct rte_ether_addr *)dev_info->mac.perm_addr);
+
+l_end:
+	return ret;
+}
+
+int32_t sxe2_switchdev_repr_private_data_init(struct rte_eth_dev *dev,
+		struct sxe2_adapter *parent_adapter, uint16_t repr_id)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_repr_private_data *repr_priv_data = adapter->repr_priv_data;
+	int32_t ret = 0;
+
+	if (repr_priv_data != NULL)
+		goto l_end;
+
+	repr_priv_data = rte_zmalloc("sxe2_repr_priv_data",
+			sizeof(struct sxe2_repr_private_data), 0);
+	if (repr_priv_data == NULL) {
+		PMD_LOG_ERR(INIT, "Failed to malloc representor private data.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	repr_priv_data->parent_adapter = parent_adapter;
+	repr_priv_data->repr_id = repr_id;
+	repr_priv_data->cp_vsi =
+		TAILQ_FIRST(&parent_adapter->vsi_ctxt.other_vsi_list);
+	if (repr_priv_data->cp_vsi == NULL) {
+		PMD_LOG_ERR(INIT, "Failed to get cp vsi.");
+		ret = -EINVAL;
+		goto l_free;
+	}
+	repr_priv_data->repr_q_id = repr_id;
+	repr_priv_data->repr_pf_id = parent_adapter->pf_idx;
+	repr_priv_data->repr_vf_id = repr_id;
+	repr_priv_data->repr_vf_k_vsi_id =
+		parent_adapter->repr_ctxt.repr_vf_id[repr_id].kernel_vsi_id;
+	repr_priv_data->repr_vf_u_vsi_id =
+		parent_adapter->repr_ctxt.repr_vf_id[repr_id].dpdk_vsi_id;
+
+	repr_priv_data->repr_vf_vsi_id =
+		parent_adapter->repr_ctxt.repr_vf_id[repr_id].kernel_vsi_id !=
+		SXE2_INVALID_VSI_ID ?
+		parent_adapter->repr_ctxt.repr_vf_id[repr_id].kernel_vsi_id :
+		parent_adapter->repr_ctxt.repr_vf_id[repr_id].dpdk_vsi_id;
+
+	adapter->repr_priv_data = repr_priv_data;
+	goto l_end;
+l_free:
+	rte_free(repr_priv_data);
+l_end:
+	return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_switchdev.h b/drivers/net/sxe2/sxe2_switchdev.h
new file mode 100644
index 0000000000..0a74454424
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_switchdev.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_SWITCHDEV_H__
+#define __SXE2_SWITCHDEV_H__
+#include <ethdev_driver.h>
+
+struct sxe2_adapter;
+
+int32_t sxe2_uplink_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_uplink_set(struct sxe2_adapter *adapter);
+
+int32_t sxe2_repr_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_repr_set(struct sxe2_adapter *adapter);
+
+int32_t sxe2_switchdev_notify_callback(struct sxe2_adapter *adapter, bool set);
+
+int32_t sxe2_switchdev_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_switchdev_uninit(struct rte_eth_dev *dev);
+
+void sxe2_free_repr_info(struct rte_eth_dev *dev);
+
+int32_t sxe2_switchdev_dev_info_init(struct rte_eth_dev *dev,
+			struct sxe2_adapter *parent_adapter);
+
+int32_t sxe2_switchdev_repr_private_data_init(struct rte_eth_dev *dev,
+		struct sxe2_adapter *parent_adapter, uint16_t repr_id);
+
+#endif /* __SXE2_SWITCHDEV_H__ */
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index a919a84450..3861e31688 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -151,6 +151,13 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
 	uint32_t batch_flags = 0;
 
 	PMD_INIT_FUNC_TRACE();
+
+	if (adapter->is_dev_repr) {
+		dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
+		dev->tx_pkt_burst = sxe2_tx_pkts;
+		tx_mode_flags = 0;
+		return;
+	}
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
 		tx_mode_flags = 0;
 		ret = sxe2_tx_vec_support_check(dev, &vec_flags);
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index 8b6e585c36..f3c4fa0d91 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -454,6 +454,14 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
 				desc_l2tag2 = tx_pkt->vlan_tci_outer;
 				desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_CMD_IL2TAG2_MASK;
 			}
+			if (unlikely(vsi->vsi_type == SXE2_VSI_T_DPDK_ESW)) {
+				desc_type_cmd_tso_mss |=
+					(SXE2_TX_CTXT_DESC_CMD_SWTCH_VSI <<
+					SXE2_TX_CTXT_DESC_CMD_SHIFT);
+				desc_type_cmd_tso_mss |=
+					((vsi->adapter->repr_priv_data->repr_vf_vsi_id & 0x3FFULL)
+					<< SXE2_TX_CTXT_DESC_VSI_SHIFT);
+			}
 
 			ctxt_desc->tunneling_params =
 				rte_cpu_to_le_32(desc_tunneling_params);
diff --git a/drivers/net/sxe2/sxe2_vsi.c b/drivers/net/sxe2/sxe2_vsi.c
index baaa20c02e..d29480b931 100644
--- a/drivers/net/sxe2/sxe2_vsi.c
+++ b/drivers/net/sxe2/sxe2_vsi.c
@@ -98,9 +98,15 @@ static struct sxe2_vsi *sxe2_vsi_node_create(struct sxe2_adapter *adapter,
 
 static void sxe2_vsi_node_free(struct sxe2_vsi *vsi)
 {
+	struct sxe2_adapter *adapter;
+
 	if (!vsi)
 		return;
 
+	adapter = vsi->adapter;
+	if (vsi->vsi_type == SXE2_VSI_T_ESW)
+		TAILQ_REMOVE(&adapter->vsi_ctxt.other_vsi_list, vsi, next);
+
 	rte_free(vsi);
 	vsi = NULL;
 }
@@ -174,10 +180,54 @@ static int32_t sxe2_main_vsi_create(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+int32_t sxe2_other_vsi_create(struct sxe2_adapter *adapter, uint16_t cnt_vf)
+{
+	int32_t ret = 0;
+	struct sxe2_vsi *other_vsi = NULL;
+	uint16_t vsi_id = SXE2_INVALID_VSI_ID;
+
+	PMD_INIT_FUNC_TRACE();
+
+	other_vsi = sxe2_vsi_node_create(adapter, SXE2_INVALID_VSI_ID, SXE2_VSI_T_DPDK_ESW);
+	if (other_vsi == NULL) {
+		ret = -ENOMEM;
+		goto l_end;
+	}
+
+	ret = sxe2_drv_switchdev_cpvsi_get(adapter, &vsi_id);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Failed to query vsi from fw, ret=%d", ret);
+		goto l_free_vsi;
+	}
+
+	other_vsi->vsi_id = vsi_id;
+	other_vsi->vsi_type = SXE2_VSI_T_DPDK_ESW;
+
+	ret = sxe2_drv_vsi_info_get(adapter, other_vsi);
+	if (ret) {
+		PMD_LOG_ERR(DRV, "Failed to query vsi info from fw, ret=%d", ret);
+		goto l_free_vsi;
+	}
+
+	other_vsi->txqs.q_cnt = RTE_MIN(cnt_vf, other_vsi->txqs.q_cnt);
+	other_vsi->rxqs.q_cnt = RTE_MIN(cnt_vf, other_vsi->rxqs.q_cnt);
+	other_vsi->irqs.avail_cnt = RTE_MIN(cnt_vf, other_vsi->irqs.avail_cnt);
+
+	TAILQ_INSERT_TAIL(&adapter->vsi_ctxt.other_vsi_list, other_vsi, next);
+	goto l_end;
+
+l_free_vsi:
+	sxe2_vsi_node_free(other_vsi);
+l_end:
+	return ret;
+}
+
 int32_t sxe2_vsi_init(struct rte_eth_dev *dev)
 {
 	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
 	int32_t ret = 0;
+	uint16_t srcvsi_list[SXE2_SRCVSI_PRUNE_MAX_NUM];
+	uint16_t srcvsi_cnt;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -187,6 +237,18 @@ int32_t sxe2_vsi_init(struct rte_eth_dev *dev)
 		goto l_end;
 	}
 
+	if (adapter->vsi_ctxt.kernel_vsi_id != SXE2_INVALID_VSI_ID) {
+		srcvsi_list[0] = adapter->vsi_ctxt.kernel_vsi_id;
+		srcvsi_list[1] = adapter->vsi_ctxt.dpdk_vsi_id;
+		srcvsi_cnt = 2;
+		ret = sxe2_drv_srcvsi_prune_config(adapter, srcvsi_list, srcvsi_cnt, true);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "Failed to set src vsi to fw, ret=%d", ret);
+			goto l_end;
+		}
+		PMD_LOG_DEBUG(DRV, "Successfully set src vsi");
+	}
+
 l_end:
 	return ret;
 }
@@ -194,21 +256,105 @@ int32_t sxe2_vsi_init(struct rte_eth_dev *dev)
 void sxe2_vsi_uninit(struct rte_eth_dev *dev)
 {
 	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_vsi *var, *tvar;
 	int32_t ret;
+	uint16_t srcvsi_list[SXE2_SRCVSI_PRUNE_MAX_NUM];
+	uint16_t srcvsi_cnt;
 
 	if (adapter->vsi_ctxt.main_vsi == NULL) {
 		PMD_LOG_INFO(DRV, "vsi is not created, no need to destroy.");
 		goto l_end;
 	}
 
+	if (adapter->vsi_ctxt.kernel_vsi_id != SXE2_INVALID_VSI_ID) {
+		srcvsi_list[0] = adapter->vsi_ctxt.kernel_vsi_id;
+		srcvsi_list[1] = adapter->vsi_ctxt.dpdk_vsi_id;
+		srcvsi_cnt = 2;
+		ret = sxe2_drv_srcvsi_prune_config(adapter, srcvsi_list,
+						   srcvsi_cnt, false);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "Failed to clear src vsi to fw, ret=%d", ret);
+			if (ret == -EPERM)
+				goto l_free;
+			goto l_end;
+		}
+		PMD_LOG_DEBUG(DRV, "Successfully clear src vsi");
+	}
+
+l_free:
 	ret = sxe2_vsi_destroy(adapter, adapter->vsi_ctxt.main_vsi);
 	if (ret) {
 		PMD_LOG_ERR(DRV, "Failed to del vsi from fw, ret=%d", ret);
 		goto l_end;
 	}
+	RTE_TAILQ_FOREACH_SAFE(var, &adapter->vsi_ctxt.other_vsi_list, next, tvar) {
+		ret = sxe2_vsi_destroy(adapter, var);
+		if (ret) {
+			PMD_LOG_ERR(DRV, "Failed to del vsi from fw, ret=%d", ret);
+			break;
+		}
+	}
 
 	PMD_LOG_DEBUG(DRV, "vsi destroyed.");
 
 l_end:
 	return;
 }
+
+int32_t sxe2_vsi_repr_main_vsi_create(struct rte_eth_dev *dev,
+				  struct sxe2_adapter *parent_adapter,
+				  uint16_t repr_id)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_vsi *vsi = NULL;
+	struct sxe2_vsi *pos;
+	int32_t ret = 0;
+
+	TAILQ_FOREACH(pos, &parent_adapter->vsi_ctxt.other_vsi_list, next) {
+		if (pos->vsi_type == SXE2_VSI_T_DPDK_ESW) {
+			vsi = pos;
+			break;
+		}
+	}
+
+	if (vsi == NULL) {
+		PMD_LOG_ERR(INIT, "Failed to get dpdk vsi.");
+		ret = -EINVAL;
+		goto l_end;
+	}
+
+	TAILQ_INIT(&adapter->vsi_ctxt.other_vsi_list);
+
+	adapter->vsi_ctxt.vsi_type = SXE2_VSI_T_DPDK_ESW;
+	adapter->vsi_ctxt.kernel_vsi_id = SXE2_INVALID_VSI_ID;
+
+	adapter->cdev = parent_adapter->cdev;
+
+	adapter->q_ctxt.base_idx_in_pf = vsi->txqs.base_idx_in_func +
+		RTE_MIN(vsi->txqs.q_cnt, repr_id);
+	adapter->irq_ctxt.base_idx_in_func = vsi->irqs.base_idx_in_pf +
+		RTE_MIN(vsi->irqs.avail_cnt, repr_id);
+	adapter->q_ctxt.qp_cnt_assign = RTE_MIN(vsi->txqs.q_cnt, 1);
+	adapter->irq_ctxt.max_cnt_hw = RTE_MIN(vsi->irqs.avail_cnt, 1);
+
+	adapter->vsi_ctxt.main_vsi =
+		sxe2_vsi_node_create(adapter, vsi->vsi_id, SXE2_VSI_T_DPDK_ESW);
+	if (adapter->vsi_ctxt.main_vsi == NULL) {
+		ret = -ENOMEM;
+		PMD_LOG_ERR(DRV, "Failed to create vsi struct, ret=%d", ret);
+		goto l_end;
+	}
+	adapter->vsi_ctxt.dpdk_vsi_id = adapter->vsi_ctxt.main_vsi->vsi_id;
+
+	ret = 0;
+
+l_end:
+	return ret;
+}
+
+void sxe2_vsi_repr_main_vsi_destroy(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+	sxe2_vsi_node_free(adapter->vsi_ctxt.main_vsi);
+}
diff --git a/drivers/net/sxe2/sxe2_vsi.h b/drivers/net/sxe2/sxe2_vsi.h
index 1d74c3262f..d4b2cd6554 100644
--- a/drivers/net/sxe2/sxe2_vsi.h
+++ b/drivers/net/sxe2/sxe2_vsi.h
@@ -193,13 +193,23 @@ struct sxe2_vsi_context {
 	uint16_t bond_member_dpdk_vsi_id[SXE2_MAX_BOND_MEMBER_CNT];
 
 	struct sxe2_vsi *main_vsi;
+
+	struct sxe2_vsi_list_head other_vsi_list;
 };
 
 void sxe2_sw_vsi_ctx_hw_cap_set(struct sxe2_adapter *adapter,
-		struct sxe2_drv_vsi_caps *vsi_caps);
+				struct sxe2_drv_vsi_caps *vsi_caps);
+
+int32_t sxe2_other_vsi_create(struct sxe2_adapter *adapter,  uint16_t cnt_vf);
 
 int32_t sxe2_vsi_init(struct rte_eth_dev *dev);
 
 void sxe2_vsi_uninit(struct rte_eth_dev *dev);
 
+int32_t sxe2_vsi_repr_main_vsi_create(struct rte_eth_dev *dev,
+				  struct sxe2_adapter *parent_adapter,
+				  uint16_t repr_id);
+
+void sxe2_vsi_repr_main_vsi_destroy(struct rte_eth_dev *dev);
+
 #endif /* SXE2_VSI_H */
-- 
2.52.0


^ permalink raw reply related

* RE: [PATCH v2] net/mlx5: promote private API to stable
From: Bing Zhao @ 2026-06-02  6:07 UTC (permalink / raw)
  To: Dariusz Sosnowski, Slava Ovsiienko, Ori Kam, Suanming Mou,
	Matan Azrad
  Cc: dev@dpdk.org
In-Reply-To: <20260529073255.689808-1-dsosnowski@nvidia.com>

Hi,

Thanks

> -----Original Message-----
> From: Dariusz Sosnowski <dsosnowski@nvidia.com>
> Sent: Friday, May 29, 2026 3:33 PM
> To: Slava Ovsiienko <viacheslavo@nvidia.com>; Bing Zhao
> <bingz@nvidia.com>; Ori Kam <orika@nvidia.com>; Suanming Mou
> <suanmingm@nvidia.com>; Matan Azrad <matan@nvidia.com>
> Cc: dev@dpdk.org
> Subject: [PATCH v2] net/mlx5: promote private API to stable
> 
> Following experimental functions are exposed by mlx5 PMD since 25.11
> release:
> 
> - rte_pmd_mlx5_driver_event_cb_register
> - rte_pmd_mlx5_driver_event_cb_unregister
> - rte_pmd_mlx5_enable_steering
> - rte_pmd_mlx5_disable_steering
> 
> First two are used to register callbacks for driver events (when Rx/Tx
> queues are created or destroyed).
> Other two are used to enable/disable flow steering in mlx5 PMD.
> No changes were made and no changes are planned to these symbols.
> 
> These are currently used by NVIDIA DOCA SDK since version 3.3, which
> started depending on upstream DPDK releases [1].
> Purpose of their use is to:
> 
> - expose HW identifiers of Rx/Tx mlx5 queues managed by DPDK and
> - allow flow steering to happen outside of DPDK.
> 
> Also, some of these symbols will be used by netdev-doca backend in Open
> vSwitch [2].
> Whenever a DOCA netdev would be added/removed in Open vSwitch, it will
> have to disable/enable steering for mlx5 driver.
> Stabilizing these symbols is required by current OVS policy to remove the
> need for ALLOW_EXPERIMENTAL_API [3].
> 
> This patch promotes aforementioned symbols to stable.
> 
> [1]: https://docs.nvidia.com/doca/sdk/customer-affecting-
> changes/index.html
> [2]:
> https://patchwork.ozlabs.org/project/openvswitch/list/?series=504726&state
> =%2A&archive=both
> [3]: https://mail.openvswitch.org/pipermail/ovs-dev/2026-May/432066.html
> 
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> ---
> v2:
> - Updated 26.07 release notes.
> 
>  doc/guides/rel_notes/release_26_07.rst | 9 +++++++++
>  drivers/net/mlx5/mlx5_driver_event.c   | 4 ++--
>  drivers/net/mlx5/mlx5_flow.c           | 4 ++--
>  drivers/net/mlx5/rte_pmd_mlx5.h        | 4 ----
>  4 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/doc/guides/rel_notes/release_26_07.rst
> b/doc/guides/rel_notes/release_26_07.rst
> index 6eba91a5e9..2af24d40a0 100644
> --- a/doc/guides/rel_notes/release_26_07.rst
> +++ b/doc/guides/rel_notes/release_26_07.rst
> @@ -127,6 +127,15 @@ API Changes
>    - ``rte_flow_dynf_metadata_get``
>    - ``rte_flow_dynf_metadata_set``
> 
> +* **mlx5: promoted driver event and steering management APIs from
> +experimental to stable.**
> +
> +  The following mlx5 APIs are no longer marked experimental:
> +
> +  - ``rte_pmd_mlx5_driver_event_cb_register``
> +  - ``rte_pmd_mlx5_driver_event_cb_unregister``
> +  - ``rte_pmd_mlx5_enable_steering``
> +  - ``rte_pmd_mlx5_disable_steering``
> +
> 
>  ABI Changes
>  -----------
> diff --git a/drivers/net/mlx5/mlx5_driver_event.c
> b/drivers/net/mlx5/mlx5_driver_event.c
> index 1dc8029ee5..89e49331c8 100644
> --- a/drivers/net/mlx5/mlx5_driver_event.c
> +++ b/drivers/net/mlx5/mlx5_driver_event.c
> @@ -236,7 +236,7 @@
> notify_existing_devices(rte_pmd_mlx5_driver_event_callback_t cb, void
> *opaque)
>  		notify_existing_queues(port_id, cb, opaque);  }
> 
> -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_driver_event_cb_register,
> 25.11)
> +RTE_EXPORT_SYMBOL(rte_pmd_mlx5_driver_event_cb_register)
>  int
> 
> rte_pmd_mlx5_driver_event_cb_register(rte_pmd_mlx5_driver_event_callback_t
> cb, void *opaque)  { @@ -264,7 +264,7 @@
> rte_pmd_mlx5_driver_event_cb_register(rte_pmd_mlx5_driver_event_callback_t
> cb, v
>  	return 0;
>  }
> 
> -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_driver_event_cb_unregister,
> 25.11)
> +RTE_EXPORT_SYMBOL(rte_pmd_mlx5_driver_event_cb_unregister)
>  int
> 
> rte_pmd_mlx5_driver_event_cb_unregister(rte_pmd_mlx5_driver_event_callback
> _t cb)  { diff --git a/drivers/net/mlx5/mlx5_flow.c
> b/drivers/net/mlx5/mlx5_flow.c index 915ea29a5a..a95dd9dc94 100644
> --- a/drivers/net/mlx5/mlx5_flow.c
> +++ b/drivers/net/mlx5/mlx5_flow.c
> @@ -12506,7 +12506,7 @@ flow_disable_steering_run_on_related(struct
> rte_eth_dev *dev,
>  	}
>  }
> 
> -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_disable_steering, 25.11)
> +RTE_EXPORT_SYMBOL(rte_pmd_mlx5_disable_steering)
>  void
>  rte_pmd_mlx5_disable_steering(void)
>  {
> @@ -12532,7 +12532,7 @@ rte_pmd_mlx5_disable_steering(void)
>  	mlx5_steering_disabled = true;
>  }
> 
> -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_enable_steering, 25.11)
> +RTE_EXPORT_SYMBOL(rte_pmd_mlx5_enable_steering)
>  int
>  rte_pmd_mlx5_enable_steering(void)
>  {
> diff --git a/drivers/net/mlx5/rte_pmd_mlx5.h
> b/drivers/net/mlx5/rte_pmd_mlx5.h index 55a26cb067..f482875434 100644
> --- a/drivers/net/mlx5/rte_pmd_mlx5.h
> +++ b/drivers/net/mlx5/rte_pmd_mlx5.h
> @@ -620,7 +620,6 @@ int rte_pmd_mlx5_external_sq_disable(uint16_t port_id,
> uint32_t sq_num);
>   *   - (-EEXIST) if @p cb was already registered.
>   *   - (-ENOMEM) if failed to allocate memory for callback entry.
>   */
> -__rte_experimental
>  int
> 
> rte_pmd_mlx5_driver_event_cb_register(rte_pmd_mlx5_driver_event_callback_t
> cb, void *opaque);
> 
> @@ -641,7 +640,6 @@
> rte_pmd_mlx5_driver_event_cb_register(rte_pmd_mlx5_driver_event_callback_t
> cb, v
>   *   - 0 if callback was successfully unregistered or if no such callback
> was registered.
>   *   - (-EINVAL) if @p cb is NULL.
>   */
> -__rte_experimental
>  int
> 
> rte_pmd_mlx5_driver_event_cb_unregister(rte_pmd_mlx5_driver_event_callback
> _t cb);
> 
> @@ -679,7 +677,6 @@
> rte_pmd_mlx5_driver_event_cb_unregister(rte_pmd_mlx5_driver_event_callback
> _t cb)
>   * with other functions from ethdev API used to configure any of the mlx5
> ports.
>   * It is the responsibility of the application to enforce this.
>   */
> -__rte_experimental
>  void
>  rte_pmd_mlx5_disable_steering(void);
> 
> @@ -697,7 +694,6 @@ rte_pmd_mlx5_disable_steering(void);
>   *   - 0 - Flow steering was successfully enabled or it flow steering was
> never disabled.
>   *   - (-EBUSY) - There are mlx5 ports probed and re-enabling steering
> cannot be done safely.
>   */
> -__rte_experimental
>  int
>  rte_pmd_mlx5_enable_steering(void);
> 
> --
> 2.47.3

Acked-by: Bing Zhao <bingz@nvidia.com>

^ permalink raw reply

* [PATCH v2] devtools: add Vertex AI to review scripts
From: David Marchand @ 2026-06-02  6:44 UTC (permalink / raw)
  To: dev; +Cc: thomas, Stephen Hemminger, Aaron Conole
In-Reply-To: <20260601132402.1125588-1-david.marchand@redhat.com>

Add support for Google Vertex AI authentication as an alternative to
direct API key authentication. All four providers (Anthropic, Google,
OpenAI, xAI) can now use Vertex AI with Application Default Credentials.

This requires a python dependency google-auth but it is left as
optional.

Key features:
- Auto-detection of authentication method based on environment
- Manual override via --auth flag (auto, direct, vertex)
- Automatic model name translation for Vertex format
- Support for both global and regional Vertex endpoints
- Proper error handling for Vertex API responses

Provider-specific implementations:
- Anthropic: Uses /publishers/anthropic/models/{model}:rawPredict
  with model name format claude-sonnet-4-5@20250929
- Google: Uses /publishers/google/models/{model}:generateContent
- OpenAI/xAI: Use /endpoints/openapi/chat/completions
  with publisher prefix (e.g., openai/gpt-oss-120b-maas)

Authentication detection logic:
- Vertex: Requires google-auth library and ADC configured
- Direct: Falls back to API key from environment variables

Available models on Vertex AI:
- Anthropic: All Claude models
- Google: All Gemini models
- OpenAI: gpt-oss-120b-maas, gpt-oss-20b-maas (open-weight only)
- xAI: grok-4.20-*, grok-4.1-fast-* variants

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Note: I only tested Vertex.
I have no API key to double check the "direct" method is still working.

Changes since v1:
- factorized auth string generation,
- enhanced -l option (offlist comment from Maxime),
- fixed some pylint warnings introduced by changes,

---
 devtools/ai/_common.py      | 204 +++++++++++++++++++++++++++++++++---
 devtools/ai/review-doc.py   |  26 ++---
 devtools/ai/review-patch.py |  30 +++---
 3 files changed, 215 insertions(+), 45 deletions(-)

diff --git a/devtools/ai/_common.py b/devtools/ai/_common.py
index 69982cbda5..3e70f4cd6f 100644
--- a/devtools/ai/_common.py
+++ b/devtools/ai/_common.py
@@ -6,6 +6,7 @@
 
 import argparse
 import json
+import os
 import subprocess
 import sys
 from dataclasses import dataclass
@@ -13,6 +14,14 @@
 from urllib.error import HTTPError, URLError
 from urllib.request import Request, urlopen
 
+# Optional dependency for Vertex AI
+try:
+    from google.auth import default as google_auth_default
+    from google.auth.transport.requests import Request as GoogleAuthRequest
+    VERTEX_AI_AVAILABLE = True
+except ImportError:
+    VERTEX_AI_AVAILABLE = False
+
 # Provider configurations (model defaults; override with --model).
 PROVIDERS: dict[str, dict[str, str]] = {
     "anthropic": {
@@ -65,10 +74,14 @@ def get_git_config(key: str) -> str | None:
 def list_providers() -> NoReturn:
     """Print available providers and exit."""
     print("Available AI Providers:\n")
-    print(f"{'Provider':<12} {'Default Model':<30} {'API Key Variable'}")
-    print(f"{'--------':<12} {'-------------':<30} {'----------------'}")
+    print(f"{'Provider':<12} {'Default Model':<30} {'API Key (Direct Auth)'}")
+    print(f"{'--------':<12} {'-------------':<30} {'---------------------'}")
     for name, config in PROVIDERS.items():
         print(f"{name:<12} {config['default_model']:<30} {config['env_var']}")
+    if VERTEX_AI_AVAILABLE:
+        print("\nVertex AI authentication is available (use --auth vertex)")
+    else:
+        print("\nVertex AI authentication requires: pip install google-auth")
     sys.exit(0)
 
 
@@ -128,25 +141,167 @@ def print_token_summary(
     print(format_token_summary(usage, provider, model), file=sys.stderr)
 
 
+def get_vertex_credentials() -> tuple[str, str]:
+    """Get Google Cloud access token and project for Vertex AI.
+
+    Uses Application Default Credentials (ADC).
+    Requires: gcloud auth application-default login
+
+    Returns: (access_token, project_id)
+    """
+    credentials, project = google_auth_default()
+
+    # Refresh credentials to get access token
+    auth_request = GoogleAuthRequest()
+    credentials.refresh(auth_request)
+
+    if not project:
+        error("Could not detect GCP project. Set GOOGLE_CLOUD_PROJECT environment variable or run: gcloud config set project PROJECT_ID")
+
+    return credentials.token, project
+
+
+def model_to_vertex(model: str, provider: str) -> str:
+    """Convert model name to Vertex AI format.
+
+    Anthropic models use @ for version dates:
+    - API format: claude-sonnet-4-5-20250929
+    - Vertex format: claude-sonnet-4-5@20250929
+
+    OpenAI/xAI models need publisher prefix:
+    - Vertex requires: openai/gpt-oss-120b-maas
+
+    Other providers use the same format for both.
+    """
+    if provider == "anthropic":
+        # Match pattern: ends with -YYYYMMDD (8 digits)
+        if model.count('-') >= 3:
+            parts = model.rsplit('-', 1)
+            if len(parts) == 2 and len(parts[1]) == 8 and parts[1].isdigit():
+                return f"{parts[0]}@{parts[1]}"
+    elif provider in ("openai", "xai"):
+        # Add publisher prefix if not already present
+        if "/" not in model:
+            return f"{provider}/{model}"
+    return model
+
+
+def detect_auth_method(provider: str) -> str:
+    """Detect authentication method for a provider.
+
+    Args:
+        provider: The provider name (e.g., "anthropic", "openai")
+
+    Returns:
+        "direct" or "vertex"
+    """
+    env_var = PROVIDERS[provider]["env_var"]
+    if os.environ.get(env_var):
+        return "direct"
+    if VERTEX_AI_AVAILABLE:
+        try:
+            credentials, project = google_auth_default()
+            if credentials and project:
+                return "vertex"
+        except Exception:
+            pass
+    return "direct"
+
+
+def get_auth_string(auth_choice: str, provider: str) -> str:
+    """Get authentication string for API requests.
+
+    Args:
+        auth_choice: User's auth choice ("auto", "direct", or "vertex")
+        provider: Provider name
+
+    Returns:
+        Authentication string - either "vertex" or "direct:<api_key>"
+    """
+    config = PROVIDERS[provider]
+
+    # Determine actual auth method
+    if auth_choice == "auto":
+        auth_method = detect_auth_method(provider)
+    else:
+        auth_method = auth_choice
+
+    # Build auth string based on method
+    if auth_method == "vertex":
+        if not VERTEX_AI_AVAILABLE:
+            error("Vertex AI support requires 'google-auth' library. Install with: pip install google-auth")
+        return "vertex"
+
+    api_key = os.environ.get(config["env_var"])
+    if not api_key:
+        error(f"{config['env_var']} environment variable not set")
+    return f"direct:{api_key}"
+
+
 def _build_request_meta(
-    provider: str, api_key: str, model: str
-) -> tuple[str, dict[str, str]]:
-    """Return (url, headers) for a provider request."""
+    provider: str, auth: str, model: str, request_data: dict[str, Any]
+) -> tuple[str, dict[str, str], dict[str, Any]]:
+    """Return (url, headers, request_data) for a provider request.
+
+    Args:
+        provider: Provider name
+        auth: Authentication string - either "direct:<api_key>" or "vertex"
+        model: Model identifier
+        request_data: The request payload (may be modified for Vertex)
+
+    Returns:
+        Tuple of (url, headers, modified_request_data)
+    """
     config = PROVIDERS[provider]
-    if provider == "anthropic":
+
+    if auth.startswith("direct:"):
+        api_key = auth[7:]
+        if provider == "anthropic":
+            request_data["model"] = model
+            return config["endpoint"], {
+                "Content-Type": "application/json",
+                "x-api-key": api_key,
+                "anthropic-version": "2023-06-01",
+            }, request_data
+        if provider == "google":
+            url = f"{config['endpoint']}/{model}:generateContent?key={api_key}"
+            return url, {"Content-Type": "application/json"}, request_data
+        # openai, xai
+        request_data["model"] = model
         return config["endpoint"], {
             "Content-Type": "application/json",
-            "x-api-key": api_key,
-            "anthropic-version": "2023-06-01",
-        }
-    if provider == "google":
-        url = f"{config['endpoint']}/{model}:generateContent?key={api_key}"
-        return url, {"Content-Type": "application/json"}
-    # openai, xai
-    return config["endpoint"], {
+            "Authorization": f"Bearer {api_key}",
+        }, request_data
+
+    # Vertex AI authentication
+    if auth != "vertex":
+        error(f"Invalid auth format: {auth}")
+
+    access_token, project_id = get_vertex_credentials()
+    project_id = os.environ.get("GOOGLE_CLOUD_PROJECT") or os.environ.get("GCP_PROJECT") or project_id
+    location = os.environ.get("CLOUD_ML_REGION", "global")
+
+    if location == "global":
+        vertex_base = f"https://aiplatform.googleapis.com/v1/projects/{project_id}/locations/{location}"
+    else:
+        vertex_base = f"https://{location}-aiplatform.googleapis.com/v1/projects/{project_id}/locations/{location}"
+
+    headers = {
         "Content-Type": "application/json",
-        "Authorization": f"Bearer {api_key}",
+        "Authorization": f"Bearer {access_token}",
     }
+    vertex_model = model_to_vertex(model, provider)
+
+    if provider == "anthropic":
+        request_data["anthropic_version"] = "vertex-2023-10-16"
+        url = f"{vertex_base}/publishers/anthropic/models/{vertex_model}:rawPredict"
+    elif provider == "google":
+        url = f"{vertex_base}/publishers/google/models/{vertex_model}:generateContent"
+    else:  # openai, xai
+        request_data["model"] = vertex_model
+        url = f"{vertex_base}/endpoints/openapi/chat/completions"
+
+    return url, headers, request_data
 
 
 def _extract_usage(provider: str, result: dict[str, Any]) -> TokenUsage:
@@ -208,7 +363,7 @@ def _print_verbose_usage(usage: TokenUsage) -> None:
 
 def send_request(
     provider: str,
-    api_key: str,
+    auth: str,
     model: str,
     request_data: dict[str, Any],
     *,
@@ -220,8 +375,19 @@ def send_request(
     The caller assembles the provider-specific request body via its own
     build_*_request helpers (the prompts differ per script). This function
     handles transport, error reporting, and token-usage extraction.
+
+    Args:
+        provider: Provider name (anthropic, openai, xai, google)
+        auth: Authentication string - either "direct:<api_key>" or "vertex"
+        model: Model identifier
+        request_data: Provider-specific request payload
+        timeout: Request timeout in seconds
+        verbose: Show detailed token usage
+
+    Returns:
+        Tuple of (response_text, token_usage)
     """
-    url, headers = _build_request_meta(provider, api_key, model)
+    url, headers, request_data = _build_request_meta(provider, auth, model, request_data)
     body = json.dumps(request_data).encode("utf-8")
     req = Request(url, data=body, headers=headers)
 
@@ -232,6 +398,8 @@ def send_request(
         error_body = e.read().decode("utf-8")
         try:
             error_data = json.loads(error_body)
+            if isinstance(error_data, list) and error_data:
+                error_data = error_data[0]
             error(f"API error: {error_data.get('error', error_body)}")
         except json.JSONDecodeError:
             error(f"API error ({e.code}): {error_body}")
@@ -239,6 +407,8 @@ def send_request(
         if isinstance(e.reason, TimeoutError):
             error(f"Request timed out after {timeout} seconds")
         error(f"Connection error: {e.reason}")
+    except TimeoutError:
+        error(f"Request timed out after {timeout} seconds")
 
     usage = _extract_usage(provider, result)
     if verbose:
diff --git a/devtools/ai/review-doc.py b/devtools/ai/review-doc.py
index 24e70ae06b..e01be077fe 100755
--- a/devtools/ai/review-doc.py
+++ b/devtools/ai/review-doc.py
@@ -27,6 +27,7 @@
     TokenUsage,
     add_token_args,
     error,
+    get_auth_string,
     get_git_config,
     list_providers,
     print_token_summary,
@@ -259,7 +260,6 @@ def build_user_prompt(
 
 
 def build_anthropic_request(
-    model: str,
     max_tokens: int,
     agents_content: str,
     doc_content: str,
@@ -273,7 +273,6 @@ def build_anthropic_request(
         doc_file, commit_prefix, output_format, include_diff_markers
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "system": [
             {"type": "text", "text": SYSTEM_PROMPT},
@@ -293,7 +292,6 @@ def build_anthropic_request(
 
 
 def build_openai_request(
-    model: str,
     max_tokens: int,
     agents_content: str,
     doc_content: str,
@@ -307,7 +305,6 @@ def build_openai_request(
         doc_file, commit_prefix, output_format, include_diff_markers
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "messages": [
             {"role": "system", "content": SYSTEM_PROMPT},
@@ -352,7 +349,7 @@ def build_google_request(
 
 def call_api(
     provider: str,
-    api_key: str,
+    auth: str,
     model: str,
     max_tokens: int,
     agents_content: str,
@@ -367,7 +364,6 @@ def call_api(
     """Build the per-provider request body and dispatch via _common."""
     if provider == "anthropic":
         request_data = build_anthropic_request(
-            model,
             max_tokens,
             agents_content,
             doc_content,
@@ -388,7 +384,6 @@ def call_api(
         )
     else:  # openai, xai
         request_data = build_openai_request(
-            model,
             max_tokens,
             agents_content,
             doc_content,
@@ -399,7 +394,7 @@ def call_api(
         )
     return send_request(
         provider,
-        api_key,
+        auth,
         model,
         request_data,
         timeout=timeout,
@@ -631,6 +626,12 @@ def main() -> None:
         help="Show API request details",
     )
     add_token_args(parser)
+    parser.add_argument(
+        "--auth",
+        choices=["auto", "direct", "vertex"],
+        default="auto",
+        help="Authentication method: auto (default), direct (API key), vertex (Google Cloud)",
+    )
     parser.add_argument(
         "-q",
         "--quiet",
@@ -709,10 +710,8 @@ def main() -> None:
     config = PROVIDERS[args.provider]
     model = args.model or config["default_model"]
 
-    # Get API key
-    api_key = os.environ.get(config["env_var"])
-    if not api_key:
-        error(f"{config['env_var']} environment variable not set")
+    # Get authentication string
+    auth = get_auth_string(args.auth, args.provider)
 
     # Validate files
     agents_path = Path(args.agents)
@@ -783,6 +782,7 @@ def main() -> None:
         if args.verbose:
             print("=== Request ===", file=sys.stderr)
             print(f"Provider: {args.provider}", file=sys.stderr)
+            print(f"Auth method: {'vertex' if auth == 'vertex' else 'direct'}", file=sys.stderr)
             print(f"Model: {model}", file=sys.stderr)
             print(f"Output format: {args.output_format}", file=sys.stderr)
             print(f"AGENTS file: {args.agents}", file=sys.stderr)
@@ -800,7 +800,7 @@ def main() -> None:
         # Call API
         review_text, call_usage = call_api(
             args.provider,
-            api_key,
+            auth,
             model,
             args.tokens,
             agents_content,
diff --git a/devtools/ai/review-patch.py b/devtools/ai/review-patch.py
index 52601ac156..9ac227000e 100755
--- a/devtools/ai/review-patch.py
+++ b/devtools/ai/review-patch.py
@@ -25,6 +25,7 @@
     TokenUsage,
     add_token_args,
     error,
+    get_auth_string,
     get_git_config,
     list_providers,
     print_token_summary,
@@ -460,7 +461,6 @@ def build_system_prompt(review_date: str, release: str | None) -> str:
 
 
 def build_anthropic_request(
-    model: str,
     max_tokens: int,
     system_prompt: str,
     agents_content: str,
@@ -474,7 +474,6 @@ def build_anthropic_request(
         patch_name=patch_name, format_instruction=format_instruction
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "system": [
             {"type": "text", "text": system_prompt},
@@ -494,7 +493,6 @@ def build_anthropic_request(
 
 
 def build_openai_request(
-    model: str,
     max_tokens: int,
     system_prompt: str,
     agents_content: str,
@@ -508,7 +506,6 @@ def build_openai_request(
         patch_name=patch_name, format_instruction=format_instruction
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "messages": [
             {"role": "system", "content": system_prompt},
@@ -553,7 +550,7 @@ def build_google_request(
 
 def call_api(
     provider: str,
-    api_key: str,
+    auth: str,
     model: str,
     max_tokens: int,
     system_prompt: str,
@@ -567,7 +564,6 @@ def call_api(
     """Build the per-provider request body and dispatch via _common."""
     if provider == "anthropic":
         request_data = build_anthropic_request(
-            model,
             max_tokens,
             system_prompt,
             agents_content,
@@ -586,7 +582,6 @@ def call_api(
         )
     else:  # openai, xai
         request_data = build_openai_request(
-            model,
             max_tokens,
             system_prompt,
             agents_content,
@@ -596,7 +591,7 @@ def call_api(
         )
     return send_request(
         provider,
-        api_key,
+        auth,
         model,
         request_data,
         timeout=timeout,
@@ -813,6 +808,12 @@ def main() -> None:
         help="Show API request details",
     )
     add_token_args(parser)
+    parser.add_argument(
+        "--auth",
+        choices=["auto", "direct", "vertex"],
+        default="auto",
+        help="Authentication method: auto (default), direct (API key), vertex (Google Cloud)",
+    )
     parser.add_argument(
         "-f",
         "--format",
@@ -930,10 +931,8 @@ def main() -> None:
     config = PROVIDERS[args.provider]
     model = args.model or config["default_model"]
 
-    # Get API key
-    api_key = os.environ.get(config["env_var"])
-    if not api_key:
-        error(f"{config['env_var']} environment variable not set")
+    # Get authentication string
+    auth = get_auth_string(args.auth, args.provider)
 
     # Validate files
     agents_path = Path(args.agents)
@@ -1041,7 +1040,7 @@ def main() -> None:
 
                 review_text, call_usage = call_api(
                     args.provider,
-                    api_key,
+                    auth,
                     model,
                     args.tokens,
                     system_prompt,
@@ -1111,7 +1110,7 @@ def main() -> None:
 
                 review_text, call_usage = call_api(
                     args.provider,
-                    api_key,
+                    auth,
                     model,
                     args.tokens,
                     system_prompt,
@@ -1136,6 +1135,7 @@ def main() -> None:
     if args.verbose:
         print("=== Request ===", file=sys.stderr)
         print(f"Provider: {args.provider}", file=sys.stderr)
+        print(f"Auth method: {'vertex' if auth == 'vertex' else 'direct'}", file=sys.stderr)
         print(f"Model: {model}", file=sys.stderr)
         print(f"Review date: {review_date}", file=sys.stderr)
         if args.release:
@@ -1164,7 +1164,7 @@ def main() -> None:
     if estimated_tokens > 0:  # Not already processed
         review_text, call_usage = call_api(
             args.provider,
-            api_key,
+            auth,
             model,
             args.tokens,
             system_prompt,
-- 
2.53.0


^ permalink raw reply related

* RE: [PATCH v7] net/idpf: update for new mempool cache algorithm
From: Morten Brørup @ 2026-06-02  6:45 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260601183621.252920-1-mb@smartsharesystems.com>

Recheck-request: iol-unit-arm64-testing

CI subsystem log:

[176/407] Compiling C object lib/librte_cmdline.a.p/cmdline_cmdline.c.o
FAILED: lib/librte_cmdline.a.p/cmdline_cmdline.c.o
gcc-10 -Ilib/librte_cmdline.a.p -Ilib -I../lib -Ilib/cmdline -I../lib/cmdline -Ilib/eal/common -I../lib/eal/common -I. -I.. -Iconfig -I../config -Ilib/eal/include -I../lib/eal/include -Ilib/eal/linux/include -I../lib/eal/linux/include -Ilib/eal/arm/include -I../lib/eal/arm/include -I../kernel/linux -Ilib/eal -I../lib/eal -Ilib/kvargs -I../lib/kvargs -Ilib/log -I../lib/log -I../lib/metrics -Ilib/telemetry -I../lib/telemetry -Ilib/argparse -I../lib/argparse -Ilib/net -I../lib/net -Ilib/mbuf -I../lib/mbuf -Ilib/mempool -I../lib/mempool -Ilib/ring -I../lib/ring -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c11 -O3 -include rte_config.h -Wvla -Wcast-qual -Wdeprecated -Wformat -Wformat-nonliteral -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wno-packed-not-aligned -Wno-missing-field-initializers -D_GN
 U_SOURCE -fPIC -march=armv8.2-a+crypto+sve -DALLOW_EXPERIMENTAL_API -DALLOW_INTERNAL_API -DRTE_LOG_DEFAULT_LOGTYPE=lib.cmdline -MD -MQ lib/librte_cmdline.a.p/cmdline_cmdline.c.o -MF lib/librte_cmdline.a.p/cmdline_cmdline.c.o.d -o lib/librte_cmdline.a.p/cmdline_cmdline.c.o -c ../lib/cmdline/cmdline.c
gcc-10: internal compiler error: Segmentation fault signal terminated program cc1
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-10/README.Bugs> for instructions.


^ permalink raw reply

* RE: [PATCH v7] mempool/dpaa: update for new mempool cache algorithm
From: Morten Brørup @ 2026-06-02  6:51 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260601183621.252920-2-mb@smartsharesystems.com>

Recheck-request: iol-unit-arm64-testing

CI log:
==== Unit test summary for Red Hat Enterprise Linux 9.7 (dpdk_unit_test): ====
[...]
53/145 DPDK:fast-tests / eal_flags_file_prefix_autotest           FAIL             0.88s   (exit status 255 or signal 127 SIGinvalid)
>>> DPDK_TEST=eal_flags_file_prefix_autotest MALLOC_PERTURB_=192 /home-local/jenkins-local/jenkins-agent/workspace/Generic-Unit-Test-DPDK/dpdk/build/app/dpdk-test --file-prefix=eal_flags_file_prefix_autotest
[...]
Error (line 1407) - failed to run with --file-prefix=memtest1
Test Failed


^ permalink raw reply

* RE: [PATCH v7] mempool/dpaa2: update for new mempool cache algorithm
From: Morten Brørup @ 2026-06-02  6:53 UTC (permalink / raw)
  To: dev
In-Reply-To: <20260601183621.252920-3-mb@smartsharesystems.com>

Recheck-request: iol-unit-arm64-testing

CI subsystem log:
==== 20 line log output for Ubuntu 24.04 (lpm_autotest): ====
[...]
[89/406] Compiling C object lib/librte_eal.a.p/eal_linux_eal_timer.c.o
FAILED: lib/librte_eal.a.p/eal_linux_eal_timer.c.o
gcc-10 -Ilib/librte_eal.a.p -Ilib -I../lib -Ilib/eal/common -I../lib/eal/common -I. -I.. -Iconfig -I../config -Ilib/eal/include -I../lib/eal/include -Ilib/eal/linux/include -I../lib/eal/linux/include -Ilib/eal/arm/include -I../lib/eal/arm/include -I../kernel/linux -Ilib/eal -I../lib/eal -Ilib/kvargs -I../lib/kvargs -Ilib/log -I../lib/log -I../lib/metrics -Ilib/telemetry -I../lib/telemetry -Ilib/argparse -I../lib/argparse -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c11 -O3 -include rte_config.h -Wvla -Wcast-qual -Wdeprecated -Wformat -Wformat-nonliteral -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wno-packed-not-aligned -Wno-missing-field-initializers -D_GNU_SOURCE -fPIC -march=armv8.2-a+crypto+sve -DALLOW_EXPERIMENTAL_API -DALLOW_INTERNAL_API '-DABI_VERSION="26.2"' -DRTE_LOG_DEFAULT_LOGTYPE=l
 ib.eal -MD -MQ lib/librte_eal.a.p/eal_linux_eal_timer.c.o -MF lib/librte_eal.a.p/eal_linux_eal_timer.c.o.d -o lib/librte_eal.a.p/eal_linux_eal_timer.c.o -c ../lib/eal/linux/eal_timer.c
gcc-10: internal compiler error: Segmentation fault signal terminated program cc1
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-10/README.Bugs> for instructions.


^ permalink raw reply

* RE: [PATCH v2] doc, eal, devtools: discourage new __rte_always_inline
From: Konstantin Ananyev @ 2026-06-02  7:07 UTC (permalink / raw)
  To: Stephen Hemminger, dev@dpdk.org; +Cc: Thomas Monjalon
In-Reply-To: <20260601172104.311909-1-stephen@networkplumber.org>



> Modern compilers at -O2 make good inlining decisions for small
> static inline functions; forced inlining via __rte_always_inline
> should be reserved for cases where it is required for correctness
> or for documented measured performance reasons.
> 
> Document the policy in the coding style guide and add a
> checkpatches.sh entry that flags when new uses of the attribute
> are introduced. Checkpatches is not an absolute blocker to
> acceptance, only an indicator that more review is needed.
> 
> Add additional comments about use of __rte_always_inline,
> __rte_noinline, __rte_hot, and __rte_cold to the rte_common.h
> to aid developers.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  devtools/checkpatches.sh                 |  8 +++++
>  doc/guides/contributing/coding_style.rst | 26 ++++++++++++++++-
>  lib/eal/include/rte_common.h             | 37 ++++++++++++++++++++++--
>  3 files changed, 68 insertions(+), 3 deletions(-)
> 
> diff --git a/devtools/checkpatches.sh b/devtools/checkpatches.sh
> index f5dd77443f..2a3d364178 100755
> --- a/devtools/checkpatches.sh
> +++ b/devtools/checkpatches.sh
> @@ -137,6 +137,14 @@ check_forbidden_additions() { # <patch>
>  		-f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \
>  		"$1" || res=1
> 
> +	# forbid new use of __rte_always_inline
> +	awk -v FOLDERS="lib drivers app examples" \
> +		-v EXPRESSIONS='\\<__rte_always_inline\\>' \
> +		-v RET_ON_FAIL=1 \
> +		-v MESSAGE='Adding __rte_always_inline; prefer plain inline' \
> +		-f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \
> +		"$1" || res=1
> +
>  	# refrain from using compiler __rte_atomic_thread_fence()
>  	# It should be avoided on x86 for SMP case.
>  	awk -v FOLDERS="lib drivers app examples" \
> diff --git a/doc/guides/contributing/coding_style.rst
> b/doc/guides/contributing/coding_style.rst
> index 243a3c2959..8f9e77d1c1 100644
> --- a/doc/guides/contributing/coding_style.rst
> +++ b/doc/guides/contributing/coding_style.rst
> @@ -747,11 +747,35 @@ Static Variables and Functions
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
>  * All functions and variables that are local to a file must be declared as ``static``
> because it can often help the compiler to do some optimizations (such as, inlining
> the code).
> -* Functions that should be inlined should to be declared as ``static inline`` and
> can be defined in a .c or a .h file.
> +* Functions that should be inlined should be declared as ``static inline`` and can
> be defined in a .c or a .h file.
> 
>  .. note::
>  	Static functions defined in a header file must be declared as ``static
> inline`` in order to prevent compiler warnings about the function being unused.
> 
> +Use of ``__rte_always_inline``
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The ``__rte_always_inline`` attribute forces the compiler to inline a function
> regardless of its size or call-graph heuristics.
> +Prefer plain ``inline`` (or no annotation at all for static functions) and let the
> compiler decide.
> +Modern compilers at ``-O2`` make good inlining decisions for small ``static
> inline`` functions in headers,
> +and forced inlining can hurt performance by inflating function bodies, increasing
> register pressure, and overriding profile-guided optimization.
> +
> +``__rte_always_inline`` should only be used when one of the following applies:
> +
> +* The function contains ``__rte_constant()`` checks that gate a constant-folded
> fast path,
> +  and the optimization is lost if the function is not inlined into the caller.
> +  Examples include byte-order helpers and length-dispatched copy/compare
> routines.
> +
> +* The function wraps inline assembly or a compiler intrinsic whose correctness
> depends on being inlined into the caller's register context (for example, intrinsics
> requiring a compile-time constant argument).
> +
> +* Measurement on a representative workload shows that the annotation is
> required to retain performance, and the reason is documented in the commit
> message that introduces it.
> +
> +Each use must be justified at the point it is introduced. Adding
> ``__rte_always_inline`` because nearby code uses it is not a justification;
> +if the constant or intrinsic that requires inlining is several call levels up the call
> chain,
> +restructure the code rather than annotating the entire chain.
> +
> +The complementary attribute ``__rte_noinline`` is useful for explicitly marking
> cold paths (error handling, initialization, slow-path fallbacks) where outlining the
> function can reduce instruction-cache pressure on the hot path.
> +
>  Const Attribute
>  ~~~~~~~~~~~~~~~
> 
> diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
> index 71415346cf..e358be7fcf 100644
> --- a/lib/eal/include/rte_common.h
> +++ b/lib/eal/include/rte_common.h
> @@ -482,7 +482,22 @@ static void __attribute__((destructor(RTE_PRIO(prio)),
> used)) func(void)
>  #endif
> 
>  /**
> - * Force a function to be inlined
> + * Force a function to be inlined, regardless of the compiler's size and
> + * call-graph heuristics.
> + *
> + * Prefer plain @c inline (or no annotation on a static function) and let the
> compiler decide.
> + * Modern compilers at -O2 inline small static functions well,
> + * and forcing it can hurt by inflating call sites, raising register pressure,
> + * and overriding profile-guided optimization.
> + *
> + * Reserve this attribute for cases where inlining is required for
> + * correctness, or for a documented and measured performance reason, e.g.
> + *  - a constant-folded fast path gated by @c __rte_constant() that is lost
> + *    unless the function is inlined into the caller;
> + *  - a wrapper around inline asm or an intrinsic that needs a
> + *    compile-time-constant argument from the caller's context.
> + *
> + * See the DPDK coding style guide for the full policy.
>   */
>  #ifdef RTE_TOOLCHAIN_MSVC
>  #define __rte_always_inline __forceinline
> @@ -491,7 +506,11 @@ static void __attribute__((destructor(RTE_PRIO(prio)),
> used)) func(void)
>  #endif
> 
>  /**
> - * Force a function to be noinlined
> + * Force a function not to be inlined.
> + *
> + * Useful for explicitly outlining cold paths such as error handling,
> + * initialization, slow-path fallbacks, so they do not bloat the hot path
> + * or add to its instruction-cache footprint.
>   */
>  #ifdef RTE_TOOLCHAIN_MSVC
>  #define __rte_noinline __declspec(noinline)
> @@ -501,6 +520,12 @@ static void __attribute__((destructor(RTE_PRIO(prio)),
> used)) func(void)
> 
>  /**
>   * Hint function in the hot path
> + *
> + * The compiler may optimize the function more aggressively, treat calls
> + * to it as likely for branch prediction, and group it with other hot
> + * functions to improve instruction-cache locality. This affects code
> + * placement and prediction, not inlining; combine with an inline
> + * annotation if both are wanted.
>   */
>  #ifdef RTE_TOOLCHAIN_MSVC
>  #define __rte_hot
> @@ -510,6 +535,14 @@ static void __attribute__((destructor(RTE_PRIO(prio)),
> used)) func(void)
> 
>  /**
>   * Hint function in the cold path
> + *
> + * The compiler optimizes the function for size rather than speed,
> + * marks branches that reach it as unlikely, and may move it to a separate
> + * section to keep it off the hot path and reduce instruction-cache
> + * pressure there.
> + *
> + * Suitable for error handling, logging, and setup/teardown code.
> + * Functions marked @c __rte_noreturn are already treated as cold.
>   */
>  #ifdef RTE_TOOLCHAIN_MSVC
>  #define __rte_cold
> --

Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>

> 2.53.0


^ permalink raw reply

* RE: [PATCH v2] app/test-pmd: add generic PROG action parser support
From: Konstantin Ananyev @ 2026-06-02  7:35 UTC (permalink / raw)
  To: Ajmera, Megha, Stephen Hemminger
  Cc: Richardson, Bruce, Dumitrescu, Cristian, Shetty, Praveen,
	Singh, Aman Deep, dev@dpdk.org
In-Reply-To: <MW4PR11MB589273F3A331E94D0876900D97152@MW4PR11MB5892.namprd11.prod.outlook.com>



> > For my own curiosity: how user can define his own PROG action?
> > Is it supposed to be programmed and uplodaded to the NIC by some external
> tool
> > (P4 compiler)?
> > Or does it refer to the set of some predefined functions that given firmware
> > supports?
> > Or ... ?
> > Sorry for probably naive questions, but I found is nearly zero information inside
> > DPDK docs about how PROG action supposed to work.
> 
> PROG in rte_flow is currently a vendor-defined action interface (name +
> arguments), not a generic DPDK programming model by itself.
> 
> So in practice:
> 
> 1. DPDK/testpmd does not define or upload user code to NIC on its own.
> 2. testpmd just passes the prog name/argument/payload to the PMD via
> rte_flow.
> 3. What that name/arguments means is NIC/firmware specific.
> 4. Depending on device support, it may map to predefined firmware-exposed
> functions

Ok, so it is predefined by the FW.
Then shouldn't CPFL PG contain a list of supported PROGs and their arguments?
Again, some tests/examples for it with testpmd/DTS.
Or that's all will be the next step (patch-series)?   
 
> 5. If the PMD/firmware does not recognize it, flow validate/create will fail.


^ permalink raw reply

* RE: [PATCH] ring: avoid extra store at move head
From: Konstantin Ananyev @ 2026-06-02  9:02 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev@dpdk.org
In-Reply-To: <20260601152313.1946d438@phoenix.local>



> > C11 __rte_ring_headtail_move_head_mt() uses output
> > parameter: 'uint32_t *old_head' directly within CAS operation.
> > In x86_64 that cause gcc to generate extra instructions to
> > store return value of CAS (eax) within 'old_head' memory location,
> > even when CAS was not successful and another attempt should be
> > performed. In some cases, even extra branch can be observed.
> > To be more specific the code like that is generated:
> > // start of 'do { } while();' loop
> > .L2
> >         ...
> >         lock cmpxchgl   %r8d, (%rdi)
> >         jne     .L17  //
> > .L1: // <---- successful completion of CAS, finish
> >         movl    %edx, %eax
> >         ret
> > .L17: // <---- unsuccessful completion of CAS, repeat
> >         movl    %eax, (%r9)
> >         jmp     .L2
> >
> > In constrast, x86 specific version that uses
> > __sync_bool_compare_and_swap() doesn't exibit such problem,
> > as __sync_bool_compare_and_swap() doesn't update the 'old_head'
> > with new value, and we have to re-read it explicitly on each iteration.
> >
> > Overcome that problem by using local variable 'head' inside the loop,
> > and updaing '*old_head' value only at exit.
> > With such change gcc manages to avoid extra store(/branch).
> >
> > Depends-on: series-38225 ("deprecate rte_atomicNN family")
> >
> > Signed-off-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>
> > ---
> 
> I used the standard ring perf tests and ran 10 times via:
> ! /bin/bash
> if [ -z "$1" ]; then
> 	echo "Usage $0 version"
> 	exit 1
> fi
> 
> VERSION=$1
> for i in $(seq 1 10); do
>      sudo DPDK_TEST=ring_perf_autotest \
>         ./build/app/dpdk-test -l 2-5 -n 4 --no-pci --file-prefix=run$i \
>         > ~/DPDK/ring_perf_results/${VERSION}_run${i}.log 2>&1
>     echo "${VERSION} run $i done"
> done
> 
> 
> Then had Claude compare results:
> 
> Key metric (two physical cores legacy MP/MC bulk n=128):
>   main:        5.380 cycles/elem
>   sync-bool:   5.377 cycles/elem  (-0.07%)
>   avoid-store: 5.892 cycles/elem  (+9.52%)  ← regresses
> 
> 
> Looking at the dissassembly of ring_enqueue_bulk:
> 
> The inner loop of main and sync-bool versions is:
> mov    0x80(%rdi),%r11d            ; load d->head via displacement
> mov    0x104(%rdi),%ebx             ; load s->tail
> add    %ecx,%ebx
> sub    %r11d,%ebx
> cmp    %ebx,%r12d
> jae    [exit]
> lea    (%r8,%r11,1),%r13d           ; new_head = old_head + n
> mov    %r11d,%eax                   ; expected → eax
> lock cmpxchg %r13d,0x80(%rdi)       ; ← displacement addressing
> jne    [retry]                      ; ← direct jne, eax preserved
> 
> Using atomic_compare_exchange and your patch:
> mov    0x38(%rdi),%r10d
> mov    0x80(%rdi),%eax              ; load d->head directly into %eax
> lea    0x80(%rdi),%rcx               ; ← MATERIALIZE &d->head into %rcx
> lea    -0x1(%r8),%r12d
> mov    0x104(%rdi),%r11d
> add    %r10d,%r11d
> sub    %eax,%r11d
> cmp    %r11d,%r12d
> jae    [exit]
> lea    (%r8,%rax,1),%r13d           ; new_head
> lock cmpxchg %r13d,(%rcx)           ; ← INDIRECT addressing via %rcx
> mov    %eax,%ebx                    ; ← EXTRA: save post-CAS %eax to %ebx
> jne    [retry]
> 
> Bottom line: good idea but still fighting with Gcc optimizer here.

Thanks for trying.
On my box (AMD EPYC 9534) with same test, there is no much difference between all of them:
use-sync-bool:                     2.2273
use-c11-current-version:   2.2422
use-c11-patched:                2.2431
Anyway, -10% on some boxes - that's probably good enough reason to keep specific version
for  __rte_ring_headtail_move_head_mt().
My ask would be to have some special macro for it, so users can enable/disable it via
'meson setup' at will.
Konstantin



^ permalink raw reply

* RE: [PATCH] app/crypto-perf: support ML DSA
From: Akhil Goyal @ 2026-06-02  9:02 UTC (permalink / raw)
  To: Pratik Senapati, dev@dpdk.org
  Cc: Anoob Joseph, Gowrishankar Muthukrishnan, kai.ji@intel.com
In-Reply-To: <20260528075853.2206573-2-psenapati@marvell.com>

Please send this patch as a series with ML KEM support so that CI can run successfully.


^ permalink raw reply

* RE: [PATCH] crypto/openssl: fix use-after-free bug and cleanup
From: Akhil Goyal @ 2026-06-02  9:03 UTC (permalink / raw)
  To: Pratik Senapati, dev@dpdk.org
  Cc: Anoob Joseph, Gowrishankar Muthukrishnan, kai.ji@intel.com,
	stable@dpdk.org
In-Reply-To: <20260528075822.2206494-1-psenapati@marvell.com>



> -----Original Message-----
> From: Pratik Senapati <psenapati@marvell.com>
> Sent: Thursday, May 28, 2026 1:28 PM
> To: dev@dpdk.org
> Cc: Akhil Goyal <gakhil@marvell.com>; Anoob Joseph <anoobj@marvell.com>;
> Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>; kai.ji@intel.com;
> stable@dpdk.org
> Subject: [PATCH] crypto/openssl: fix use-after-free bug and cleanup
> 
> params is freed before it is used by
> EVP_PKEY_decapsulate_init() causing a
> use-after-free issue. Pass NULL to
> EVP_PKEY_decapsulate_init() instead of params
> to avoid it.
> 
> Add resource cleanup for all error paths in the ML-KEM
> decapsulate handler and consolidate cleanup into
> two goto labels err_pkey and err_decap.
> 
> Fixes: 5f761d7b60 ("crypto/openssl: support ML-KEM and ML-DSA")
> Cc: stable@dpdk.org
> Signed-off-by: Pratik Senapati <psenapati@marvell.com>
> ---
Fix compilation.

^ permalink raw reply

* [RFC PATCH 0/3] remove unneeded build options
From: Bruce Richardson @ 2026-06-02  9:08 UTC (permalink / raw)
  To: dev; +Cc: Bruce Richardson

Having unnecessary build options just makes things confusing for
the user, and expands the set of potential builds. This set
makes 3 build options no-ops, and marks them as deprecated for
future removal.

Bruce Richardson (3):
  build: deprecate kernel dir option
  build: deprecate standalone tests option
  build: deprecate HPET build option

 app/meson.build                      | 6 +-----
 app/test/test.c                      | 7 -------
 app/test/test_timer.c                | 5 +++++
 config/meson.build                   | 2 +-
 doc/guides/linux_gsg/enable_func.rst | 2 --
 doc/guides/rel_notes/deprecation.rst | 7 +++++++
 lib/eal/linux/meson.build            | 5 +----
 meson_options.txt                    | 6 +++---
 8 files changed, 18 insertions(+), 22 deletions(-)

--
2.53.0


^ permalink raw reply

* [RFC PATCH 1/3] build: deprecate kernel dir option
From: Bruce Richardson @ 2026-06-02  9:08 UTC (permalink / raw)
  To: dev; +Cc: Bruce Richardson
In-Reply-To: <20260602090847.905721-1-bruce.richardson@intel.com>

The kernel_dir option does nothing, so it can be deprecated and removed
in future.

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
 doc/guides/rel_notes/deprecation.rst | 4 ++++
 meson_options.txt                    | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 17f90a6352..ed1dda6008 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -17,6 +17,10 @@ Other API and ABI deprecation notices are to be posted below.
 Deprecation Notices
 -------------------
 
+* build: The following meson build options are deprecated and will be removed in a future release:
+
+  - ``kernel_dir``: option unused as Linux kernel drivers are in a separate ``dpdk-kmods`` repository.
+
 * kvargs: The function ``rte_kvargs_process`` will get a new parameter
   for returning key match count. It will ease handling of no-match case.
 
diff --git a/meson_options.txt b/meson_options.txt
index e28d24054c..7bd5ebc084 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -33,7 +33,7 @@ option('ibverbs_link', type: 'combo', choices : ['static', 'shared', 'dlopen'],
 option('include_subdir_arch', type: 'string', value: '', description:
        'subdirectory where to install arch-dependent headers')
 option('kernel_dir', type: 'string', value: '', description:
-       'Path to the kernel for building kernel modules. Headers must be in $kernel_dir or $kernel_dir/build. Modules will be installed in /lib/modules.')
+       '[Deprecated] Value unused. Previously, path to the kernel for building kernel modules.')
 option('machine', type: 'string', value: 'auto', description:
        'Alias of cpu_instruction_set.')
 option('max_ethports', type: 'integer', value: 32, description:
-- 
2.53.0


^ permalink raw reply related

* [RFC PATCH 2/3] build: deprecate standalone tests option
From: Bruce Richardson @ 2026-06-02  9:08 UTC (permalink / raw)
  To: dev; +Cc: Bruce Richardson
In-Reply-To: <20260602090847.905721-1-bruce.richardson@intel.com>

The unit tests can be disabled in DPDK in a couple of ways. Firstly,
there is the original "tests" boolean option - when set to false, the
tests are skipped as part of the build. However, the newer
enable_apps/disable_apps options also can be used to disable the tests
[you can disable using the "enable" option by omitting "tests" from the
list to enable].

This duplication of functionality is unnecessary, so let's remove the
standalone tests option.

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
 app/meson.build                      | 6 +-----
 doc/guides/rel_notes/deprecation.rst | 1 +
 meson_options.txt                    | 2 +-
 3 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/app/meson.build b/app/meson.build
index 1798db3ae4..52f704ec94 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -17,6 +17,7 @@ apps = [
         'graph',
         'pdump',
         'proc-info',
+        'test',
         'test-acl',
         'test-bbdev',
         'test-cmdline',
@@ -35,11 +36,6 @@ apps = [
         'test-security-perf',
 ]
 
-if get_option('tests')
-# build the auto test app if enabled.
-    apps += 'test'
-endif
-
 default_cflags = machine_args + ['-DALLOW_EXPERIMENTAL_API']
 default_ldflags = []
 if get_option('default_library') == 'static' and not is_windows
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index ed1dda6008..15459851d0 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -20,6 +20,7 @@ Deprecation Notices
 * build: The following meson build options are deprecated and will be removed in a future release:
 
   - ``kernel_dir``: option unused as Linux kernel drivers are in a separate ``dpdk-kmods`` repository.
+  - ``tests``: disabling tests can be achieved by using the ``enable_apps`` / ``disable_apps`` options instead.
 
 * kvargs: The function ``rte_kvargs_process`` will get a new parameter
   for returning key match count. It will ease handling of no-match case.
diff --git a/meson_options.txt b/meson_options.txt
index 7bd5ebc084..323a3901e1 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -55,6 +55,6 @@ option('enable_stdatomic', type: 'boolean', value: false, description:
 option('enable_trace_fp', type: 'boolean', value: false, description:
        'enable fast path trace points.')
 option('tests', type: 'boolean', value: true, description:
-       'build unit tests')
+       '[Deprecated] Value unused. Add "tests" to disable_apps setting to disable the unit tests')
 option('use_hpet', type: 'boolean', value: false, description:
        'use HPET timer in EAL')
-- 
2.53.0


^ permalink raw reply related

* [RFC PATCH 3/3] build: deprecate HPET build option
From: Bruce Richardson @ 2026-06-02  9:08 UTC (permalink / raw)
  To: dev; +Cc: Bruce Richardson
In-Reply-To: <20260602090847.905721-1-bruce.richardson@intel.com>

We can enable the building of the HPET code by default on Linux, since
the timers are not used - or even initialized - by default. Instead an
app needs to explicitly call rte_eal_hpet_init() to use the HPET timer
APIs. Therefore, let's simplify the user experience by deprecating the
option "use_hpet" and make it a no-op.

To avoid issue with the dpdk-test binary which was trying to initialize
the hpet on startup, move the hpet init call to the timer autotest - the
only place where it was used.

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
 app/test/test.c                      | 7 -------
 app/test/test_timer.c                | 5 +++++
 config/meson.build                   | 2 +-
 doc/guides/linux_gsg/enable_func.rst | 2 --
 doc/guides/rel_notes/deprecation.rst | 2 ++
 lib/eal/linux/meson.build            | 5 +----
 meson_options.txt                    | 2 +-
 7 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/app/test/test.c b/app/test/test.c
index 58ef52f312..99d6e90f8b 100644
--- a/app/test/test.c
+++ b/app/test/test.c
@@ -180,13 +180,6 @@ main(int argc, char **argv)
 		goto out;
 	}
 
-#ifdef RTE_LIBEAL_USE_HPET
-	if (rte_eal_hpet_init(1) < 0)
-#endif
-		RTE_LOG(INFO, APP,
-				"HPET is not enabled, using TSC as default timer\n");
-
-
 	char *dpdk_test = getenv("DPDK_TEST");
 
 	if (dpdk_test && strlen(dpdk_test) > 0)
diff --git a/app/test/test_timer.c b/app/test/test_timer.c
index c936843ddc..dcb26c4395 100644
--- a/app/test/test_timer.c
+++ b/app/test/test_timer.c
@@ -501,6 +501,11 @@ static int
 timer_sanity_check(void)
 {
 #ifdef RTE_LIBEAL_USE_HPET
+	if (rte_eal_hpet_init(1) < 0) {
+		printf("HPET is not enabled, using TSC as default timer\n");
+		return 0;
+	}
+
 	if (eal_timer_source != EAL_TIMER_HPET) {
 		printf("Not using HPET, can't sanity check timer sources\n");
 		return 0;
diff --git a/config/meson.build b/config/meson.build
index 9ba7b9a338..6012a3c243 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -381,7 +381,7 @@ endforeach
 
 # set other values pulled from the build options
 dpdk_conf.set('RTE_MAX_ETHPORTS', get_option('max_ethports'))
-dpdk_conf.set('RTE_LIBEAL_USE_HPET', get_option('use_hpet'))
+dpdk_conf.set('RTE_LIBEAL_USE_HPET', is_linux)
 dpdk_conf.set('RTE_ENABLE_STDATOMIC', get_option('enable_stdatomic'))
 dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp'))
 dpdk_conf.set('RTE_PKTMBUF_HEADROOM', get_option('pkt_mbuf_headroom'))
diff --git a/doc/guides/linux_gsg/enable_func.rst b/doc/guides/linux_gsg/enable_func.rst
index 4e1a939f35..1d5b030172 100644
--- a/doc/guides/linux_gsg/enable_func.rst
+++ b/doc/guides/linux_gsg/enable_func.rst
@@ -176,8 +176,6 @@ To enable HPET support in DPDK:
    Note that this may involve doing a kernel rebuild,
    as many common linux distributions do *not* have this setting
    enabled by default in their kernel builds.
-#. Enable DPDK support for HPET by using the build-time meson option ``use_hpet``,
-   for example, ``meson configure -Duse_hpet=true``
 
 For an application to use the ``rte_get_hpet_cycles()`` and ``rte_get_hpet_hz()`` API calls,
 and optionally to make the HPET the default time source for the rte_timer library,
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 15459851d0..42ad118c92 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -21,6 +21,8 @@ Deprecation Notices
 
   - ``kernel_dir``: option unused as Linux kernel drivers are in a separate ``dpdk-kmods`` repository.
   - ``tests``: disabling tests can be achieved by using the ``enable_apps`` / ``disable_apps`` options instead.
+  - ``use_hpet``: option unused as HPET is only supported on Linux
+    and is runtime-enabled using ``rte_eal_hpet_init()`` API.
 
 * kvargs: The function ``rte_kvargs_process`` will get a new parameter
   for returning key match count. It will ease handling of no-match case.
diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build
index 29ba313218..8b0519c9a1 100644
--- a/lib/eal/linux/meson.build
+++ b/lib/eal/linux/meson.build
@@ -15,14 +15,11 @@ sources += files(
         'eal_memory.c',
         'eal_thread.c',
         'eal_timer.c',
+        'eal_timer_hpet.c',
         'eal_vfio.c',
         'eal_vfio_mp_sync.c',
 )
 
-if dpdk_conf.get('RTE_LIBEAL_USE_HPET')
-    sources += files('eal_timer_hpet.c')
-endif
-
 deps += ['kvargs', 'telemetry']
 if has_libnuma
     dpdk_conf.set10('RTE_EAL_NUMA_AWARE_HUGEPAGES', true)
diff --git a/meson_options.txt b/meson_options.txt
index 323a3901e1..242de6681f 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -57,4 +57,4 @@ option('enable_trace_fp', type: 'boolean', value: false, description:
 option('tests', type: 'boolean', value: true, description:
        '[Deprecated] Value unused. Add "tests" to disable_apps setting to disable the unit tests')
 option('use_hpet', type: 'boolean', value: false, description:
-       'use HPET timer in EAL')
+       '[Deprecated] Value unused. HPET can be runtime-enabled on Linux using rte_eal_hpet_init().')
-- 
2.53.0


^ permalink raw reply related

* RE: [PATCH] ring: avoid extra store at move head
From: Morten Brørup @ 2026-06-02  9:21 UTC (permalink / raw)
  To: Konstantin Ananyev, Stephen Hemminger; +Cc: dev
In-Reply-To: <580828b0214b4e1fb22e2f6d4079eadf@huawei.com>

> > Then had Claude compare results:
> >
> > Key metric (two physical cores legacy MP/MC bulk n=128):
> >   main:        5.380 cycles/elem
> >   sync-bool:   5.377 cycles/elem  (-0.07%)
> >   avoid-store: 5.892 cycles/elem  (+9.52%)  ← regresses
> >
> >
> > Looking at the dissassembly of ring_enqueue_bulk:
> >
> > The inner loop of main and sync-bool versions is:
> > mov    0x80(%rdi),%r11d            ; load d->head via displacement
> > mov    0x104(%rdi),%ebx             ; load s->tail
> > add    %ecx,%ebx
> > sub    %r11d,%ebx
> > cmp    %ebx,%r12d
> > jae    [exit]
> > lea    (%r8,%r11,1),%r13d           ; new_head = old_head + n
> > mov    %r11d,%eax                   ; expected → eax
> > lock cmpxchg %r13d,0x80(%rdi)       ; ← displacement addressing
> > jne    [retry]                      ; ← direct jne, eax preserved
> >
> > Using atomic_compare_exchange and your patch:
> > mov    0x38(%rdi),%r10d
> > mov    0x80(%rdi),%eax              ; load d->head directly into %eax
> > lea    0x80(%rdi),%rcx               ; ← MATERIALIZE &d->head into
> %rcx
> > lea    -0x1(%r8),%r12d
> > mov    0x104(%rdi),%r11d
> > add    %r10d,%r11d
> > sub    %eax,%r11d
> > cmp    %r11d,%r12d
> > jae    [exit]
> > lea    (%r8,%rax,1),%r13d           ; new_head
> > lock cmpxchg %r13d,(%rcx)           ; ← INDIRECT addressing via %rcx
> > mov    %eax,%ebx                    ; ← EXTRA: save post-CAS %eax to
> %ebx
> > jne    [retry]
> >
> > Bottom line: good idea but still fighting with Gcc optimizer here.
> 
> Thanks for trying.
> On my box (AMD EPYC 9534) with same test, there is no much difference
> between all of them:
> use-sync-bool:                     2.2273
> use-c11-current-version:   2.2422
> use-c11-patched:                2.2431
> Anyway, -10% on some boxes - that's probably good enough reason to keep
> specific version
> for  __rte_ring_headtail_move_head_mt().
> My ask would be to have some special macro for it, so users can
> enable/disable it via 'meson setup' at will.

This seems very exotic as a meson command line option.
Either put it in rte_config.h, or make it CPU specific.


^ permalink raw reply

* RE: [RFC PATCH 1/3] build: deprecate kernel dir option
From: Morten Brørup @ 2026-06-02  9:24 UTC (permalink / raw)
  To: Bruce Richardson, dev
In-Reply-To: <20260602090847.905721-2-bruce.richardson@intel.com>

> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> Sent: Tuesday, 2 June 2026 11.09
> 
> The kernel_dir option does nothing, so it can be deprecated and removed
> in future.
> 
> Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> ---

Good cleanup.
Acked-by: Morten Brørup <mb@smartsharesystems.com>


^ permalink raw reply

* RE: [RFC PATCH 2/3] build: deprecate standalone tests option
From: Morten Brørup @ 2026-06-02  9:26 UTC (permalink / raw)
  To: Bruce Richardson, dev
In-Reply-To: <20260602090847.905721-3-bruce.richardson@intel.com>

> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> Sent: Tuesday, 2 June 2026 11.09
> 
> The unit tests can be disabled in DPDK in a couple of ways. Firstly,
> there is the original "tests" boolean option - when set to false, the
> tests are skipped as part of the build. However, the newer
> enable_apps/disable_apps options also can be used to disable the tests
> [you can disable using the "enable" option by omitting "tests" from the
> list to enable].
> 
> This duplication of functionality is unnecessary, so let's remove the
> standalone tests option.
> 
> Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> ---

Good cleanup.
Acked-by: Morten Brørup <mb@smartsharesystems.com>


^ permalink raw reply

* Re: [PATCH] gpu/metax: add new driver for Metax GPU
From: Thomas Monjalon @ 2026-06-02 10:01 UTC (permalink / raw)
  To: 许玲燕; +Cc: dev, eagostini
In-Reply-To: <6c18e957-c1c2-4b43-9b2c-b36424c1e9af.lingyan.xu@metax-tech.com>

Hello,

01/06/2026 07:47, 许玲燕:
> I am writing to propose a new driver for the Metax GPU,

How do you access the GPU?
Are you using a specific library or kernel module?

> which I believe will significantly enhance our support
> and performance for this hardware.
> The patch attached includes the initial implementation of the driver,
> with key features such as:
> 
>  * Basic initialization and configuration 
>  * Memory management and allocation 
>  * Core functionality for rendering and compute tasks 

I am familiar with connecting compute tasks of a GPU
with DPDK networking, but I'm surprised by the rendering functionality.
Do you mean graphical rendering of data coming from the network?

> Please review the code and let me know if you have any feedback or suggestions.
> I am more than happy to make any necessary adjustments and improvements.

Thank you for working on this.

I recommend following this guide to introduce a new driver:
https://doc.dpdk.org/guides/contributing/new_driver.html



^ permalink raw reply

* RE: [RFC PATCH 3/3] build: deprecate HPET build option
From: Morten Brørup @ 2026-06-02 10:47 UTC (permalink / raw)
  To: Bruce Richardson, dev
In-Reply-To: <20260602090847.905721-4-bruce.richardson@intel.com>

> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> Sent: Tuesday, 2 June 2026 11.09
> 
> We can enable the building of the HPET code by default on Linux, since
> the timers are not used - or even initialized - by default. Instead an
> app needs to explicitly call rte_eal_hpet_init() to use the HPET timer
> APIs. Therefore, let's simplify the user experience by deprecating the
> option "use_hpet" and make it a no-op.
> 
> To avoid issue with the dpdk-test binary which was trying to initialize
> the hpet on startup, move the hpet init call to the timer autotest -
> the
> only place where it was used.
> 
> Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> ---

Careful!
I think this patch has unintended side effects:

On Linux, it unconditionally enables HPET (and sets RTE_LIBEAL_USE_HPET), which was previously disabled by default.

So, if some Linux applications use #ifdef RTE_LIBEAL_USE_HPET, they will now tell DPDK to use that timer instead of the TSC.
We can fix the apps/examples in the DPDK repo, but it will potentially change behavior of DPDK user's applications.

I'm not opposed to unconditionally enabling HPET ability in DPDK itself on Linux.
But I'm worried about side effects of unconditionally enabling #ifdef RTE_LIBEAL_USE_HPET in Linux user applications.


^ permalink raw reply

* Re: [RFC PATCH 3/3] build: deprecate HPET build option
From: David Marchand @ 2026-06-02 11:39 UTC (permalink / raw)
  To: Morten Brørup, Bruce Richardson; +Cc: dev
In-Reply-To: <98CBD80474FA8B44BF855DF32C47DC35F658D8@smartserver.smartshare.dk>

On Tue, 2 Jun 2026 at 12:47, Morten Brørup <mb@smartsharesystems.com> wrote:
>
> > From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> > Sent: Tuesday, 2 June 2026 11.09
> >
> > We can enable the building of the HPET code by default on Linux, since
> > the timers are not used - or even initialized - by default. Instead an
> > app needs to explicitly call rte_eal_hpet_init() to use the HPET timer
> > APIs. Therefore, let's simplify the user experience by deprecating the
> > option "use_hpet" and make it a no-op.
> >
> > To avoid issue with the dpdk-test binary which was trying to initialize
> > the hpet on startup, move the hpet init call to the timer autotest -
> > the
> > only place where it was used.
> >
> > Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> > ---
>
> Careful!
> I think this patch has unintended side effects:
>
> On Linux, it unconditionally enables HPET (and sets RTE_LIBEAL_USE_HPET), which was previously disabled by default.
>
> So, if some Linux applications use #ifdef RTE_LIBEAL_USE_HPET, they will now tell DPDK to use that timer instead of the TSC.
> We can fix the apps/examples in the DPDK repo, but it will potentially change behavior of DPDK user's applications.
>
> I'm not opposed to unconditionally enabling HPET ability in DPDK itself on Linux.
> But I'm worried about side effects of unconditionally enabling #ifdef RTE_LIBEAL_USE_HPET in Linux user applications.

I don't see a functional impact.

There may be an impact on performance?
But users can switch to rte_get_tsc_cycles() to avoid the added branch.


On the other hand, did you consider dropping HPET altogether?


-- 
David Marchand


^ permalink raw reply

* RE: [PATCH 1/2] crypto/ipsec_mb: allow aesni_mb and aesni_gcm vdevs on Arm
From: Hemant Agrawal @ 2026-06-02 12:09 UTC (permalink / raw)
  To: Wathsala Vithanage, Kai Ji, Pablo de Lara
  Cc: dev@dpdk.org, nd@arm.com, Paul.Elliott@arm.com,
	Dhruv.Tripathi@arm.com, Shebu.VargheseKuriakose@arm.com
In-Reply-To: <20260529205512.1985844-1-wathsala.vithanage@arm.com>



> -----Original Message-----
> From: Wathsala Vithanage <wathsala.vithanage@arm.com>
> Sent: 30 May 2026 02:25
> To: Kai Ji <kai.ji@intel.com>; Pablo de Lara <pablo.de.lara.guarch@intel.com>
> Cc: dev@dpdk.org; nd@arm.com; Paul.Elliott@arm.com;
> Dhruv.Tripathi@arm.com; Shebu.VargheseKuriakose@arm.com; Wathsala
> Vithanage <wathsala.vithanage@arm.com>
> Subject: [PATCH 1/2] crypto/ipsec_mb: allow aesni_mb and aesni_gcm vdevs
> on Arm
> 
> Extend Arm PMD gating in ipsec_mb_create() to permit
> IPSEC_MB_PMD_TYPE_AESNI_MB and IPSEC_MB_PMD_TYPE_AESNI_GCM in
> addition to existing SNOW3G and ZUC.
> 
> This removes -ENOTSUP rejection for crypto_aesni_mb and crypto_aesni_gcm
> on Arm, enabling these vdevs to probe and run when backed by a compatible
> ipsec-mb library.
> 
> Signed-off-by: Wathsala Vithanage <wathsala.vithanage@arm.com>
> ---
 Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

^ permalink raw reply

* RE: [PATCH 2/2] doc: update Arm IPsec-MB references for cryptodev PMDs
From: Hemant Agrawal @ 2026-06-02 12:10 UTC (permalink / raw)
  To: Wathsala Vithanage, Kai Ji, Pablo de Lara
  Cc: dev@dpdk.org, nd@arm.com, paul.elliott@arm.com,
	dhruv.tripathi@arm.com, shebu.vargheseKuriakose@arm.com
In-Reply-To: <20260529210404.1986896-1-wathsala.vithanage@arm.com>



> -----Original Message-----
> From: Wathsala Vithanage <wathsala.vithanage@arm.com>
> Sent: 30 May 2026 02:34
> To: Kai Ji <kai.ji@intel.com>; Pablo de Lara <pablo.de.lara.guarch@intel.com>
> Cc: dev@dpdk.org; nd@arm.com; paul.elliott@arm.com;
> dhruv.tripathi@arm.com; shebu.vargheseKuriakose@arm.com; Wathsala
> Vithanage <wathsala.vithanage@arm.com>
> Subject: [PATCH 2/2] doc: update Arm IPsec-MB references for cryptodev
> PMDs
> 
> Document Arm/ARM64 IPsec-MB source and supported tag level for
> aesni_mb, aesni_gcm, snow3g, and zuc cryptodev guides.
> 
> - Add Arm library reference to aesni_mb and aesni_gcm docs.
> - Update snow3g and zuc IPsec-MB library tag to SECLIB-IPSEC-2026.05.30.
> 
> Signed-off-by: Wathsala Vithanage <wathsala.vithanage@arm.com>
> ---
>  doc/guides/cryptodevs/aesni_gcm.rst | 4 ++++
> doc/guides/cryptodevs/aesni_mb.rst  | 4 ++++
>  doc/guides/cryptodevs/snow3g.rst    | 2 +-
>  doc/guides/cryptodevs/zuc.rst       | 2 +-
>  4 files changed, 10 insertions(+), 2 deletions(-)
> 
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

^ 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