* Re: [PATCH v4 00/12] Bus cleanup infrastructure and fixes
From: David Marchand @ 2026-06-25 12:24 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
On Wed, 24 Jun 2026 at 12:43, David Marchand <david.marchand@redhat.com> wrote:
>
> This is a followup of the previous bus refactoring.
> See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
>
> This series refactors the bus cleanup infrastructure to reduce code
> duplication and fix resource leaks in several bus drivers.
> It should address the leak Thomas pointed at.
>
> The first part of the series (patches 1-6) addresses several bugs and
> inconsistencies:
> - Documentation and log message inconsistencies from earlier bus
> refactoring
> - Device list management issues in dma/idxd and bus/vdev
> - Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
> - Deferred interrupt allocation to probe time (VMBUS)
>
> The core infrastructure changes (patches 7-8) introduce the generic
> cleanup framework:
> - Refactors unplug operations to be the counterpart of probe_device
> - Implements rte_bus_generic_cleanup() to centralize cleanup logic
> - Adds .free_device operation to struct rte_bus
>
> The final patches (9-10) convert the VMBUS bus to use the generic
> cleanup helper.
>
> After this series, most buses use the generic cleanup helper, eliminating
> duplicated code and ensuring consistent cleanup behavior across the
> codebase.
>
> NXP bus drivers require more (leak) fixes and refactoring and
> are left untouched.
>
>
> --
> David Marchand
>
> Changes since v3:
> - added fix on vdpa/nfp,
>
> Changes since v2:
> - moved ifpga interruption allocation,
>
> Changes since v1:
> - dropped all changes on DPAA and FSLMC bus,
> - added one more cleanup on the first patch,
> - changed coding style in rte_vdev_init,
> - implemented explicit .free_device instead of hack for calling free(),
> - reordered interrupt handle allocation in VMBUS bus,
>
>
> David Marchand (12):
> bus: fix reference to plug callback
> dma/idxd: remove next pointer in bus specific device
> bus/vdev: remove driver setting in probe
> vdpa/nfp: fix double PCI unmap on unplug
> bus/pci: fix mapping leak in bus cleanup
> bus/vmbus: fix interrupt leak in cleanup
> bus/vmbus: allocate interrupt during probing
> bus/ifpga: allocate interrupt during probing
> bus: align unplug with device probe
> bus: implement cleanup in EAL
> bus/vmbus: store name in bus specific device
> bus/vmbus: support unplug
>
> doc/guides/prog_guide/device_hotplug.rst | 20 +++---
> doc/guides/rel_notes/release_26_07.rst | 4 ++
> drivers/bus/auxiliary/auxiliary_common.c | 54 +++------------
> drivers/bus/cdx/cdx.c | 29 ++------
> drivers/bus/dpaa/dpaa_bus.c | 4 +-
> drivers/bus/fslmc/fslmc_bus.c | 9 +--
> drivers/bus/ifpga/ifpga_bus.c | 88 ++++++++----------------
> drivers/bus/pci/pci_common.c | 68 +++---------------
> drivers/bus/platform/platform.c | 26 ++-----
> drivers/bus/uacce/uacce.c | 59 +++-------------
> drivers/bus/vdev/vdev.c | 76 ++++++++------------
> drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
> drivers/bus/vmbus/linux/vmbus_bus.c | 16 +----
> drivers/bus/vmbus/vmbus_common.c | 58 +++++++++-------
> drivers/dma/idxd/idxd_bus.c | 1 -
> drivers/vdpa/nfp/nfp_vdpa.c | 4 +-
> lib/eal/common/eal_common_bus.c | 33 ++++++++-
> lib/eal/common/eal_common_dev.c | 10 +--
> lib/eal/include/bus_driver.h | 51 +++++++++-----
> 19 files changed, 235 insertions(+), 376 deletions(-)
Series applied, thanks for the reviews.
--
David Marchand
^ permalink raw reply
* [PATCH v8 4/4] net/zxdh: optimize Tx xmit pkts performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 21892 bytes --]
Add simple Tx xmit functions (zxdh_xmit_pkts_simple)
for single-segment packet xmit.
Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
drivers/net/zxdh/zxdh_ethdev.c | 15 +-
drivers/net/zxdh/zxdh_queue.h | 2 +-
drivers/net/zxdh/zxdh_rxtx.c | 409 ++++++++++++++++++++++++++-------
drivers/net/zxdh/zxdh_rxtx.h | 13 +-
4 files changed, 343 insertions(+), 96 deletions(-)
diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index fe76139f3d..cf0395aee8 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -490,7 +490,7 @@ zxdh_dev_free_mbufs(struct rte_eth_dev *dev)
if (!vq)
continue;
while ((buf = zxdh_queue_detach_unused(vq)) != NULL)
- rte_pktmbuf_free(buf);
+ rte_pktmbuf_free_seg(buf);
PMD_DRV_LOG(DEBUG, "freeing %s[%d] used and unused buf",
"rxq", i * 2);
}
@@ -499,7 +499,7 @@ zxdh_dev_free_mbufs(struct rte_eth_dev *dev)
if (!vq)
continue;
while ((buf = zxdh_queue_detach_unused(vq)) != NULL)
- rte_pktmbuf_free(buf);
+ rte_pktmbuf_free_seg(buf);
PMD_DRV_LOG(DEBUG, "freeing %s[%d] used and unused buf",
"txq", i * 2 + 1);
}
@@ -1291,10 +1291,17 @@ static int zxdh_scattered_rx(struct rte_eth_dev *eth_dev)
static int32_t
zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
{
- eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+ uint64_t tx_offloads = eth_dev->data->dev_conf.txmode.offloads;
+
eth_dev->data->scattered_rx = zxdh_scattered_rx(eth_dev);
- eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
+ if (!(tx_offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) {
+ eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_simple_prepare;
+ eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_simple;
+ } else {
+ eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+ eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
+ }
if (eth_dev->data->scattered_rx)
eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index b079272162..091d1f25db 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -374,7 +374,7 @@ zxdh_queue_full(const struct zxdh_virtqueue *vq)
}
static inline void
-zxdh_queue_store_flags_packed(struct zxdh_vring_packed_desc *dp, uint16_t flags)
+zxdh_queue_store_flags_packed(volatile struct zxdh_vring_packed_desc *dp, uint16_t flags)
{
rte_io_wmb();
dp->flags = flags;
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index ab0510a753..aedcb65bea 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -114,6 +114,25 @@
RTE_MBUF_F_TX_SEC_OFFLOAD | \
RTE_MBUF_F_TX_UDP_SEG)
+static_assert(RTE_PKTMBUF_HEADROOM >= ZXDH_DL_NET_HDR_SIZE,
+ "RTE_PKTMBUF_HEADROOM too small for zxdh Tx downlink header");
+
+#if RTE_CACHE_LINE_SIZE == 128
+#define NEXT_CACHELINE_OFF_16B 8
+#define NEXT_CACHELINE_OFF_8B 16
+#elif RTE_CACHE_LINE_SIZE == 64
+#define NEXT_CACHELINE_OFF_16B 4
+#define NEXT_CACHELINE_OFF_8B 8
+#else
+#define NEXT_CACHELINE_OFF_16B (RTE_CACHE_LINE_SIZE / 16)
+#define NEXT_CACHELINE_OFF_8B (RTE_CACHE_LINE_SIZE / 8)
+#endif
+#define N_PER_LOOP NEXT_CACHELINE_OFF_8B
+#define N_PER_LOOP_MASK (N_PER_LOOP - 1)
+
+#define rxq_get_vq(q) ((q)->vq)
+#define txq_get_vq(q) ((q)->vq)
+
uint32_t zxdh_outer_l2_type[16] = {
0,
RTE_PTYPE_L2_ETHER,
@@ -201,43 +220,6 @@ uint32_t zxdh_inner_l4_type[16] = {
0,
};
-static void
-zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
-{
- uint16_t used_idx = 0;
- uint16_t id = 0;
- uint16_t curr_id = 0;
- uint16_t free_cnt = 0;
- uint16_t size = vq->vq_nentries;
- struct zxdh_vring_packed_desc *desc = vq->vq_packed.ring.desc;
- struct zxdh_vq_desc_extra *dxp = NULL;
-
- used_idx = vq->vq_used_cons_idx;
- /* desc_is_used has a load-acquire or rte_io_rmb inside
- * and wait for used desc in virtqueue.
- */
- while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
- id = desc[used_idx].id;
- do {
- curr_id = used_idx;
- dxp = &vq->vq_descx[used_idx];
- used_idx += dxp->ndescs;
- free_cnt += dxp->ndescs;
- num -= dxp->ndescs;
- if (used_idx >= size) {
- used_idx -= size;
- vq->used_wrap_counter ^= 1;
- }
- if (dxp->cookie != NULL) {
- rte_pktmbuf_free(dxp->cookie);
- dxp->cookie = NULL;
- }
- } while (curr_id != id);
- }
- vq->vq_used_cons_idx = used_idx;
- vq->vq_free_cnt += free_cnt;
-}
-
static inline uint16_t
zxdh_get_mtu(struct zxdh_virtqueue *vq)
{
@@ -334,7 +316,7 @@ zxdh_xmit_fill_net_hdr(struct zxdh_virtqueue *vq, struct rte_mbuf *cookie,
}
static inline void
-zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
+zxdh_xmit_enqueue_push(struct zxdh_virtnet_tx *txvq,
struct rte_mbuf *cookie)
{
struct zxdh_virtqueue *vq = txvq->vq;
@@ -345,7 +327,6 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
uint8_t hdr_len = vq->hw->dl_net_hdr_len;
struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[id];
- dxp->ndescs = 1;
dxp->cookie = cookie;
hdr = rte_pktmbuf_mtod_offset(cookie, struct zxdh_net_hdr_dl *, -hdr_len);
zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
@@ -362,52 +343,57 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
}
static inline void
-zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
+zxdh_xmit_enqueue_append(struct zxdh_virtnet_tx *txvq,
struct rte_mbuf *cookie,
uint16_t needed)
{
struct zxdh_tx_region *txr = txvq->zxdh_net_hdr_mz->addr;
struct zxdh_virtqueue *vq = txvq->vq;
- uint16_t id = vq->vq_avail_idx;
- struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
+ struct zxdh_vq_desc_extra *dep = &vq->vq_descx[0];
uint16_t head_idx = vq->vq_avail_idx;
uint16_t idx = head_idx;
struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
struct zxdh_vring_packed_desc *head_dp = &vq->vq_packed.ring.desc[idx];
struct zxdh_net_hdr_dl *hdr = NULL;
-
- uint16_t head_flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
+ uint16_t id = vq->vq_avail_idx;
+ struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
uint8_t hdr_len = vq->hw->dl_net_hdr_len;
+ uint16_t head_flags = 0;
- dxp->ndescs = needed;
- dxp->cookie = cookie;
- head_flags |= vq->cached_flags;
+ /*
+ * IMPORTANT: For multi-seg packets, we set the head descriptor's cookie to NULL
+ * and store each segment's mbuf in its corresponding vq_descx[idx].cookie.
+ * This is required for the per-descriptor mbuf free in zxdh_xmit_fast_flush()
+ * which uses rte_pktmbuf_free_seg() to free individual segments.
+ * Any code path that attempts to read vq_descx[head_id].cookie will see NULL
+ * and must handle this case appropriately.
+ */
+ dxp->cookie = NULL;
+ /* setup first tx ring slot to point to header stored in reserved region. */
start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
start_dp[idx].len = hdr_len;
- head_flags |= ZXDH_VRING_DESC_F_NEXT;
+ start_dp[idx].id = idx;
+ head_flags |= vq->cached_flags | ZXDH_VRING_DESC_F_NEXT;
hdr = (void *)&txr[idx].tx_hdr;
- rte_prefetch1(hdr);
+ zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
+
idx++;
if (idx >= vq->vq_nentries) {
idx -= vq->vq_nentries;
vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
}
- zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
-
do {
start_dp[idx].addr = rte_pktmbuf_iova(cookie);
start_dp[idx].len = cookie->data_len;
- start_dp[idx].id = id;
- if (likely(idx != head_idx)) {
- uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
-
- flags |= vq->cached_flags;
- start_dp[idx].flags = flags;
- }
+ start_dp[idx].id = idx;
+ dep[idx].cookie = cookie;
+ uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
+ flags |= vq->cached_flags;
+ start_dp[idx].flags = flags;
idx++;
if (idx >= vq->vq_nentries) {
idx -= vq->vq_nentries;
@@ -417,7 +403,6 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
vq->vq_avail_idx = idx;
-
zxdh_queue_store_flags_packed(head_dp, head_flags);
}
@@ -456,7 +441,7 @@ zxdh_update_packet_stats(struct zxdh_virtnet_stats *stats, struct rte_mbuf *mbuf
}
static void
-zxdh_xmit_flush(struct zxdh_virtqueue *vq)
+zxdh_xmit_fast_flush(struct zxdh_virtqueue *vq)
{
uint16_t id = 0;
uint16_t curr_id = 0;
@@ -472,20 +457,22 @@ zxdh_xmit_flush(struct zxdh_virtqueue *vq)
* for a used descriptor in the virtqueue.
*/
while (desc_is_used(&desc[used_idx], vq)) {
+ rte_prefetch0(&desc[used_idx + NEXT_CACHELINE_OFF_16B]);
id = desc[used_idx].id;
do {
+ desc[used_idx].id = used_idx;
curr_id = used_idx;
dxp = &vq->vq_descx[used_idx];
- used_idx += dxp->ndescs;
- free_cnt += dxp->ndescs;
- if (used_idx >= size) {
- used_idx -= size;
- vq->used_wrap_counter ^= 1;
- }
if (dxp->cookie != NULL) {
- rte_pktmbuf_free(dxp->cookie);
+ rte_pktmbuf_free_seg(dxp->cookie);
dxp->cookie = NULL;
}
+ used_idx += 1;
+ free_cnt += 1;
+ if (unlikely(used_idx == size)) {
+ used_idx = 0;
+ vq->used_wrap_counter ^= 1;
+ }
} while (curr_id != id);
}
vq->vq_used_cons_idx = used_idx;
@@ -499,13 +486,12 @@ zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
struct zxdh_virtqueue *vq = txvq->vq;
uint16_t nb_tx = 0;
- zxdh_xmit_flush(vq);
+ zxdh_xmit_fast_flush(vq);
for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
struct rte_mbuf *txm = tx_pkts[nb_tx];
int32_t can_push = 0;
int32_t slots = 0;
- int32_t need = 0;
rte_prefetch0(txm);
/* optimize ring usage */
@@ -522,26 +508,15 @@ zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
* default => number of segments + 1
**/
slots = txm->nb_segs + !can_push;
- need = slots - vq->vq_free_cnt;
/* Positive value indicates it need free vring descriptors */
- if (unlikely(need > 0)) {
- zxdh_xmit_cleanup_inorder_packed(vq, need);
- need = slots - vq->vq_free_cnt;
- if (unlikely(need > 0)) {
- PMD_TX_LOG(ERR,
- " No enough %d free tx descriptors to transmit."
- "freecnt %d",
- need,
- vq->vq_free_cnt);
- break;
- }
- }
+ if (unlikely(slots > vq->vq_free_cnt))
+ break;
/* Enqueue Packet buffers */
if (can_push)
- zxdh_enqueue_xmit_packed_fast(txvq, txm);
+ zxdh_xmit_enqueue_push(txvq, txm);
else
- zxdh_enqueue_xmit_packed(txvq, txm, slots);
+ zxdh_xmit_enqueue_append(txvq, txm, slots);
zxdh_update_packet_stats(&txvq->stats, txm);
}
txvq->stats.packets += nb_tx;
@@ -602,6 +577,48 @@ uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts,
return nb_tx;
}
+uint16_t zxdh_xmit_pkts_simple_prepare(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts)
+{
+ struct zxdh_virtnet_tx *txvq = tx_queue;
+ struct zxdh_hw *hw = txvq->vq->hw;
+ uint16_t nb_tx;
+
+ for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+ struct rte_mbuf *m = tx_pkts[nb_tx];
+ int32_t error;
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+ error = rte_validate_tx_offload(m);
+ if (unlikely(error)) {
+ rte_errno = -error;
+ break;
+ }
+#endif
+
+ error = rte_net_intel_cksum_prepare(m);
+ if (unlikely(error)) {
+ rte_errno = -error;
+ break;
+ }
+ if (m->data_off < ZXDH_DL_NET_HDR_SIZE) {
+ PMD_TX_LOG(ERR, "HEADROOM too small for zxdh Tx downlink header");
+ txvq->stats.invalid_hdr_len_err += nb_pkts - nb_tx;
+ rte_errno = ENOMEM;
+ break;
+ }
+
+ error = dl_net_hdr_check(m, hw);
+ if (unlikely(error)) {
+ rte_errno = ENOTSUP;
+ txvq->stats.errors += nb_pkts - nb_tx;
+ txvq->stats.offload_cfg_err += nb_pkts - nb_tx;
+ break;
+ }
+ }
+ return nb_tx;
+}
+
static uint16_t
zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
struct rte_mbuf **rx_pkts,
@@ -1070,7 +1087,6 @@ uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint1
if (unlikely(zxdh_init_mbuf(rxm, len, hw, &vq->rxq) < 0))
continue;
- rcv_pkts[nb_rx] = rxm;
zxdh_update_packet_stats(&rxvq->stats, rxm);
nb_rx++;
}
@@ -1084,3 +1100,226 @@ uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint1
}
return nb_rx;
}
+
+static inline void pkt_padding(struct rte_mbuf *cookie, struct zxdh_hw *hw)
+{
+ uint16_t mtu_or_mss = 0;
+ uint16_t pkt_flag_lw16 = ZXDH_NO_IPID_UPDATE;
+ uint16_t l3_offset;
+ uint8_t pcode = ZXDH_PCODE_NO_IP_PKT_TYPE;
+ uint8_t l3_ptype = ZXDH_PI_L3TYPE_NOIP;
+ struct zxdh_pi_hdr *pi_hdr;
+ struct zxdh_pd_hdr_dl *pd_hdr;
+ struct zxdh_net_hdr_dl *net_hdr_dl = hw->net_hdr_dl;
+ uint8_t hdr_len = hw->dl_net_hdr_len;
+ uint16_t ol_flag = 0;
+ struct zxdh_net_hdr_dl *hdr;
+
+ hdr = rte_pktmbuf_mtod_offset(cookie, struct zxdh_net_hdr_dl *, -hdr_len);
+ rte_memcpy(hdr, net_hdr_dl, hdr_len);
+
+ /* Update mbuf to reflect the prepended header */
+ cookie->data_off -= hdr_len;
+ cookie->data_len += hdr_len;
+ cookie->pkt_len += hdr_len;
+
+ if (hw->has_tx_offload) {
+ pi_hdr = &hdr->pipd_hdr_dl.pi_hdr;
+ pd_hdr = &hdr->pipd_hdr_dl.pd_hdr;
+
+ pcode = ZXDH_PCODE_IP_PKT_TYPE;
+ if (cookie->ol_flags & RTE_MBUF_F_TX_IPV6)
+ l3_ptype = ZXDH_PI_L3TYPE_IPV6;
+ else if (cookie->ol_flags & RTE_MBUF_F_TX_IPV4)
+ l3_ptype = ZXDH_PI_L3TYPE_IP;
+ else
+ pcode = ZXDH_PCODE_NO_IP_PKT_TYPE;
+
+ if (cookie->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ mtu_or_mss = (cookie->tso_segsz >= ZXDH_MIN_MSS) ?
+ cookie->tso_segsz : ZXDH_MIN_MSS;
+ pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL;
+ pkt_flag_lw16 |= ZXDH_NO_IP_FRAGMENT | ZXDH_TX_IP_CKSUM_CAL;
+ pcode = ZXDH_PCODE_TCP_PKT_TYPE;
+ } else if (cookie->ol_flags & RTE_MBUF_F_TX_UDP_SEG) {
+ mtu_or_mss = hw->eth_dev->data->mtu;
+ mtu_or_mss = (mtu_or_mss >= ZXDH_MIN_MSS) ? mtu_or_mss : ZXDH_MIN_MSS;
+ pkt_flag_lw16 |= ZXDH_TX_IP_CKSUM_CAL;
+ pi_hdr->pkt_flag_hi8 |= ZXDH_NO_TCP_FRAGMENT | ZXDH_TX_TCPUDP_CKSUM_CAL;
+ pcode = ZXDH_PCODE_UDP_PKT_TYPE;
+ } else {
+ pkt_flag_lw16 |= ZXDH_NO_IP_FRAGMENT;
+ pi_hdr->pkt_flag_hi8 |= ZXDH_NO_TCP_FRAGMENT;
+ }
+
+ if (cookie->ol_flags & RTE_MBUF_F_TX_IP_CKSUM)
+ pkt_flag_lw16 |= ZXDH_TX_IP_CKSUM_CAL;
+
+ if ((cookie->ol_flags & RTE_MBUF_F_TX_UDP_CKSUM) == RTE_MBUF_F_TX_UDP_CKSUM) {
+ pcode = ZXDH_PCODE_UDP_PKT_TYPE;
+ pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL;
+ } else if ((cookie->ol_flags & RTE_MBUF_F_TX_TCP_CKSUM) ==
+ RTE_MBUF_F_TX_TCP_CKSUM) {
+ pcode = ZXDH_PCODE_TCP_PKT_TYPE;
+ pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL;
+ }
+ pkt_flag_lw16 |= (mtu_or_mss >> ZXDH_MTU_MSS_UNIT_SHIFTBIT) & ZXDH_MTU_MSS_MASK;
+ pi_hdr->pkt_flag_lw16 = rte_be_to_cpu_16(pkt_flag_lw16);
+ pi_hdr->pkt_type = l3_ptype | ZXDH_PKT_FORM_CPU | pcode;
+
+ l3_offset = hdr_len + cookie->l2_len;
+ l3_offset += (cookie->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) ?
+ cookie->outer_l2_len + cookie->outer_l3_len : 0;
+ pi_hdr->l3_offset = rte_be_to_cpu_16(l3_offset);
+ pi_hdr->l4_offset = rte_be_to_cpu_16(l3_offset + cookie->l3_len);
+ if (cookie->ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+ ol_flag |= ZXDH_PD_OFFLOAD_OUTER_IPCSUM;
+ } else {
+ pd_hdr = &hdr->pd_hdr;
+ }
+
+ pd_hdr->dst_vfid = rte_be_to_cpu_16(cookie->port);
+
+ if (cookie->ol_flags & (RTE_MBUF_F_TX_VLAN | RTE_MBUF_F_TX_QINQ)) {
+ ol_flag |= ZXDH_PD_OFFLOAD_CVLAN_INSERT;
+ pd_hdr->cvlan_insert = rte_be_to_cpu_16(cookie->vlan_tci);
+ if (cookie->ol_flags & RTE_MBUF_F_TX_QINQ) {
+ ol_flag |= ZXDH_PD_OFFLOAD_SVLAN_INSERT;
+ pd_hdr->svlan_insert = rte_be_to_cpu_16(cookie->vlan_tci_outer);
+ }
+ }
+
+ pd_hdr->ol_flag = rte_be_to_cpu_16(ol_flag);
+}
+
+/*
+ * Populate N_PER_LOOP descriptors with data from N_PER_LOOP single-segment mbufs.
+ * Note: The simple transmit path (zxdh_xmit_pkts_simple) is selected only when
+ * RTE_ETH_TX_OFFLOAD_MULTI_SEGS is disabled, so all packets handled here are
+ * guaranteed to be single-segment.
+ */
+static inline void
+tx_bunch(struct zxdh_virtqueue *vq, volatile struct zxdh_vring_packed_desc *txdp,
+ struct rte_mbuf **pkts, uint16_t start_id)
+{
+ uint16_t flags = vq->cached_flags;
+ int i;
+ for (i = 0; i < N_PER_LOOP; ++i, ++txdp, ++pkts) {
+ /* write data to descriptor */
+ txdp->addr = rte_mbuf_data_iova(*pkts);
+ txdp->len = (*pkts)->data_len;
+ txdp->id = start_id + i;
+ txdp->flags = flags;
+ }
+}
+
+/* Populate 1 descriptor with data from 1 single-segment mbuf */
+static inline void
+tx1(struct zxdh_virtqueue *vq, volatile struct zxdh_vring_packed_desc *txdp,
+ struct rte_mbuf *pkts, uint16_t id)
+{
+ uint16_t flags = vq->cached_flags;
+ txdp->addr = rte_mbuf_data_iova(pkts);
+ txdp->len = pkts->data_len;
+ txdp->id = id;
+ zxdh_queue_store_flags_packed(txdp, flags);
+}
+
+static void submit_to_backend_simple(struct zxdh_virtqueue *vq,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ struct zxdh_hw *hw = vq->hw;
+ struct rte_mbuf *m = NULL;
+ uint16_t id = vq->vq_avail_idx;
+ struct zxdh_vring_packed_desc *txdp = &vq->vq_packed.ring.desc[id];
+ struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
+ int mainpart, leftover;
+ int i, j;
+
+ /*
+ * Process most of the packets in chunks of N pkts. Any
+ * leftover packets will get processed one at a time.
+ */
+ mainpart = (nb_pkts & ~N_PER_LOOP_MASK);
+ leftover = (nb_pkts & N_PER_LOOP_MASK);
+
+ for (i = 0; i < mainpart; i += N_PER_LOOP) {
+ rte_prefetch0(dxp + i);
+ rte_prefetch0(tx_pkts + i);
+ for (j = 0; j < N_PER_LOOP; ++j) {
+ m = *(tx_pkts + i + j);
+ pkt_padding(m, hw);
+ (dxp + i + j)->cookie = (void *)m;
+ zxdh_update_packet_stats(&vq->txq.stats, m);
+ }
+ /* write data to descriptor */
+ tx_bunch(vq, txdp + i, tx_pkts + i, id + i);
+ }
+
+ if (leftover > 0) {
+ rte_prefetch0(dxp + mainpart);
+ rte_prefetch0(tx_pkts + mainpart);
+
+ for (i = 0; i < leftover; ++i) {
+ m = *(tx_pkts + mainpart + i);
+ pkt_padding(m, hw);
+ (dxp + mainpart + i)->cookie = m;
+ tx1(vq, txdp + mainpart + i, *(tx_pkts + mainpart + i), id + mainpart + i);
+ zxdh_update_packet_stats(&vq->txq.stats, m);
+ }
+ }
+}
+
+uint16_t zxdh_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ struct zxdh_virtnet_tx *txvq = tx_queue;
+ struct zxdh_virtqueue *vq = txq_get_vq(txvq);
+ uint8_t hdr_len = vq->hw->dl_net_hdr_len;
+ uint16_t nb_tx = 0, nb_tx_left;
+ uint16_t i;
+
+ zxdh_xmit_fast_flush(vq);
+
+ /*
+ * Filter out mbufs with insufficient headroom. The first short-
+ * headroom packet and everything after it are returned to the
+ * caller; the caller can retry with tx_pkt_prepare() to be told
+ * exactly which packet was rejected.
+ */
+ for (i = 0; i < nb_pkts; i++) {
+ rte_prefetch0(tx_pkts[i]);
+ if (unlikely(tx_pkts[i]->data_off < hdr_len)) {
+ txvq->stats.errors += nb_pkts - i;
+ nb_pkts = i;
+ break;
+ }
+ }
+
+ nb_pkts = (uint16_t)RTE_MIN(nb_pkts, vq->vq_free_cnt);
+ if (unlikely(nb_pkts == 0)) {
+ txvq->stats.idle++;
+ return 0;
+ }
+
+ nb_tx_left = nb_pkts;
+ if ((vq->vq_avail_idx + nb_pkts) >= vq->vq_nentries) {
+ nb_tx = vq->vq_nentries - vq->vq_avail_idx;
+ nb_tx_left = nb_pkts - nb_tx;
+ submit_to_backend_simple(vq, tx_pkts, nb_tx);
+ vq->vq_avail_idx = 0;
+ vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+
+ vq->vq_free_cnt -= nb_tx;
+ tx_pkts += nb_tx;
+ }
+ if (nb_tx_left) {
+ submit_to_backend_simple(vq, tx_pkts, nb_tx_left);
+ vq->vq_avail_idx += nb_tx_left;
+ vq->vq_free_cnt -= nb_tx_left;
+ }
+
+ zxdh_queue_notify(vq);
+ txvq->stats.packets += nb_pkts;
+
+ return nb_pkts;
+}
diff --git a/drivers/net/zxdh/zxdh_rxtx.h b/drivers/net/zxdh/zxdh_rxtx.h
index dba9567414..627e8b05c3 100644
--- a/drivers/net/zxdh/zxdh_rxtx.h
+++ b/drivers/net/zxdh/zxdh_rxtx.h
@@ -56,18 +56,19 @@ struct __rte_cache_aligned zxdh_virtnet_rx {
struct __rte_cache_aligned zxdh_virtnet_tx {
struct zxdh_virtqueue *vq;
-
- rte_iova_t zxdh_net_hdr_mem; /* hdr for each xmit packet */
- uint16_t queue_id; /* DPDK queue index. */
- uint16_t port_id; /* Device port identifier. */
+ const struct rte_memzone *zxdh_net_hdr_mz; /* memzone to populate hdr. */
+ rte_iova_t zxdh_net_hdr_mem; /* hdr for each xmit packet */
struct zxdh_virtnet_stats stats;
const struct rte_memzone *mz; /* mem zone to populate TX ring. */
- const struct rte_memzone *zxdh_net_hdr_mz; /* memzone to populate hdr. */
+ uint64_t offloads;
+ uint16_t queue_id; /* DPDK queue index. */
+ uint16_t port_id; /* Device port identifier. */
};
uint16_t zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts);
-
+uint16_t zxdh_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t zxdh_xmit_pkts_simple_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
#endif /* ZXDH_RXTX_H */
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 54963 bytes --]
^ permalink raw reply related
* [PATCH v8 2/4] net/zxdh: optimize queue structure to improve performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 16846 bytes --]
1. Reorganize structure fields for better cache locality.
2. Remove RX software ring (sw_ring) to reduce memory allocation and
copy.
3. Remove zxdh_mb(), use native rte_mb().
4. optimize zxdh_queue_notify() functions, remove unnecessary feature
check.
Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
drivers/net/zxdh/zxdh_ethdev.c | 33 +--------
drivers/net/zxdh/zxdh_pci.c | 2 +-
drivers/net/zxdh/zxdh_queue.c | 11 ++-
drivers/net/zxdh/zxdh_queue.h | 120 ++++++++++++++++-----------------
drivers/net/zxdh/zxdh_rxtx.c | 22 +++---
5 files changed, 77 insertions(+), 111 deletions(-)
diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index 80ff19b3ea..a383619419 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -644,7 +644,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
struct zxdh_virtnet_tx *txvq = NULL;
struct zxdh_virtqueue *vq = NULL;
size_t sz_hdr_mz = 0;
- void *sw_ring = NULL;
int32_t queue_type = zxdh_get_queue_type(vtpci_logic_qidx);
int32_t numa_node = dev->device->numa_node;
uint16_t vtpci_phy_qidx = 0;
@@ -692,11 +691,10 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
vq->vq_queue_index = vtpci_phy_qidx;
vq->vq_nentries = vq_size;
- vq->vq_packed.used_wrap_counter = 1;
- vq->vq_packed.cached_flags = ZXDH_VRING_PACKED_DESC_F_AVAIL;
- vq->vq_packed.event_flags_shadow = 0;
+ vq->used_wrap_counter = 1;
+ vq->cached_flags = ZXDH_VRING_PACKED_DESC_F_AVAIL;
if (queue_type == ZXDH_VTNET_RQ)
- vq->vq_packed.cached_flags |= ZXDH_VRING_DESC_F_WRITE;
+ vq->cached_flags |= ZXDH_VRING_DESC_F_WRITE;
/*
* Reserve a memzone for vring elements
@@ -741,16 +739,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
}
if (queue_type == ZXDH_VTNET_RQ) {
- size_t sz_sw = (ZXDH_MBUF_BURST_SZ + vq_size) * sizeof(vq->sw_ring[0]);
-
- sw_ring = rte_zmalloc_socket("sw_ring", sz_sw, RTE_CACHE_LINE_SIZE, numa_node);
- if (!sw_ring) {
- PMD_DRV_LOG(ERR, "can not allocate RX soft ring");
- ret = -ENOMEM;
- goto fail_q_alloc;
- }
-
- vq->sw_ring = sw_ring;
rxvq = &vq->rxq;
rxvq->vq = vq;
rxvq->port_id = dev->data->port_id;
@@ -764,23 +752,9 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
txvq->zxdh_net_hdr_mem = hdr_mz->iova;
}
- vq->offset = offsetof(struct rte_mbuf, buf_iova);
if (queue_type == ZXDH_VTNET_TQ) {
struct zxdh_tx_region *txr = hdr_mz->addr;
- uint32_t i;
-
memset(txr, 0, vq_size * sizeof(*txr));
- for (i = 0; i < vq_size; i++) {
- /* first indirect descriptor is always the tx header */
- struct zxdh_vring_packed_desc *start_dp = txr[i].tx_packed_indir;
-
- zxdh_vring_desc_init_indirect_packed(start_dp,
- RTE_DIM(txr[i].tx_packed_indir));
- start_dp->addr = txvq->zxdh_net_hdr_mem + i * sizeof(*txr) +
- offsetof(struct zxdh_tx_region, tx_hdr);
- /* length will be updated to actual pi hdr size when xmit pkt */
- start_dp->len = 0;
- }
}
if (ZXDH_VTPCI_OPS(hw)->setup_queue(hw, vq) < 0) {
PMD_DRV_LOG(ERR, "setup_queue failed");
@@ -788,7 +762,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
}
return 0;
fail_q_alloc:
- rte_free(sw_ring);
rte_memzone_free(hdr_mz);
rte_memzone_free(mz);
rte_free(vq);
diff --git a/drivers/net/zxdh/zxdh_pci.c b/drivers/net/zxdh/zxdh_pci.c
index 4ba31905fc..0bc27ed111 100644
--- a/drivers/net/zxdh/zxdh_pci.c
+++ b/drivers/net/zxdh/zxdh_pci.c
@@ -231,7 +231,7 @@ zxdh_notify_queue(struct zxdh_hw *hw, struct zxdh_virtqueue *vq)
notify_data = ((uint32_t)vq->vq_avail_idx << 16) | vq->vq_queue_index;
if (zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) &&
- (vq->vq_packed.cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
+ (vq->cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
notify_data |= RTE_BIT32(31);
PMD_DRV_LOG(DEBUG, "queue:%d notify_data 0x%x notify_addr 0x%p",
diff --git a/drivers/net/zxdh/zxdh_queue.c b/drivers/net/zxdh/zxdh_queue.c
index 7162593b16..4668cb5d13 100644
--- a/drivers/net/zxdh/zxdh_queue.c
+++ b/drivers/net/zxdh/zxdh_queue.c
@@ -407,7 +407,7 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
{
struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
struct zxdh_vq_desc_extra *dxp;
- uint16_t flags = vq->vq_packed.cached_flags;
+ uint16_t flags = vq->cached_flags;
int32_t i;
uint16_t idx;
@@ -415,7 +415,6 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
idx = vq->vq_avail_idx;
dxp = &vq->vq_descx[idx];
dxp->cookie = (void *)cookie[i];
- dxp->ndescs = 1;
/* rx pkt fill in data_off */
start_dp[idx].addr = rte_mbuf_iova_get(cookie[i]) + RTE_PKTMBUF_HEADROOM;
start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM;
@@ -423,8 +422,8 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
zxdh_queue_store_flags_packed(&start_dp[idx], flags);
if (++vq->vq_avail_idx >= vq->vq_nentries) {
vq->vq_avail_idx -= vq->vq_nentries;
- vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
- flags = vq->vq_packed.cached_flags;
+ vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+ flags = vq->cached_flags;
}
}
vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
@@ -467,7 +466,7 @@ void zxdh_queue_rxvq_flush(struct zxdh_virtqueue *vq)
int32_t cnt = 0;
i = vq->vq_used_cons_idx;
- while (zxdh_desc_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
+ while (desc_is_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
dxp = &vq->vq_descx[descs[i].id];
if (dxp->cookie != NULL) {
rte_pktmbuf_free(dxp->cookie);
@@ -477,7 +476,7 @@ void zxdh_queue_rxvq_flush(struct zxdh_virtqueue *vq)
vq->vq_used_cons_idx++;
if (vq->vq_used_cons_idx >= vq->vq_nentries) {
vq->vq_used_cons_idx -= vq->vq_nentries;
- vq->vq_packed.used_wrap_counter ^= 1;
+ vq->used_wrap_counter ^= 1;
}
i = vq->vq_used_cons_idx;
}
diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index 711ea291d0..b079272162 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -9,6 +9,7 @@
#include <rte_common.h>
#include <rte_atomic.h>
+#include <rte_io.h>
#include "zxdh_ethdev.h"
#include "zxdh_rxtx.h"
@@ -117,7 +118,6 @@ struct zxdh_vring_packed_desc_event {
};
struct zxdh_vring_packed {
- uint32_t num;
struct zxdh_vring_packed_desc *desc;
struct zxdh_vring_packed_desc_event *driver;
struct zxdh_vring_packed_desc_event *device;
@@ -129,50 +129,59 @@ struct zxdh_vq_desc_extra {
uint16_t next;
};
+struct zxdh_vring {
+ uint32_t num;
+ struct zxdh_vring_desc *desc;
+ struct zxdh_vring_avail *avail;
+ struct zxdh_vring_used *used;
+};
+
struct zxdh_virtqueue {
+ union {
+ struct {
+ struct zxdh_vring ring; /**< vring keeping desc, used and avail */
+ } vq_split;
+ struct __rte_packed_begin {
+ struct zxdh_vring_packed ring;
+ } __rte_packed_end vq_packed;
+ };
struct zxdh_hw *hw; /* < zxdh_hw structure pointer. */
- struct {
- /* vring keeping descs and events */
- struct zxdh_vring_packed ring;
- uint8_t used_wrap_counter;
- uint8_t rsv;
- uint16_t cached_flags; /* < cached flags for descs */
- uint16_t event_flags_shadow;
- uint16_t rsv1;
- } vq_packed;
-
- uint16_t vq_used_cons_idx; /* < last consumed descriptor */
- uint16_t vq_nentries; /* < vring desc numbers */
- uint16_t vq_free_cnt; /* < num of desc available */
- uint16_t vq_avail_idx; /* < sync until needed */
- uint16_t vq_free_thresh; /* < free threshold */
- uint16_t rsv2;
-
- void *vq_ring_virt_mem; /* < linear address of vring */
- uint32_t vq_ring_size;
+ uint16_t vq_used_cons_idx; /**< last consumed descriptor */
+ uint16_t vq_avail_idx; /**< sync until needed */
+ uint16_t vq_nentries; /**< vring desc numbers */
+ uint16_t vq_free_cnt; /**< num of desc available */
+
+ uint16_t cached_flags; /**< cached flags for descs */
+ uint8_t used_wrap_counter;
+ uint8_t rsv;
+ uint16_t vq_free_thresh; /**< free threshold */
+ uint16_t next_qidx;
+
+ void *notify_addr;
union {
struct zxdh_virtnet_rx rxq;
struct zxdh_virtnet_tx txq;
};
- /*
- * physical address of vring, or virtual address
- */
- rte_iova_t vq_ring_mem;
+ uint16_t vq_queue_index; /* PACKED: phy_idx, SPLIT: logic_idx */
+ uint16_t event_flags_shadow;
+ uint32_t vq_ring_size;
- /*
+ /**
* Head of the free chain in the descriptor table. If
* there are no free descriptors, this will be set to
* VQ_RING_DESC_CHAIN_END.
- */
+ **/
uint16_t vq_desc_head_idx;
uint16_t vq_desc_tail_idx;
- uint16_t vq_queue_index; /* < PCI queue index */
- uint16_t offset; /* < relative offset to obtain addr in mbuf */
- uint16_t *notify_addr;
- struct rte_mbuf **sw_ring; /* < RX software ring. */
+ uint32_t rsv_8B;
+
+ void *vq_ring_virt_mem; /**< linear address of vring*/
+ /* physical address of vring, or virtual address for virtio_user. */
+ rte_iova_t vq_ring_mem;
+
struct zxdh_vq_desc_extra vq_descx[];
};
@@ -296,10 +305,9 @@ static inline void
zxdh_vring_init_packed(struct zxdh_vring_packed *vr, uint8_t *p,
unsigned long align, uint32_t num)
{
- vr->num = num;
vr->desc = (struct zxdh_vring_packed_desc *)p;
vr->driver = (struct zxdh_vring_packed_desc_event *)(p +
- vr->num * sizeof(struct zxdh_vring_packed_desc));
+ num * sizeof(struct zxdh_vring_packed_desc));
vr->device = (struct zxdh_vring_packed_desc_event *)RTE_ALIGN_CEIL(((uintptr_t)vr->driver +
sizeof(struct zxdh_vring_packed_desc_event)), align);
}
@@ -331,30 +339,21 @@ zxdh_vring_desc_init_indirect_packed(struct zxdh_vring_packed_desc *dp, int32_t
static inline void
zxdh_queue_disable_intr(struct zxdh_virtqueue *vq)
{
- if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_DISABLE) {
- vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
- vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
+ if (vq->event_flags_shadow != ZXDH_RING_EVENT_FLAGS_DISABLE) {
+ vq->event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
+ vq->vq_packed.ring.driver->desc_event_flags = vq->event_flags_shadow;
}
}
static inline void
zxdh_queue_enable_intr(struct zxdh_virtqueue *vq)
{
- if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
- vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
- vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
+ if (vq->event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
+ vq->event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
+ vq->vq_packed.ring.driver->desc_event_flags = vq->event_flags_shadow;
}
}
-static inline void
-zxdh_mb(uint8_t weak_barriers)
-{
- if (weak_barriers)
- rte_atomic_thread_fence(rte_memory_order_seq_cst);
- else
- rte_mb();
-}
-
static inline
int32_t desc_is_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue *vq)
{
@@ -365,7 +364,7 @@ int32_t desc_is_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue
rte_io_rmb();
used = !!(flags & ZXDH_VRING_PACKED_DESC_F_USED);
avail = !!(flags & ZXDH_VRING_PACKED_DESC_F_AVAIL);
- return avail == used && used == vq->vq_packed.used_wrap_counter;
+ return avail == used && used == vq->used_wrap_counter;
}
static inline int32_t
@@ -381,22 +380,17 @@ zxdh_queue_store_flags_packed(struct zxdh_vring_packed_desc *dp, uint16_t flags)
dp->flags = flags;
}
-static inline int32_t
-zxdh_desc_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue *vq)
-{
- uint16_t flags;
- uint16_t used, avail;
-
- flags = desc->flags;
- rte_io_rmb();
- used = !!(flags & ZXDH_VRING_PACKED_DESC_F_USED);
- avail = !!(flags & ZXDH_VRING_PACKED_DESC_F_AVAIL);
- return avail == used && used == vq->vq_packed.used_wrap_counter;
-}
-
static inline void zxdh_queue_notify(struct zxdh_virtqueue *vq)
{
- ZXDH_VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
+ /* Bit[0:15]: vq queue index
+ * Bit[16:30]: avail index
+ * Bit[31]: avail wrap counter
+ */
+ uint32_t notify_data = ((uint32_t)(!!(vq->cached_flags &
+ ZXDH_VRING_PACKED_DESC_F_AVAIL)) << 31) |
+ ((uint32_t)vq->vq_avail_idx << 16) |
+ vq->vq_queue_index;
+ rte_write32(notify_data, vq->notify_addr);
}
static inline int32_t
@@ -404,7 +398,7 @@ zxdh_queue_kick_prepare_packed(struct zxdh_virtqueue *vq)
{
uint16_t flags = 0;
- zxdh_mb(1);
+ rte_mb();
flags = vq->vq_packed.ring.device->desc_event_flags;
return (flags != ZXDH_RING_EVENT_FLAGS_DISABLE);
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index db86922aea..93506a4b49 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -216,7 +216,7 @@ zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
/* desc_is_used has a load-acquire or rte_io_rmb inside
* and wait for used desc in virtqueue.
*/
- while (num > 0 && zxdh_desc_used(&desc[used_idx], vq)) {
+ while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
id = desc[used_idx].id;
do {
curr_id = used_idx;
@@ -226,7 +226,7 @@ zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
num -= dxp->ndescs;
if (used_idx >= size) {
used_idx -= size;
- vq->vq_packed.used_wrap_counter ^= 1;
+ vq->used_wrap_counter ^= 1;
}
if (dxp->cookie != NULL) {
rte_pktmbuf_free(dxp->cookie);
@@ -340,7 +340,7 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
struct zxdh_virtqueue *vq = txvq->vq;
uint16_t id = vq->vq_avail_idx;
struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
- uint16_t flags = vq->vq_packed.cached_flags;
+ uint16_t flags = vq->cached_flags;
struct zxdh_net_hdr_dl *hdr = NULL;
uint8_t hdr_len = vq->hw->dl_net_hdr_len;
struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[id];
@@ -355,7 +355,7 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
dp->id = id;
if (++vq->vq_avail_idx >= vq->vq_nentries) {
vq->vq_avail_idx -= vq->vq_nentries;
- vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+ vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
}
vq->vq_free_cnt--;
zxdh_queue_store_flags_packed(dp, flags);
@@ -381,7 +381,7 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
dxp->ndescs = needed;
dxp->cookie = cookie;
- head_flags |= vq->vq_packed.cached_flags;
+ head_flags |= vq->cached_flags;
start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
start_dp[idx].len = hdr_len;
@@ -392,7 +392,7 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
idx++;
if (idx >= vq->vq_nentries) {
idx -= vq->vq_nentries;
- vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+ vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
}
zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
@@ -404,14 +404,14 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
if (likely(idx != head_idx)) {
uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
- flags |= vq->vq_packed.cached_flags;
+ flags |= vq->cached_flags;
start_dp[idx].flags = flags;
}
idx++;
if (idx >= vq->vq_nentries) {
idx -= vq->vq_nentries;
- vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+ vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
}
} while ((cookie = cookie->next) != NULL);
@@ -480,7 +480,7 @@ zxdh_xmit_flush(struct zxdh_virtqueue *vq)
free_cnt += dxp->ndescs;
if (used_idx >= size) {
used_idx -= size;
- vq->vq_packed.used_wrap_counter ^= 1;
+ vq->used_wrap_counter ^= 1;
}
if (dxp->cookie != NULL) {
rte_pktmbuf_free(dxp->cookie);
@@ -619,7 +619,7 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
* desc_is_used has a load-acquire or rte_io_rmb inside
* and wait for used desc in virtqueue.
*/
- if (!zxdh_desc_used(&desc[used_idx], vq))
+ if (!desc_is_used(&desc[used_idx], vq))
return i;
len[i] = desc[used_idx].len;
id = desc[used_idx].id;
@@ -637,7 +637,7 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
vq->vq_used_cons_idx++;
if (vq->vq_used_cons_idx >= vq->vq_nentries) {
vq->vq_used_cons_idx -= vq->vq_nentries;
- vq->vq_packed.used_wrap_counter ^= 1;
+ vq->used_wrap_counter ^= 1;
}
}
return i;
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 38856 bytes --]
^ permalink raw reply related
* [PATCH v8 3/4] net/zxdh: optimize Rx recv pkts performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 16239 bytes --]
1. Add simple RX recv functions (zxdh_recv_single_pkts)
for single-segment packet recv.
2. And optimize Rx recv pkts packed ops.
3. Remove unnecessary ZXDH_NET_F_MRG_RXBUF negotiation check and
some unnecessary statistical counters form the xstats name tables.
Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
drivers/net/zxdh/zxdh_ethdev.c | 39 +++++--
drivers/net/zxdh/zxdh_ethdev_ops.c | 23 ++--
drivers/net/zxdh/zxdh_ethdev_ops.h | 4 +
drivers/net/zxdh/zxdh_rxtx.c | 174 +++++++++++++++++++++++------
drivers/net/zxdh/zxdh_rxtx.h | 16 +--
5 files changed, 193 insertions(+), 63 deletions(-)
diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index a383619419..fe76139f3d 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -1263,18 +1263,43 @@ zxdh_dev_close(struct rte_eth_dev *dev)
return ret;
}
-static int32_t
-zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
+/*
+ * Determine whether the current configuration requires support for scattered
+ * receive; return 1 if scattered receive is required and 0 if not.
+ */
+static int zxdh_scattered_rx(struct rte_eth_dev *eth_dev)
{
- struct zxdh_hw *hw = eth_dev->data->dev_private;
+ uint16_t buf_size;
- if (!zxdh_pci_with_feature(hw, ZXDH_NET_F_MRG_RXBUF)) {
- PMD_DRV_LOG(ERR, "port %u not support rx mergeable", eth_dev->data->port_id);
- return -1;
+ if (eth_dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) {
+ eth_dev->data->lro = 1;
+ return 1;
}
+
+ if (eth_dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER)
+ return 1;
+
+ PMD_DRV_LOG(DEBUG, "port %u min_rx_buf_size %u",
+ eth_dev->data->port_id, eth_dev->data->min_rx_buf_size);
+ buf_size = eth_dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+ if (eth_dev->data->mtu + ZXDH_ETH_OVERHEAD > buf_size)
+ return 1;
+
+ return 0;
+}
+
+static int32_t
+zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
+{
eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+ eth_dev->data->scattered_rx = zxdh_scattered_rx(eth_dev);
+
eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
- eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
+
+ if (eth_dev->data->scattered_rx)
+ eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
+ else
+ eth_dev->rx_pkt_burst = &zxdh_recv_single_pkts;
return 0;
}
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.c b/drivers/net/zxdh/zxdh_ethdev_ops.c
index 50247116d9..9a8e05e941 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.c
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.c
@@ -95,10 +95,6 @@ static const struct rte_zxdh_xstats_name_off zxdh_rxq_stat_strings[] = {
{"good_bytes", offsetof(struct zxdh_virtnet_rx, stats.bytes)},
{"errors", offsetof(struct zxdh_virtnet_rx, stats.errors)},
{"idle", offsetof(struct zxdh_virtnet_rx, stats.idle)},
- {"full", offsetof(struct zxdh_virtnet_rx, stats.full)},
- {"norefill", offsetof(struct zxdh_virtnet_rx, stats.norefill)},
- {"multicast_packets", offsetof(struct zxdh_virtnet_rx, stats.multicast)},
- {"broadcast_packets", offsetof(struct zxdh_virtnet_rx, stats.broadcast)},
{"truncated_err", offsetof(struct zxdh_virtnet_rx, stats.truncated_err)},
{"offload_cfg_err", offsetof(struct zxdh_virtnet_rx, stats.offload_cfg_err)},
{"invalid_hdr_len_err", offsetof(struct zxdh_virtnet_rx, stats.invalid_hdr_len_err)},
@@ -117,14 +113,12 @@ static const struct rte_zxdh_xstats_name_off zxdh_txq_stat_strings[] = {
{"good_packets", offsetof(struct zxdh_virtnet_tx, stats.packets)},
{"good_bytes", offsetof(struct zxdh_virtnet_tx, stats.bytes)},
{"errors", offsetof(struct zxdh_virtnet_tx, stats.errors)},
- {"idle", offsetof(struct zxdh_virtnet_tx, stats.idle)},
- {"norefill", offsetof(struct zxdh_virtnet_tx, stats.norefill)},
- {"multicast_packets", offsetof(struct zxdh_virtnet_tx, stats.multicast)},
- {"broadcast_packets", offsetof(struct zxdh_virtnet_tx, stats.broadcast)},
+ {"idle", offsetof(struct zxdh_virtnet_tx, stats.idle)},
{"truncated_err", offsetof(struct zxdh_virtnet_tx, stats.truncated_err)},
{"offload_cfg_err", offsetof(struct zxdh_virtnet_tx, stats.offload_cfg_err)},
{"invalid_hdr_len_err", offsetof(struct zxdh_virtnet_tx, stats.invalid_hdr_len_err)},
{"no_segs_err", offsetof(struct zxdh_virtnet_tx, stats.no_segs_err)},
+ {"no_free_tx_desc_err", offsetof(struct zxdh_virtnet_tx, stats.no_free_tx_desc_err)},
{"undersize_packets", offsetof(struct zxdh_virtnet_tx, stats.size_bins[0])},
{"size_64_packets", offsetof(struct zxdh_virtnet_tx, stats.size_bins[1])},
{"size_65_127_packets", offsetof(struct zxdh_virtnet_tx, stats.size_bins[2])},
@@ -2026,6 +2020,19 @@ int zxdh_dev_mtu_set(struct rte_eth_dev *dev, uint16_t new_mtu)
uint16_t vfid = zxdh_vport_to_vfid(hw->vport);
int ret;
+ /* If device is started, refuse mtu that requires the support of
+ * scattered packets when this feature has not been enabled before.
+ */
+ if (dev->data->dev_started) {
+ uint32_t buf_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+ uint8_t need_scatter = (uint32_t)ZXDH_MTU_TO_PKTLEN(new_mtu) > buf_size;
+
+ if (need_scatter != dev->data->scattered_rx) {
+ PMD_DRV_LOG(ERR, "Stop port first.");
+ return -EINVAL;
+ }
+ }
+
if (hw->is_pf) {
ret = zxdh_get_panel_attr(dev, &panel);
if (ret != 0) {
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.h b/drivers/net/zxdh/zxdh_ethdev_ops.h
index 6dfe4be473..c49d79c232 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.h
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.h
@@ -40,6 +40,10 @@
#define ZXDH_SPM_SPEED_4X_100G RTE_BIT32(10)
#define ZXDH_SPM_SPEED_4X_200G RTE_BIT32(11)
+#define ZXDH_VLAN_TAG_LEN 4
+#define ZXDH_ETH_OVERHEAD (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + ZXDH_VLAN_TAG_LEN * 2)
+#define ZXDH_MTU_TO_PKTLEN(mtu) ((mtu) + ZXDH_ETH_OVERHEAD)
+
struct zxdh_np_stats_data {
uint64_t n_pkts_dropped;
uint64_t n_bytes_dropped;
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index 93506a4b49..ab0510a753 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -613,10 +613,12 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
uint16_t i, used_idx;
uint16_t id;
+ used_idx = vq->vq_used_cons_idx;
+ rte_prefetch0(&desc[used_idx]);
+
for (i = 0; i < num; i++) {
used_idx = vq->vq_used_cons_idx;
- /**
- * desc_is_used has a load-acquire or rte_io_rmb inside
+ /* desc_is_used has a load-acquire or rte_io_rmb inside
* and wait for used desc in virtqueue.
*/
if (!desc_is_used(&desc[used_idx], vq))
@@ -823,17 +825,52 @@ zxdh_rx_update_mbuf(struct zxdh_hw *hw, struct rte_mbuf *m, struct zxdh_net_hdr_
}
}
-static void zxdh_discard_rxbuf(struct zxdh_virtqueue *vq, struct rte_mbuf *m)
+static void refill_desc_unwrap(struct zxdh_virtqueue *vq,
+ struct rte_mbuf **cookie, uint16_t nb_pkts)
{
- int32_t error = 0;
- /*
- * Requeue the discarded mbuf. This should always be
- * successful since it was just dequeued.
- */
- error = zxdh_enqueue_recv_refill_packed(vq, &m, 1);
- if (unlikely(error)) {
- PMD_RX_LOG(ERR, "cannot enqueue discarded mbuf");
- rte_pktmbuf_free(m);
+ struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
+ struct zxdh_vq_desc_extra *dxp;
+ uint16_t flags = vq->cached_flags;
+ int32_t i;
+ uint16_t idx;
+
+ idx = vq->vq_avail_idx;
+ for (i = 0; i < nb_pkts; i++) {
+ dxp = &vq->vq_descx[idx];
+ dxp->cookie = (void *)cookie[i];
+ start_dp[idx].addr = rte_mbuf_iova_get(cookie[i]) + RTE_PKTMBUF_HEADROOM;
+ start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM;
+ zxdh_queue_store_flags_packed(&start_dp[idx], flags);
+ idx++;
+ }
+ vq->vq_avail_idx += nb_pkts;
+ vq->vq_free_cnt = vq->vq_free_cnt - nb_pkts;
+}
+
+static void refill_que_descs(struct zxdh_virtqueue *vq, struct rte_eth_dev *dev)
+{
+ /* free_cnt may include mrg descs */
+ struct rte_mbuf *new_pkts[ZXDH_MBUF_BURST_SZ];
+ uint16_t free_cnt = RTE_MIN(ZXDH_MBUF_BURST_SZ, vq->vq_free_cnt);
+ struct zxdh_virtnet_rx *rxvq = &vq->rxq;
+ uint16_t unwrap_cnt, left_cnt;
+
+ if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
+ left_cnt = free_cnt;
+ unwrap_cnt = 0;
+ if ((vq->vq_avail_idx + free_cnt) >= vq->vq_nentries) {
+ unwrap_cnt = vq->vq_nentries - vq->vq_avail_idx;
+ left_cnt = free_cnt - unwrap_cnt;
+ refill_desc_unwrap(vq, new_pkts, unwrap_cnt);
+ vq->vq_avail_idx = 0;
+ vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+ }
+ if (left_cnt)
+ refill_desc_unwrap(vq, new_pkts + unwrap_cnt, left_cnt);
+
+ rte_io_wmb();
+ } else {
+ dev->data->rx_mbuf_alloc_failed += free_cnt;
}
}
@@ -852,7 +889,6 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t len = 0;
uint32_t seg_num = 0;
uint32_t seg_res = 0;
- uint32_t error = 0;
uint16_t hdr_size = 0;
uint16_t nb_rx = 0;
uint16_t i;
@@ -873,7 +909,8 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
rx_pkts[nb_rx] = rxm;
prev = rxm;
len = lens[i];
- header = rte_pktmbuf_mtod(rxm, struct zxdh_net_hdr_ul *);
+ header = (struct zxdh_net_hdr_ul *)((char *)
+ rxm->buf_addr + RTE_PKTMBUF_HEADROOM);
seg_num = header->type_hdr.num_buffers;
@@ -886,7 +923,7 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
rxvq->stats.invalid_hdr_len_err++;
continue;
}
- rxm->data_off += hdr_size;
+ rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
rxm->nb_segs = seg_num;
rxm->ol_flags = 0;
rcvd_pkt_len = len - hdr_size;
@@ -902,18 +939,19 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
len = lens[i];
rxm = rcv_pkts[i];
rxm->data_len = len;
+ rxm->data_off = RTE_PKTMBUF_HEADROOM;
rcvd_pkt_len += len;
prev->next = rxm;
prev = rxm;
rxm->next = NULL;
- seg_res -= 1;
+ seg_res--;
}
if (!seg_res) {
if (rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len) {
PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
- zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
+ rte_pktmbuf_free(rx_pkts[nb_rx]);
rxvq->stats.errors++;
rxvq->stats.truncated_err++;
continue;
@@ -942,14 +980,14 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
prev->next = rxm;
prev = rxm;
rxm->next = NULL;
- extra_idx += 1;
+ extra_idx++;
}
seg_res -= rcv_cnt;
if (!seg_res) {
if (unlikely(rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len)) {
PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
- zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
+ rte_pktmbuf_free(rx_pkts[nb_rx]);
rxvq->stats.errors++;
rxvq->stats.truncated_err++;
continue;
@@ -961,26 +999,88 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
rxvq->stats.packets += nb_rx;
refill:
- /* Allocate new mbuf for the used descriptor */
- if (likely(!zxdh_queue_full(vq))) {
- struct rte_mbuf *new_pkts[ZXDH_MBUF_BURST_SZ];
- /* free_cnt may include mrg descs */
- uint16_t free_cnt = RTE_MIN(vq->vq_free_cnt, ZXDH_MBUF_BURST_SZ);
-
- if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
- error = zxdh_enqueue_recv_refill_packed(vq, new_pkts, free_cnt);
- if (unlikely(error)) {
- for (i = 0; i < free_cnt; i++)
- rte_pktmbuf_free(new_pkts[i]);
- }
+ if (vq->vq_free_cnt > 0) {
+ struct rte_eth_dev *dev = hw->eth_dev;
+ refill_que_descs(vq, dev);
+ zxdh_queue_notify(vq);
+ }
- if (unlikely(zxdh_queue_kick_prepare_packed(vq)))
- zxdh_queue_notify(vq);
- } else {
- struct rte_eth_dev *dev = hw->eth_dev;
+ return nb_rx;
+}
- dev->data->rx_mbuf_alloc_failed += free_cnt;
- }
+static inline int zxdh_init_mbuf(struct rte_mbuf *rxm, uint16_t len,
+ struct zxdh_hw *hw, struct zxdh_virtnet_rx *rxvq)
+{
+ uint16_t hdr_size = 0;
+ struct zxdh_net_hdr_ul *header;
+
+ header = rte_pktmbuf_mtod(rxm, struct zxdh_net_hdr_ul *);
+ rxm->ol_flags = 0;
+ rxm->vlan_tci = 0;
+ rxm->vlan_tci_outer = 0;
+
+ hdr_size = header->type_hdr.pd_len << 1;
+ if (unlikely(header->type_hdr.num_buffers != 1)) {
+ PMD_RX_LOG(DEBUG, "hdr_size:%u nb_segs %d is invalid",
+ hdr_size, header->type_hdr.num_buffers);
+ rte_pktmbuf_free(rxm);
+ rxvq->stats.invalid_hdr_len_err++;
+ return -1;
+ }
+ zxdh_rx_update_mbuf(hw, rxm, header);
+
+ rxm->nb_segs = 1;
+ rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
+ rxm->data_len = len - hdr_size;
+ rxm->port = hw->port_id;
+
+ if (rxm->data_len != rxm->pkt_len) {
+ PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d bufaddr %p.",
+ rxm->data_len, rxm->pkt_len, rxm->buf_addr);
+ rte_pktmbuf_free(rxm);
+ rxvq->stats.truncated_err++;
+ rxvq->stats.errors++;
+ return -1;
+ }
+ return 0;
+}
+
+uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts)
+{
+ struct zxdh_virtnet_rx *rxvq = rx_queue;
+ struct zxdh_virtqueue *vq = rxvq->vq;
+ struct zxdh_hw *hw = vq->hw;
+ uint32_t lens[ZXDH_MBUF_BURST_SZ];
+ uint16_t nb_rx = 0;
+ uint16_t num;
+ uint16_t i;
+
+ num = nb_pkts;
+ if (unlikely(num > ZXDH_MBUF_BURST_SZ))
+ num = ZXDH_MBUF_BURST_SZ;
+ num = zxdh_dequeue_burst_rx_packed(vq, rcv_pkts, lens, num);
+ if (num == 0) {
+ rxvq->stats.idle++;
+ goto refill;
+ }
+
+ for (i = 0; i < num; i++) {
+ struct rte_mbuf *rxm = rcv_pkts[i];
+ uint16_t len = lens[i];
+
+ if (unlikely(zxdh_init_mbuf(rxm, len, hw, &vq->rxq) < 0))
+ continue;
+ rcv_pkts[nb_rx] = rxm;
+ zxdh_update_packet_stats(&rxvq->stats, rxm);
+ nb_rx++;
+ }
+ rxvq->stats.packets += nb_rx;
+
+refill:
+ if (vq->vq_free_cnt > 0) {
+ struct rte_eth_dev *dev = hw->eth_dev;
+ refill_que_descs(vq, dev);
+ zxdh_queue_notify(vq);
}
return nb_rx;
}
diff --git a/drivers/net/zxdh/zxdh_rxtx.h b/drivers/net/zxdh/zxdh_rxtx.h
index 424048607e..dba9567414 100644
--- a/drivers/net/zxdh/zxdh_rxtx.h
+++ b/drivers/net/zxdh/zxdh_rxtx.h
@@ -36,29 +36,22 @@ struct zxdh_virtnet_stats {
uint64_t bytes;
uint64_t errors;
uint64_t idle;
- uint64_t full;
- uint64_t norefill;
- uint64_t multicast;
- uint64_t broadcast;
uint64_t truncated_err;
uint64_t offload_cfg_err;
uint64_t invalid_hdr_len_err;
uint64_t no_segs_err;
+ uint64_t no_free_tx_desc_err;
uint64_t size_bins[8];
};
struct __rte_cache_aligned zxdh_virtnet_rx {
struct zxdh_virtqueue *vq;
-
- uint64_t mbuf_initializer; /* value to init mbufs. */
struct rte_mempool *mpool; /* mempool for mbuf allocation */
- uint16_t queue_id; /* DPDK queue index. */
- uint16_t port_id; /* Device port identifier. */
struct zxdh_virtnet_stats stats;
const struct rte_memzone *mz; /* mem zone to populate RX ring. */
-
- /* dummy mbuf, for wraparound when processing RX ring. */
- struct rte_mbuf fake_mbuf;
+ uint64_t offloads;
+ uint16_t queue_id; /* DPDK queue index. */
+ uint16_t port_id; /* Device port identifier. */
};
struct __rte_cache_aligned zxdh_virtnet_tx {
@@ -75,5 +68,6 @@ struct __rte_cache_aligned zxdh_virtnet_tx {
uint16_t zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts);
#endif /* ZXDH_RXTX_H */
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 39105 bytes --]
^ permalink raw reply related
* [PATCH v8 1/4] net/zxdh: fix queue enable intr issues
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
To: stephen; +Cc: dev, Junlong Wang, stable
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 1196 bytes --]
Fix incorrect condition check in zxdh_queue_enable_intr.
Change "==" to "!=", consistent with zxdh_queue_disable_intr logic,
to properly enable interrupts when event_flags_shadow is not
already set to ENABLE state.
Fixes: 7677f3871ef3 ("net/zxdh: setup Rx/Tx queues and interrupt")
Cc: stable@dpdk.org
Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
drivers/net/zxdh/zxdh_queue.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index 1a0c8a0d90..711ea291d0 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -340,8 +340,8 @@ zxdh_queue_disable_intr(struct zxdh_virtqueue *vq)
static inline void
zxdh_queue_enable_intr(struct zxdh_virtqueue *vq)
{
- if (vq->vq_packed.event_flags_shadow == ZXDH_RING_EVENT_FLAGS_DISABLE) {
- vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
+ if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
+ vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
}
}
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 2002 bytes --]
^ permalink raw reply related
* [PATCH v8 0/4] net/zxdh: optimize Rx/Tx path performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260623060909.97023-1-wang.junlong1@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 4184 bytes --]
v8:
- Add checked the size of ZXDH_DL_NET_HDR_SIZE and RTE_PKTMBUF_HEADROOM in
zxdh_xmit_pkts_simple() before submitting. Add static_assert to reject builds with insufficient
default headroom at compile time.
v7:
- Add a new xmit prepare func for xmit_pkts_simple, which will checked the size of
ZXDH_DL_NET_HDR_SIZE and RTE_PKTMBUF_HEADROOM.
v6:
- Remove unnecessary error checking code in submit_to_backend_simple() and
pkt_padding(). Since as the max dl_net_hdr_len is always less than
RTE_PKTMBUF_HEADROOM, rte_pktmbuf_prepend() cannot fail in the
simple path (single-segment mbufs).
v5:
- Reorganize patch series, placing interrupt fix as the first patch
and fix condition check to properly enable interrupts.
- Fix zxdh_recv_single_pkts() not compacting rcv_pkts[] on failure,
which could cause use-after-free and mbuf leak.
- Fix tx_bunch() and tx1() missing store barrier before setting AVAIL flag,
preventing data race on weakly-ordered architectures.
- Fix submit_to_backend_simple() writing descriptors for packets that
failed pkt_padding(), causing mbuf leak.
v4:
- fix some AI review issues.
- fix queue enable intr bug.
v3:
- remove unnecessary NULL check in zxdh_init_queue.
- Split Ring: Bit[31] is unused and reserved, zxdh_queue_notify(): removing the
zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) check;
- remove unnecessary double-free in in zxdh_recv_single_pkts();
- used rte_pktmbuf_mtod();
- remove rxq_get_vq(q) macro, use q->vq and apply it consistently;
- Refactoring scatter and mtu check logic in zxdh_dev_mtu_set();
- set txdp->id = avail_idx + i in tx_bunch/tx1.
- add comment documenting zxdh_xmit_enqueue_append() now sets dxp->cookie = NULL for
the head slot and stores cookies per descriptor via dep[idx].cookie.
- add one-line comment noting tx_bunch() is the simple path handles single-segment.
- remove unnecessary Extra initialization and the uint32_t cast.
v2:
- zxdh_rxtx.c, pkt_padding(): modifyed the return value of pkt_padding();
- zxdh_rxtx.c, zxdh_recv_single_pkts(): modifyed When zxdh_init_mbuf() fails
the loop does "continue" and free mbufs;
- zxdh_rxtx.c, refill_desc_unwrap(): Add rte_io_wmb() before writing flags
in the refill_que_descs();
- zxdh_queue.h, zxdh_queue_enable_intr(): Remove unnecessary function of zxdh_queue_enable_intr;
- zxdh_ethdev.c, zxdh_init_queue(): changed the hdr_mz NULL check logic;
- zxdh_rxtx.c, zxdh_xmit_pkts_simple()、zxdh_recv_single_pkts(): add stats.bytes count;
- zxdh_rxtx.c, zxdh_init_mbuf():remove rte_pktmbuf_dump(stdout, rxm, 40);
- zxdh_ethdev.c, zxdh_dev_free_mbufs(): using rte_pktmbuf_free() to free mbufs;
- Splitting into separate patches, structure reorganization and sw_ring removal、
RX recv optimize、Tx xmit optimize、Tx;
v1:
This patch optimizes the ZXDH PMD's receive and transmit path for better
performance through several improvements:
- Add simple TX/RX burst functions (zxdh_xmit_pkts_simple and
zxdh_recv_single_pkts) for single-segment packet scenarios.
- Remove RX software ring (sw_ring) to reduce memory allocation and
copy.
- Optimize descriptor management with prefetching and simplified
cleanup.
- Reorganize structure fields for better cache locality.
These changes reduce CPU cycles and memory bandwidth consumption,
resulting in improved packet processing throughput.
Junlong Wang (4):
net/zxdh: fix queue enable intr issues
net/zxdh: optimize queue structure to improve performance
net/zxdh: optimize Rx recv pkts performance
net/zxdh: optimize Tx xmit pkts performance
drivers/net/zxdh/zxdh_ethdev.c | 83 ++--
drivers/net/zxdh/zxdh_ethdev_ops.c | 23 +-
drivers/net/zxdh/zxdh_ethdev_ops.h | 4 +
drivers/net/zxdh/zxdh_pci.c | 2 +-
drivers/net/zxdh/zxdh_queue.c | 11 +-
drivers/net/zxdh/zxdh_queue.h | 122 +++---
drivers/net/zxdh/zxdh_rxtx.c | 591 +++++++++++++++++++++++------
drivers/net/zxdh/zxdh_rxtx.h | 29 +-
8 files changed, 604 insertions(+), 261 deletions(-)
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 7543 bytes --]
^ permalink raw reply
* Re: [PATCH 0/3] Cleanup rte_dpaa_device
From: David Marchand @ 2026-06-25 11:23 UTC (permalink / raw)
To: David Marchand; +Cc: dev, hemant.agrawal
In-Reply-To: <20260611130738.1720628-1-david.marchand@redhat.com>
On Thu, 11 Jun 2026 at 15:08, David Marchand <david.marchand@redhat.com> wrote:
>
> Similar to the cleanup on the FSLMC bus, the DPAA bus device can
> be cleaned.
>
> The rte_dpaa_device object keeps track of a device class object
> (cryptodev, dmadev, ethdev) which is a layer violation.
>
> Make use of the device class respective infrastructure and remove those
> back references.
>
> Disclaimer: this series is untested as I don't have the hardware.
> I only based those changes on look at the code and other drivers.
>
>
> --
> David Marchand
>
> David Marchand (3):
> crypto/dpaa_sec: remove cryptodev pointer from bus device
> dma/dpaa: remove dmadev pointer from bus device
> net/dpaa: remove ethdev pointer from bus device
>
> drivers/bus/dpaa/bus_dpaa_driver.h | 5 ----
> drivers/crypto/dpaa_sec/dpaa_sec.c | 8 ++----
> drivers/dma/dpaa/dpaa_qdma.c | 39 +++++++++++++++---------------
> drivers/net/dpaa/dpaa_ethdev.c | 3 +--
> 4 files changed, 22 insertions(+), 33 deletions(-)
>
Series applied.
--
David Marchand
^ permalink raw reply
* RE: DPDK release candidate 26.07-rc1
From: Xu, HailinX @ 2026-06-25 10:51 UTC (permalink / raw)
To: Thomas Monjalon, dev
Cc: Puttaswamy, Rajesh T, Hosamani, Manjunathgouda, Mcnamara, John,
Richardson, Bruce, Ferruh Yigit
In-Reply-To: <EE7NFX47QzqKRvGYzs3QUA@monjalon.net>
> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Thursday, June 11, 2026 10:52 AM
> To: announce@dpdk.org
> Subject: DPDK release candidate 26.07-rc1
>
> A new DPDK release candidate is ready for testing:
> https://git.dpdk.org/dpdk/tag/?id=v26.07-rc1
>
> There are 432 new patches in this snapshot.
>
> Release notes:
> https://doc.dpdk.org/guides/rel_notes/release_26_07.html
>
> Highlights of 26.07-rc1:
> - option --pagesz-mem for per-page-size maximum
> - option --no-auto-probing for no device at init
> - less mempool cache misses in run-to-completion
> - peek style API for staged-ordered ring
> - RISC-V vector paths
> - PTP helpers and clock relay example
> - selective Rx API to save PCI bandwidth
> - vhost memory hotplug
> - pcap driver enhanced
> - LinkData sxe2 NIC driver
> - AI review helpers
>
> Important note:
> Pipelined applications, where ethdev Rx and Tx run on separate lcores, should
> adapt to the new algorithm by doubling their configured mempool cache size,
> to avoid doubling their mempool cache miss rate.
>
> Please test and report issues on bugs.dpdk.org.
>
> We plan to release -rc2 in 2 weeks.
>
> Thank you everyone
>
Update the test status for Intel part. dpdk26.07-rc1 all validation test done. found 6 new issues.
New issues:
1. [dpdk-26.07-rc1] ice_dcf: core dump occurs when creating a switch rule on DCF -> Intel development is investigating
2. [dpdk-26.07] ABI testing dpdk26.07rc1+dpdk25.11 shows error: "undefined symbol: rte_flow_dynf_metadata_offs, version EXPERIMENTAL" -> has fix patch
https://patchwork.dpdk.org/project/dpdk/list/?series=38569
3. [26.07]rss_to_rte_flow/test_set_key_keylen: create ingress failed -> has fix patch
https://patches.dpdk.org/project/dpdk/patch/7f6f11fb07bc550784335123af6a270cd514f7d7.1781692817.git.anatoly.burakov@intel.com/
4. [dpdk-26.07-rc1] ice_flow_priority:test_flow_priority_filter create flow failed -> Intel development is investigating
5. [26.07-rc1] Ice ports status is incorrect in testpmd -> Intel development is investigating
6. [dpdk-26.07][X550]meson_tests/driver: event_inline_ipsec_auto test case test failed -> has fix patch
https://patches.dpdk.org/project/dpdk/list/?series=38530
* Build & CFLAG compile: cover the build test with latest GCC/Clang version on the following OS(all passed)
- Ubuntu25.10/Ubuntu26.04
- RHEL9.6/RHEL10
- Fedora43
- FreeBSD15.0
- SUSE16
- OpenAnolis8.10
- OpenEuler24.04-SP2
- AzureLinux3.0
* Function tests: All test done and found 3 issues.
- ICE-(E810, E825, E830, E2100) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS/Switch/Package Management/Flow Director/Advanced Tx/Advanced RSS/ACL/DCF/Flexible Descriptor, etc.
- i40E-(XXV710, X722) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc.
- IXGBE-(E610, X550) PF/VF: test scenarios including basic/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc.
- IGC-(i226) PF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc.
- IPsec: test scenarios including ipsec/ipsec-gw/ipsec library basic test - QAT&SW/FIB library, etc.
- Virtio: both function and performance test are covered. Such as PVP/Virtio_loopback/virtio-user loopback/virtio-net VM2VM perf testing/VMAWARE ESXI 9.0, etc.
- Cryptodev: test scenarios including Cryptodev API testing/CompressDev ISA-L/QAT/ZLIB PMD Testing/FIPS, etc.
- DLB: test scenarios including DLB2.0 and DLB2.5
- Other: test scenarios including AF_XDP, Power, CBDMA, DSA
* Performance test: All test done and passed
- Thoughput Performance
- Cryptodev Latency
- PF/VF NIC single core
- XXV710/E810/E825/E2100 NIC Performance
Regards,
Xu, Hailin
^ permalink raw reply
* [PATCH 3/3] net/iavf: fix Rx packets statistics underflow
From: Ciara Loftus @ 2026-06-25 9:36 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus, stable
In-Reply-To: <20260625093619.726471-1-ciara.loftus@intel.com>
The number of Rx packets is computed as the sum of the unicast,
multicast and broadcast packet counters, minus the discarded packet
count:
ipackets = rx_unicast + rx_multicast + rx_broadcast - rx_discards
The unicast, multicast and broadcast counters already include the
packets that were subsequently dropped, so subtracting rx_discards
yields only the packets delivered to the application. These values are
provided by the PF in a virtchnl_eth_stats message; the PF samples them
from separate sources and the VF cannot guarantee the order in which
they are read. Under load, rx_discards can therefore momentarily exceed
the sum of the unicast, multicast and broadcast counters. As ipackets is
unsigned, the subtraction then wraps to a huge bogus value, reported to
the application as an enormous Rx packet count and packet rate.
The read order cannot be guaranteed from the VF, so use a saturating
subtraction: when rx_discards exceeds the sum of the unicast, multicast
and broadcast counters essentially nothing was delivered, so report zero
instead of underflowing.
Fixes: e71ffcc1008e ("net/iavf: fix Rx total stats")
Cc: stable@dpdk.org
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
drivers/net/intel/iavf/iavf_ethdev.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index ec1ad02826..f2b100e290 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -1887,8 +1887,16 @@ iavf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
RTE_ETH_RX_OFFLOAD_KEEP_CRC) ? 0 :
RTE_ETHER_CRC_LEN;
iavf_update_stats(vsi, &pstats);
- stats->ipackets = pstats.rx_unicast + pstats.rx_multicast +
- pstats.rx_broadcast - pstats.rx_discards;
+ stats->ipackets = pstats.rx_unicast + pstats.rx_multicast + pstats.rx_broadcast;
+ /*
+ * Unicast/multicast/broadcast counters include discarded packets, so subtract
+ * rx_discards to report only the packets delivered to the application. The
+ * counters are sampled from separate sources and can be momentarily inconsistent
+ * under load. If rx_discards exceeds their sum then essentially nothing was
+ * delivered, so saturate at zero rather than underflow.
+ */
+ stats->ipackets = stats->ipackets >= pstats.rx_discards ?
+ stats->ipackets - pstats.rx_discards : 0;
stats->opackets = pstats.tx_broadcast + pstats.tx_multicast +
pstats.tx_unicast;
stats->imissed = pstats.rx_discards;
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] net/ice: fix DCF Rx packets statistics underflow
From: Ciara Loftus @ 2026-06-25 9:36 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus, stable
In-Reply-To: <20260625093619.726471-1-ciara.loftus@intel.com>
The number of Rx packets is computed as the sum of the unicast,
multicast and broadcast packet counters, minus the discarded packet
count:
ipackets = rx_unicast + rx_multicast + rx_broadcast - rx_discards
The unicast, multicast and broadcast counters already include the
packets that were subsequently dropped, so subtracting rx_discards
yields only the packets delivered to the application. These values are
provided by the PF in a virtchnl_eth_stats message; the PF samples them
from separate sources and the order in which they are read cannot be
guaranteed. Under load, rx_discards can therefore momentarily exceed the
sum of the unicast, multicast and broadcast counters. As ipackets is
unsigned, the subtraction then wraps to a huge bogus value, reported to
the application as an enormous Rx packet count and packet rate.
The read order cannot be guaranteed, so use a saturating subtraction:
when rx_discards exceeds the sum of the unicast, multicast and broadcast
counters essentially nothing was delivered, so report zero instead of
underflowing.
Fixes: c9f889e99616 ("net/ice: enable stats for DCF")
Cc: stable@dpdk.org
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
drivers/net/intel/ice/ice_dcf_ethdev.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/intel/ice/ice_dcf_ethdev.c b/drivers/net/intel/ice/ice_dcf_ethdev.c
index 4fce59617e..c78b290b0d 100644
--- a/drivers/net/intel/ice/ice_dcf_ethdev.c
+++ b/drivers/net/intel/ice/ice_dcf_ethdev.c
@@ -1523,8 +1523,16 @@ ice_dcf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
ret = ice_dcf_query_stats(hw, &pstats);
if (ret == 0) {
ice_dcf_update_stats(&hw->eth_stats_offset, &pstats);
- stats->ipackets = pstats.rx_unicast + pstats.rx_multicast +
- pstats.rx_broadcast - pstats.rx_discards;
+ stats->ipackets = pstats.rx_unicast + pstats.rx_multicast + pstats.rx_broadcast;
+ /*
+ * Unicast/multicast/broadcast counters include discarded packets, so subtract
+ * rx_discards to report only the packets delivered to the application. The
+ * counters are sampled from separate sources and can be momentarily inconsistent
+ * under load. If rx_discards exceeds their sum then essentially nothing was
+ * delivered, so saturate at zero rather than underflow.
+ */
+ stats->ipackets = stats->ipackets >= pstats.rx_discards ?
+ stats->ipackets - pstats.rx_discards : 0;
stats->opackets = pstats.tx_broadcast + pstats.tx_multicast +
pstats.tx_unicast;
stats->imissed = pstats.rx_discards;
--
2.43.0
^ permalink raw reply related
* [PATCH 1/3] net/ice: fix Rx packets statistics underflow
From: Ciara Loftus @ 2026-06-25 9:36 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus, stable
In-Reply-To: <20260625093619.726471-1-ciara.loftus@intel.com>
The number of Rx packets is computed as the sum of the unicast,
multicast and broadcast packet counters, minus the discarded packet
count:
ipackets = rx_unicast + rx_multicast + rx_broadcast - rx_discards
The unicast, multicast and broadcast counters already include the
packets that were subsequently dropped, so subtracting rx_discards
yields only the packets delivered to the application. However, each of
these counters is read from a separate hardware register, and the reads
happen at slightly different instants. Under load, rx_discards (read
last) can momentarily exceed the sum of the unicast, multicast and
broadcast counters (read earlier). As ipackets is unsigned, the
subtraction then wraps to a huge bogus value, reported to the
application as an enormous Rx packet count and packet rate.
Read the rx_discards register before the unicast, multicast and
broadcast registers. As all of these counters only ever increase, and
the unicast, multicast and broadcast counters always include the
discarded packets, sampling rx_discards first guarantees it can never
exceed the later sum of the other three, so the subtraction can never
underflow.
Fixes: a37bde56314d ("net/ice: support statistics")
Cc: stable@dpdk.org
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
drivers/net/intel/ice/ice_ethdev.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/intel/ice/ice_ethdev.c b/drivers/net/intel/ice/ice_ethdev.c
index ad9c49b339..94e07446be 100644
--- a/drivers/net/intel/ice/ice_ethdev.c
+++ b/drivers/net/intel/ice/ice_ethdev.c
@@ -6457,6 +6457,15 @@ ice_update_vsi_stats(struct ice_vsi *vsi)
struct ice_hw *hw = ICE_VSI_TO_HW(vsi);
int idx = rte_le_to_cpu_16(vsi->vsi_id);
+ /*
+ * Unicast/multicast/broadcast counters include discarded packets. Received packets is
+ * calculated by deducting discards from unicast/multicast/broadcast. To prevent a
+ * potential underflow, read discards first to guarantee it is smaller than
+ * unicast/multicast/broadcast.
+ */
+ ice_stat_update_32(hw, GLV_RDPC(idx), vsi->offset_loaded,
+ &oes->rx_discards, &nes->rx_discards);
+
ice_stat_update_40(hw, GLV_GORCH(idx), GLV_GORCL(idx),
vsi->offset_loaded, &oes->rx_bytes,
&nes->rx_bytes);
@@ -6483,8 +6492,6 @@ ice_update_vsi_stats(struct ice_vsi *vsi)
nes->rx_bytes -= (nes->rx_unicast + nes->rx_multicast +
nes->rx_broadcast) * RTE_ETHER_CRC_LEN;
- ice_stat_update_32(hw, GLV_RDPC(idx), vsi->offset_loaded,
- &oes->rx_discards, &nes->rx_discards);
/* GLV_REPC not supported */
/* GLV_RMPC not supported */
ice_stat_update_32(hw, GLSWID_RUPP(idx), vsi->offset_loaded,
--
2.43.0
^ permalink raw reply related
* [PATCH 0/3] net/intel: fix potential rx stats underflow
From: Ciara Loftus @ 2026-06-25 9:36 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus
The Rx packet count reported by ice, ice DCF and iavf can momentarily
jump to an enormous invalid value under load. ipackets is derived by
subtracting the discarded packet count from the sum of the unicast,
multicast and broadcast counters. That sum already includes the
discarded packets, so the result is the number actually delivered. The
inputs are sampled from separate sources at slightly different instants,
so the discard count can briefly exceed the measured sum. Because the
arithmetic is unsigned, the subtraction wraps to a huge value and is
reported as a hugely incorrect packet count and rate.
All three share the bug but not the fix, because they differ in how
much control they have over the sampling.
The ice PF reads its counters directly from hardware registers, so the
order is under the driver's control. Reading the discard register before
the other three, combined with the fact that the counters only ever
increase and the delivered-packet sum always includes the discards,
makes it impossible for the discard count to exceed the later sum. No
clamping is needed and the subtraction can never underflow.
ice DCF and iavf receive their counters from the PF in a single virtchnl
message and cannot influence the order in which the PF sampled them.
There a reorder is not available, so the subtraction is made saturating:
when the discard count exceeds the sum, essentially nothing was delivered,
so zero is reported instead of underflowing.
Ciara Loftus (3):
net/ice: fix Rx packets statistics underflow
net/ice: fix DCF Rx packets statistics underflow
net/iavf: fix Rx packets statistics underflow
drivers/net/intel/iavf/iavf_ethdev.c | 12 ++++++++++--
drivers/net/intel/ice/ice_dcf_ethdev.c | 12 ++++++++++--
drivers/net/intel/ice/ice_ethdev.c | 11 +++++++++--
3 files changed, 29 insertions(+), 6 deletions(-)
--
2.43.0
^ permalink raw reply
* RE: [PATCH v2 4/4] ethdev: fix promoted flow metadata symbols
From: Dariusz Sosnowski @ 2026-06-25 9:22 UTC (permalink / raw)
To: David Marchand
Cc: Bruce Richardson, NBU-Contact-Thomas Monjalon (EXTERNAL),
Andrew Rybchenko, Ori Kam, dev@dpdk.org, Yu Jiang
In-Reply-To: <CAJFAV8wZhj+WRGY5sWYQSHFHA_7XNhCNS7Hqf5xSzAEt3U6z+Q@mail.gmail.com>
> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Thursday, June 25, 2026 9:45 AM
> To: Dariusz Sosnowski <dsosnowski@nvidia.com>
> Cc: Bruce Richardson <bruce.richardson@intel.com>; NBU-Contact-Thomas
> Monjalon (EXTERNAL) <thomas@monjalon.net>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ori Kam <orika@nvidia.com>;
> dev@dpdk.org; Yu Jiang <yux.jiang@intel.com>
> Subject: Re: [PATCH v2 4/4] ethdev: fix promoted flow metadata symbols
>
> External email: Use caution opening links or attachments
>
>
> On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com>
> wrote:
> >
> > Offending commit stabilized the following symbols related to flow
> > metadata:
> >
> > - 1 function symbol:
> > - rte_flow_dynf_metadata_register
> > - 2 variable symbols:
> > - rte_flow_dynf_metadata_offs
> > - rte_flow_dynf_metadata_mask
> >
> > Any application using experimental flow metadata symbols, which was
> > linked dynamically against 25.11 version of ethdev library and using
> > current version of ethdev library would fail to start on symbol lookup
> > error:
> >
> > /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
> > symbol lookup error: /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
> > undefined symbol: rte_flow_dynf_metadata_offs, version
> > EXPERIMENTAL
> >
> > This patch addresses that issue by restoring EXPERIMENTAL version on
> > the global variables to keep ABI compatibility [1].
> > Related inline helpers and variable declarations are kept as stable
> > (i.e., no __rte_experimental marker).
> > EXPERIMENTAL version will be removed from these global variables in
> > 26.11 release cycle on next ABI version bump.
> >
> > Standard function symbol versioning is also applied on
> > rte_flow_dynf_metadata_register() function.
> >
> > [1]:
> > https://inbox.dpdk.org/dev/m7s3jl2566kibbapr2mfa2ic2opuc6b4ok2g67j3il5
> > dgduzih@cz5wcdstb75n/
> >
> > Bugzilla ID: 1957
> > Fixes: 4ee2f5c1cedf ("ethdev: promote flow metadata API to stable")
> >
> > Reported-by: Yu Jiang <yux.jiang@intel.com>
> > Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>
> Acked-by: David Marchand <david.marchand@redhat.com>
>
> Once this series is merged, could you send a patch against 26.11 dropping this
> compat and marking the variables as stable?
> I'll mark it as deferred in patchwork, this is just to have a reminder to clean this
> up.
Of course, I'll send it once merged.
Best regards,
Dariusz Sosnowski
^ permalink raw reply
* Re: [PATCH v2 4/4] ethdev: fix promoted flow metadata symbols
From: David Marchand @ 2026-06-25 7:44 UTC (permalink / raw)
To: Dariusz Sosnowski
Cc: Bruce Richardson, Thomas Monjalon, Andrew Rybchenko, Ori Kam, dev,
Yu Jiang
In-Reply-To: <20260624131337.1127323-5-dsosnowski@nvidia.com>
On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Offending commit stabilized the following symbols
> related to flow metadata:
>
> - 1 function symbol:
> - rte_flow_dynf_metadata_register
> - 2 variable symbols:
> - rte_flow_dynf_metadata_offs
> - rte_flow_dynf_metadata_mask
>
> Any application using experimental flow metadata symbols,
> which was linked dynamically against 25.11 version of ethdev
> library and using current version of ethdev library
> would fail to start on symbol lookup error:
>
> /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
> symbol lookup error: /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
> undefined symbol: rte_flow_dynf_metadata_offs, version EXPERIMENTAL
>
> This patch addresses that issue by restoring EXPERIMENTAL version
> on the global variables to keep ABI compatibility [1].
> Related inline helpers and variable declarations are kept as stable
> (i.e., no __rte_experimental marker).
> EXPERIMENTAL version will be removed from these global variables
> in 26.11 release cycle on next ABI version bump.
>
> Standard function symbol versioning is also applied on
> rte_flow_dynf_metadata_register() function.
>
> [1]: https://inbox.dpdk.org/dev/m7s3jl2566kibbapr2mfa2ic2opuc6b4ok2g67j3il5dgduzih@cz5wcdstb75n/
>
> Bugzilla ID: 1957
> Fixes: 4ee2f5c1cedf ("ethdev: promote flow metadata API to stable")
>
> Reported-by: Yu Jiang <yux.jiang@intel.com>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: David Marchand <david.marchand@redhat.com>
Once this series is merged, could you send a patch against 26.11
dropping this compat and marking the variables as stable?
I'll mark it as deferred in patchwork, this is just to have a reminder
to clean this up.
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 3/4] net/mlx5: fix stabilized function versions
From: David Marchand @ 2026-06-25 7:41 UTC (permalink / raw)
To: Dariusz Sosnowski
Cc: Bruce Richardson, Viacheslav Ovsiienko, Bing Zhao, Ori Kam,
Suanming Mou, Matan Azrad, dev, Yu Jiang
In-Reply-To: <20260624131337.1127323-4-dsosnowski@nvidia.com>
On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Offending patch stabilized the following function symbols:
>
> - rte_pmd_mlx5_driver_event_cb_register
> - rte_pmd_mlx5_driver_event_cb_unregister
> - rte_pmd_mlx5_enable_steering
> - rte_pmd_mlx5_disable_steering
>
> These function symbols were introduced in 25.11.
> Any application using these functions, linked against 25.11 version,
> would fail when used with 26.07 libraries, because only DPDK_26 versions
> of these symbols were exported.
>
> This patch fixes that by adding proper function symbol versioning
> to these symbols.
>
> Fixes: e8cab133645f ("net/mlx5: promote some private API to stable")
>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: David Marchand <david.marchand@redhat.com>
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 2/4] build: support function versioning for drivers
From: David Marchand @ 2026-06-25 7:38 UTC (permalink / raw)
To: Dariusz Sosnowski, Bruce Richardson; +Cc: dev, Yu Jiang
In-Reply-To: <20260624131337.1127323-3-dsosnowski@nvidia.com>
On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Add support for enabling function versioning
> (through use_function_versioning meson variable) for drivers,
> similar to libraries.
>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> ---
> drivers/meson.build | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/meson.build b/drivers/meson.build
> index 4d95604ecd..a63d93372a 100644
> --- a/drivers/meson.build
> +++ b/drivers/meson.build
> @@ -171,6 +171,7 @@ foreach subpath:subdirs
> pkgconfig_extra_libs = []
> testpmd_sources = []
> require_iova_in_mbuf = true
> + use_function_versioning = false
> # for handling base code files which may need extra cflags
> base_sources = []
> base_cflags = []
> @@ -273,6 +274,13 @@ foreach subpath:subdirs
> endif
> dpdk_conf.set(lib_name.to_upper(), 1)
>
> + if developer_mode and is_windows and use_function_versioning
> + message('@0@: Function versioning is not supported by Windows.'.format(name))
> + endif
> + if use_function_versioning
> + cflags += '-DRTE_USE_FUNCTION_VERSIONING'
> + endif
> +
> dpdk_extra_ldflags += pkgconfig_extra_libs
>
> dpdk_headers += headers
Don't we need to build with RTE_BUILD_SHARED_LIB for the shared library objects?
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 1/4] eal: fix macro for versioned experimental symbol
From: David Marchand @ 2026-06-25 7:34 UTC (permalink / raw)
To: Dariusz Sosnowski; +Cc: Bruce Richardson, dev, Yu Jiang
In-Reply-To: <20260624131337.1127323-2-dsosnowski@nvidia.com>
On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Add a missing semicolon after __asm__ block in
> RTE_VERSION_EXPERIMENTAL_SYMBOL macro.
> It's lack triggers the following compilation error with clang:
>
> ../lib/ethdev/rte_flow.c:320:1: error: expected ';' after top-level asm block
> 320 | RTE_VERSION_EXPERIMENTAL_SYMBOL(int, rte_flow_dynf_metadata_register, (void))
> | ^
> ../lib/eal/common/eal_export.h:75:74: note: expanded from macro 'RTE_VERSION_EXPERIMENTAL_SYMBOL'
> 75 | __asm__(".symver " RTE_STR(name) "_exp, " RTE_STR(name) "@EXPERIMENTAL") \
> | ^
> ../lib/eal/include/rte_common.h:237:20: note: expanded from macro '\
> __rte_used'
> 237 | #define __rte_used __attribute__((used))
> | ^
>
> Fixes: e30e194c4d06 ("eal: rework function versioning macros")
> Cc: david.marchand@redhat.com
>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Thank you.
Reviewed-by: David Marchand <david.marchand@redhat.com>
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2] eal: return error on devargs truncation in hotplug MP messages
From: David Marchand @ 2026-06-25 7:23 UTC (permalink / raw)
To: Long Li
Cc: dev, stable, Thomas Monjalon, Bruce Richardson, Stephen Hemminger,
Burakov, Anatoly
In-Reply-To: <20260624000531.1562655-1-longli@microsoft.com>
On Wed, 24 Jun 2026 at 02:11, Long Li <longli@microsoft.com> wrote:
>
> The EAL hotplug multi-process messaging uses a fixed-size buffer
> (EAL_DEV_MP_DEV_ARGS_MAX_LEN, 128 bytes) for device arguments.
> When devargs exceeds this limit, strlcpy silently truncates the
> string. This causes secondary processes to receive incomplete
> devargs during hotplug re-add, leading to failed port
> re-initialization.
>
> For example, a MANA PCI device with 6 mac= arguments:
>
> mac=AA:BB:CC:DD:EE:01,mac=AA:BB:CC:DD:EE:02,
> mac=AA:BB:CC:DD:EE:03,mac=AA:BB:CC:DD:EE:04,
> mac=AA:BB:CC:DD:EE:05,mac=AA:BB:CC:DD:EE:06
>
> produces a 131-byte devargs string that gets silently truncated
> to 127 bytes, losing the last MAC address.
>
> Return -E2BIG from rte_dev_probe() when devargs would be truncated,
> instead of silently corrupting data. rte_dev_remove() does not need
> the same check because the length was already validated at probe time.
>
> Fixes: 244d5130719c ("eal: enable hotplug on multi-process")
> Cc: stable@dpdk.org
>
> Signed-off-by: Long Li <longli@microsoft.com>
Re-reading the function, I have one concern about the fix.
I agree there is a bug with multiprocess.
But this change here also imposes a limit to 128 that was not there
before, even if multiprocess is disabled.
It may not be a big problem, but we are calling the the multi process
machinerie when unneeded (it ends up with a ENOTSUP).
I sent a small patch on this topic, could you have a look please?
https://inbox.dpdk.org/dev/20260625072254.4190227-1-david.marchand@redhat.com/
--
David Marchand
^ permalink raw reply
* [PATCH] dev: skip multi-process in hotplug
From: David Marchand @ 2026-06-25 7:22 UTC (permalink / raw)
To: dev; +Cc: longli
If multi-process is disabled (--no-shconf/--in-memory),
there is no need to build a multi-process message.
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
lib/eal/common/eal_common_dev.c | 46 ++++++++++++++++++++++++---------
1 file changed, 34 insertions(+), 12 deletions(-)
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 48b631532a..b0ec2b0601 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -267,10 +267,16 @@ RTE_EXPORT_SYMBOL(rte_dev_probe)
int
rte_dev_probe(const char *devargs)
{
+ const struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ bool do_mp = internal_conf->no_shconf == 0;
struct eal_dev_mp_req req;
struct rte_device *dev;
int ret;
+ if (!do_mp)
+ goto skip_mp_req;
+
memset(&req, 0, sizeof(req));
req.t = EAL_DEV_REQ_TYPE_ATTACH;
strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
@@ -294,6 +300,7 @@ rte_dev_probe(const char *devargs)
/* attach a shared device from primary start from here: */
+skip_mp_req:
/* primary attach the new device itself. */
ret = local_dev_probe(devargs, &dev);
@@ -311,6 +318,9 @@ rte_dev_probe(const char *devargs)
return ret;
}
+ if (!do_mp)
+ goto skip_mp_notify;
+
/* primary send attach sync request to secondary. */
ret = eal_dev_hotplug_request_to_secondary(&req);
@@ -337,16 +347,19 @@ rte_dev_probe(const char *devargs)
goto rollback;
}
+skip_mp_notify:
return 0;
rollback:
- req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
+ if (do_mp) {
+ req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
- /* primary send rollback request to secondary. */
- if (eal_dev_hotplug_request_to_secondary(&req) != 0)
- EAL_LOG(WARNING,
- "Failed to rollback device attach on secondary."
- "Devices in secondary may not sync with primary");
+ /* primary send rollback request to secondary. */
+ if (eal_dev_hotplug_request_to_secondary(&req) != 0)
+ EAL_LOG(WARNING,
+ "Failed to rollback device attach on secondary."
+ "Devices in secondary may not sync with primary");
+ }
/* primary rollback itself. */
if (local_dev_remove(dev) != 0)
@@ -405,6 +418,9 @@ RTE_EXPORT_SYMBOL(rte_dev_remove)
int
rte_dev_remove(struct rte_device *dev)
{
+ const struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+ bool do_mp = internal_conf->no_shconf == 0;
struct eal_dev_mp_req req;
char *devargs;
int ret;
@@ -418,6 +434,9 @@ rte_dev_remove(struct rte_device *dev)
if (ret != 0)
return ret;
+ if (!do_mp)
+ goto skip_mp_req;
+
memset(&req, 0, sizeof(req));
req.t = EAL_DEV_REQ_TYPE_DETACH;
strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
@@ -472,6 +491,7 @@ rte_dev_remove(struct rte_device *dev)
goto rollback;
}
+skip_mp_req:
/* primary detach the device itself. */
ret = local_dev_remove(dev);
@@ -488,13 +508,15 @@ rte_dev_remove(struct rte_device *dev)
return 0;
rollback:
- req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
+ if (do_mp) {
+ req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
- /* primary send rollback request to secondary. */
- if (eal_dev_hotplug_request_to_secondary(&req) != 0)
- EAL_LOG(WARNING,
- "Failed to rollback device detach on secondary."
- "Devices in secondary may not sync with primary");
+ /* primary send rollback request to secondary. */
+ if (eal_dev_hotplug_request_to_secondary(&req) != 0)
+ EAL_LOG(WARNING,
+ "Failed to rollback device detach on secondary."
+ "Devices in secondary may not sync with primary");
+ }
return ret;
}
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v7 00/23] net/sxe2: added Linkdata sxe2 ethernet driver
From: liujie5 @ 2026-06-25 6:07 UTC (permalink / raw)
To: liujie5, stephen; +Cc: dev
In-Reply-To: <20260625054108.51381-1-liujie5@linkdatatechnology.com>
[-- Attachment #1: Type: text/plain, Size: 7659 bytes --]
Hi stephen,
Please ignore v7 patch/series. I found an issue and will send a revised version (v8) shortly.
liujie5@linkdatatechnology.com
From: liujie5
Date: 2026-06-25 13:41
To: stephen
CC: dev; Jie Liu
Subject: [PATCH v7 00/23] net/sxe2: added Linkdata sxe2 ethernet driver
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch set implements core functionality for the SXE2 PMD,
including basic driver framework, data path setup, and advanced
offload features (VLAN, RSS,TM, PTP etc.).
V7:
- Add support for flow duplicate pattern.
Jie Liu (23):
net/sxe2: remove software statistics devargs
net/sxe2: add Rx framework and packet types callback
net/sxe2: support AVX512 vectorized path for Rx and Tx
net/sxe2: add AVX2 vector data path for Rx and Tx
net/sxe2: add link update callback
net/sxe2: support L2 filtering and MAC config
drivers: support RSS feature
net/sxe2: support TM hierarchy and shaping
net/sxe2: support IPsec inline protocol offload
net/sxe2: support statistics and multi-process
drivers: interrupt handling
net/sxe2: add NEON vec Rx/Tx burst functions
drivers: add support for VF representors
net/sxe2: add support for custom UDP tunnel ports
net/sxe2: support firmware version reading
net/sxe2: implement get monitor address
common/sxe2: add shared SFP module definitions
net/sxe2: support SFP module info and EEPROM access
net/sxe2: add mbuf validation in Tx debug mode
common/sxe2: add callback for memory event handling
net/sxe2: add private devargs parsing
net/sxe2: implement private dump info
net/sxe2: update sxe2 feature matrix docs
doc/guides/nics/features/sxe2.ini | 56 +
doc/guides/nics/sxe2.rst | 168 ++
drivers/common/sxe2/sxe2_common.c | 156 ++
drivers/common/sxe2/sxe2_common.h | 4 +
drivers/common/sxe2/sxe2_flow_public.h | 633 +++++++
drivers/common/sxe2/sxe2_ioctl_chnl.c | 178 +-
drivers/common/sxe2/sxe2_ioctl_chnl_func.h | 18 +
drivers/common/sxe2/sxe2_msg.h | 118 ++
drivers/net/sxe2/meson.build | 52 +
drivers/net/sxe2/sxe2_cmd_chnl.c | 1587 +++++++++++++++-
drivers/net/sxe2/sxe2_cmd_chnl.h | 139 ++
drivers/net/sxe2/sxe2_drv_cmd.h | 523 +++++-
drivers/net/sxe2/sxe2_dump.c | 287 +++
drivers/net/sxe2/sxe2_dump.h | 12 +
drivers/net/sxe2/sxe2_ethdev.c | 1485 ++++++++++++++-
drivers/net/sxe2/sxe2_ethdev.h | 111 +-
drivers/net/sxe2/sxe2_ethdev_repr.c | 609 ++++++
drivers/net/sxe2/sxe2_ethdev_repr.h | 32 +
drivers/net/sxe2/sxe2_filter.c | 895 +++++++++
drivers/net/sxe2/sxe2_filter.h | 100 +
drivers/net/sxe2/sxe2_flow.c | 1394 ++++++++++++++
drivers/net/sxe2/sxe2_flow.h | 30 +
drivers/net/sxe2/sxe2_flow_define.h | 144 ++
drivers/net/sxe2/sxe2_flow_parse_action.c | 1182 ++++++++++++
drivers/net/sxe2/sxe2_flow_parse_action.h | 23 +
drivers/net/sxe2/sxe2_flow_parse_engine.c | 106 ++
drivers/net/sxe2/sxe2_flow_parse_engine.h | 13 +
drivers/net/sxe2/sxe2_flow_parse_pattern.c | 1935 +++++++++++++++++++
drivers/net/sxe2/sxe2_flow_parse_pattern.h | 46 +
drivers/net/sxe2/sxe2_ipsec.c | 1565 ++++++++++++++++
drivers/net/sxe2/sxe2_ipsec.h | 254 +++
drivers/net/sxe2/sxe2_irq.c | 1026 ++++++++++
drivers/net/sxe2/sxe2_irq.h | 25 +
drivers/net/sxe2/sxe2_mac.c | 530 ++++++
drivers/net/sxe2/sxe2_mac.h | 84 +
drivers/net/sxe2/sxe2_mp.c | 414 +++++
drivers/net/sxe2/sxe2_mp.h | 67 +
drivers/net/sxe2/sxe2_queue.c | 17 +-
drivers/net/sxe2/sxe2_queue.h | 15 +-
drivers/net/sxe2/sxe2_rss.c | 584 ++++++
drivers/net/sxe2/sxe2_rss.h | 81 +
drivers/net/sxe2/sxe2_rx.c | 93 +-
drivers/net/sxe2/sxe2_rx.h | 2 +
drivers/net/sxe2/sxe2_security.c | 335 ++++
drivers/net/sxe2/sxe2_security.h | 77 +
drivers/net/sxe2/sxe2_stats.c | 586 ++++++
drivers/net/sxe2/sxe2_stats.h | 39 +
drivers/net/sxe2/sxe2_switchdev.c | 332 ++++
drivers/net/sxe2/sxe2_switchdev.h | 33 +
drivers/net/sxe2/sxe2_tm.c | 1151 ++++++++++++
drivers/net/sxe2/sxe2_tm.h | 76 +
drivers/net/sxe2/sxe2_tx.c | 7 +
drivers/net/sxe2/sxe2_txrx.c | 1958 +++++++++++++++++++-
drivers/net/sxe2/sxe2_txrx.h | 8 +
drivers/net/sxe2/sxe2_txrx_check_mbuf.c | 595 ++++++
drivers/net/sxe2/sxe2_txrx_check_mbuf.h | 38 +
drivers/net/sxe2/sxe2_txrx_poll.c | 284 ++-
drivers/net/sxe2/sxe2_txrx_vec.c | 46 +-
drivers/net/sxe2/sxe2_txrx_vec.h | 38 +-
drivers/net/sxe2/sxe2_txrx_vec_avx2.c | 747 ++++++++
drivers/net/sxe2/sxe2_txrx_vec_avx512.c | 867 +++++++++
drivers/net/sxe2/sxe2_txrx_vec_common.h | 54 +-
drivers/net/sxe2/sxe2_txrx_vec_neon.c | 689 +++++++
drivers/net/sxe2/sxe2_txrx_vec_sse.c | 38 +-
drivers/net/sxe2/sxe2_vsi.c | 146 ++
drivers/net/sxe2/sxe2_vsi.h | 12 +-
drivers/net/sxe2/sxe2vf_regs.h | 85 +
67 files changed, 24761 insertions(+), 273 deletions(-)
create mode 100644 drivers/common/sxe2/sxe2_flow_public.h
create mode 100644 drivers/common/sxe2/sxe2_msg.h
create mode 100644 drivers/net/sxe2/sxe2_dump.c
create mode 100644 drivers/net/sxe2/sxe2_dump.h
create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.c
create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.h
create mode 100644 drivers/net/sxe2/sxe2_filter.c
create mode 100644 drivers/net/sxe2/sxe2_filter.h
create mode 100644 drivers/net/sxe2/sxe2_flow.c
create mode 100644 drivers/net/sxe2/sxe2_flow.h
create mode 100644 drivers/net/sxe2/sxe2_flow_define.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.h
create mode 100644 drivers/net/sxe2/sxe2_ipsec.c
create mode 100644 drivers/net/sxe2/sxe2_ipsec.h
create mode 100644 drivers/net/sxe2/sxe2_irq.c
create mode 100644 drivers/net/sxe2/sxe2_mac.c
create mode 100644 drivers/net/sxe2/sxe2_mac.h
create mode 100644 drivers/net/sxe2/sxe2_mp.c
create mode 100644 drivers/net/sxe2/sxe2_mp.h
create mode 100644 drivers/net/sxe2/sxe2_rss.c
create mode 100644 drivers/net/sxe2/sxe2_rss.h
create mode 100644 drivers/net/sxe2/sxe2_security.c
create mode 100644 drivers/net/sxe2/sxe2_security.h
create mode 100644 drivers/net/sxe2/sxe2_stats.c
create mode 100644 drivers/net/sxe2/sxe2_stats.h
create mode 100644 drivers/net/sxe2/sxe2_switchdev.c
create mode 100644 drivers/net/sxe2/sxe2_switchdev.h
create mode 100644 drivers/net/sxe2/sxe2_tm.c
create mode 100644 drivers/net/sxe2/sxe2_tm.h
create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.h
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx2.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx512.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_neon.c
create mode 100644 drivers/net/sxe2/sxe2vf_regs.h
--
2.52.0
[-- Attachment #2: Type: text/html, Size: 14762 bytes --]
^ permalink raw reply
* RE: [PATCH v3 0/2] Extend NUMA nodes limit
From: Liangxing Wang @ 2026-06-25 6:01 UTC (permalink / raw)
To: thomas@monjalon.net; +Cc: dev@dpdk.org, fengchengwen
In-Reply-To: <ac35b365-8efe-4930-99ee-1d68a92cc972@huawei.com>
Hi Thomas,
Friendly ping for review/upstream, thanks.
Regards,
Liangxing
> -----Original Message-----
> From: Liangxing Wang
> Sent: 2026年3月23日 18:01
> To: 'fengchengwen' <fengchengwen@huawei.com>; thomas@monjalon.net
> Cc: dev@dpdk.org
> Subject: RE: [PATCH v3 0/2] Extend NUMA nodes limit
>
> Hi Thomas,
>
> Friendly ping for review/upstream.
>
> Regards,
> Liangxing
>
> > -----Original Message-----
> > From: fengchengwen <fengchengwen@huawei.com>
> > Sent: 2026年2月26日 10:11
> > To: Liangxing Wang <wangliangxing@hygon.cn>; thomas@monjalon.net;
> > stephen@networkplumber.org
> > Cc: dev@dpdk.org
> > Subject: Re: [PATCH v3 0/2] Extend NUMA nodes limit
> >
> > Series-acked-by: Chengwen Feng <fengchengwen@huawei.com>
> >
> > On 2/25/2026 4:04 PM, Liangxing Wang wrote:
> > > This patchset use RTE_MAX_NUMA_NODES instead of hardcoded values to
> > > extend NUMA nodes limit for some examples and test app. Also remove
> > > unused NB_SOCKETS macro for ip_reassembly example and graph app.
> > >
> > > Liangxing Wang (2):
> > > examples: extend NUMA nodes limit
> > > app: extend NUMA nodes limit
> > >
> > > app/graph/ethdev_rx_priv.h | 1 -
> > > app/test/test_pmd_perf.c | 2 +-
> > > examples/ip_reassembly/main.c | 2 --
> > > examples/ipsec-secgw/ipsec-secgw.h | 2 +-
> > > examples/l3fwd-graph/main.c | 2 +-
> > > examples/l3fwd-power/main.c | 2 +-
> > > examples/l3fwd/l3fwd.h | 2 +-
> > > examples/vhost_crypto/main.c | 2 +-
> > > 8 files changed, 6 insertions(+), 9 deletions(-)
> > >
> >
^ permalink raw reply
* [PATCH v7 16/23] net/sxe2: implement get monitor address
From: liujie5 @ 2026-06-25 5:56 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260624020249.3687380-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch implements the 'get_monitor_addr' ethdev ops in the sxe2
PMD. This interface allows the Ethernet device to provide the
address of the next expected Rx descriptor to the power management
library.
The implementation calculates the address of the next Rx descriptor
based on the receive queue's current hardware ring position and
descriptor size. Applications can then use this address with
rte_power_monitor() to put the CPU into a low-power state until
new packets are written to the descriptor by the hardware.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/sxe2_ethdev.c | 2 ++
drivers/net/sxe2/sxe2_rx.c | 21 +++++++++++++++++++++
drivers/net/sxe2/sxe2_rx.h | 2 ++
3 files changed, 25 insertions(+)
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 02ff6be322..d6efab239c 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -183,6 +183,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.queue_stats_mapping_set = sxe2_queue_stats_mapping_set,
.fw_version_get = sxe2_fw_version_string_get,
+
+ .get_monitor_addr = sxe2_get_monitor_addr,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
diff --git a/drivers/net/sxe2/sxe2_rx.c b/drivers/net/sxe2/sxe2_rx.c
index 2495ab3ab7..820d4f0620 100644
--- a/drivers/net/sxe2/sxe2_rx.c
+++ b/drivers/net/sxe2/sxe2_rx.c
@@ -534,3 +534,24 @@ void __rte_cold sxe2_rxqs_all_stop(struct rte_eth_dev *dev)
}
}
}
+
+static int32_t sxe2_monitor_callback(const uint64_t value,
+ const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused)
+{
+ const uint64_t dd_state = rte_cpu_to_le_64(SXE2_RX_DESC_STATUS_DD_MASK);
+ return (value & dd_state) == dd_state ? -1 : 0;
+}
+
+int32_t sxe2_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
+{
+ volatile union sxe2_rx_desc *rxdp;
+ struct sxe2_rx_queue *rxq = (struct sxe2_rx_queue *)rx_queue;
+
+ rxdp = &rxq->desc_ring[rxq->processing_idx];
+
+ pmc->addr = &rxdp->wb.status_err_ptype_len;
+ pmc->fn = sxe2_monitor_callback;
+ pmc->size = sizeof(uint16_t);
+
+ return 0;
+}
diff --git a/drivers/net/sxe2/sxe2_rx.h b/drivers/net/sxe2/sxe2_rx.h
index 295d9005e0..c2582bc571 100644
--- a/drivers/net/sxe2/sxe2_rx.h
+++ b/drivers/net/sxe2/sxe2_rx.h
@@ -29,4 +29,6 @@ int32_t __rte_cold sxe2_rxqs_all_start(struct rte_eth_dev *dev);
void __rte_cold sxe2_rxqs_all_stop(struct rte_eth_dev *dev);
+int32_t sxe2_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
+
#endif /* SXE2_RX_H */
--
2.52.0
^ permalink raw reply related
* [PATCH v7 15/23] net/sxe2: support firmware version reading
From: liujie5 @ 2026-06-25 5:55 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260624020249.3687380-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch implements the logic to retrieve the firmware version and
Build ID from the hardware during device initialization.
The version is exposed to applications through the dev_info_get API.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/sxe2_ethdev.c | 35 +++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 9bff741961..02ff6be322 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -119,7 +119,8 @@ static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *tunnel_udp);
static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *tunnel_udp);
-
+static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev,
+ char *fw_version, size_t fw_size);
static const struct eth_dev_ops sxe2_eth_dev_ops = {
.dev_configure = sxe2_dev_configure,
@@ -180,6 +181,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.xstats_reset = sxe2_stats_info_reset,
.queue_stats_mapping_set = sxe2_queue_stats_mapping_set,
+
+ .fw_version_get = sxe2_fw_version_string_get,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -1556,6 +1559,36 @@ static int32_t sxe2_eth_pmd_remove(struct sxe2_common_device *cdev)
return ret;
}
+static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size)
+{
+ struct sxe2_adapter *adapter =
+ SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_fw_info *fw_info = &adapter->dev_info.fw;
+ int32_t ret_len;
+ int32_t ret;
+
+ ret_len = snprintf(fw_version, fw_size,
+ "%u.%u.%u.%u",
+ fw_info->main_version_id,
+ fw_info->sub_version_id,
+ fw_info->fix_version_id,
+ fw_info->build_id);
+
+ if (ret_len < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret_len += 1;
+ if (fw_size < (size_t)ret_len)
+ ret = -EINVAL;
+ else
+ ret = 0;
+
+out:
+ return ret;
+}
+
static uint16_t sxe2_switchdev_repr_id_encode_get(struct sxe2_switchdev_info *switchdev_info)
{
enum rte_eth_representor_type type;
--
2.52.0
^ permalink raw reply related
* [PATCH v7 14/23] net/sxe2: add support for custom UDP tunnel ports
From: liujie5 @ 2026-06-25 5:55 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260624020249.3687380-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch enables the configuration of custom UDP port numbers for
tunneling protocols in the SXE2 PMD.
The change includes:
- Adding a new entry in the tunnel port lookup table.
- Updating the hardware profile to recognize
the custom UDP port as a tunnel type.
- Enabling inner header parsing for packets arriving on these ports.
This allows the Switch module to correctly apply recipes based on
inner packet fields (e.g., inner MAC or IP).
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/sxe2_cmd_chnl.c | 96 ++++++++++
drivers/net/sxe2/sxe2_cmd_chnl.h | 17 ++
drivers/net/sxe2/sxe2_drv_cmd.h | 16 ++
drivers/net/sxe2/sxe2_ethdev.c | 200 ++++++++++++++++++++-
drivers/net/sxe2/sxe2_ethdev.h | 9 +
drivers/net/sxe2/sxe2_flow.c | 54 ++++++
drivers/net/sxe2/sxe2_flow.h | 3 +-
drivers/net/sxe2/sxe2_flow_define.h | 1 +
drivers/net/sxe2/sxe2_flow_parse_pattern.c | 113 ++++++++++++
drivers/net/sxe2/sxe2_flow_parse_pattern.h | 6 +
drivers/net/sxe2/sxe2_txrx_poll.c | 46 ++++-
11 files changed, 557 insertions(+), 4 deletions(-)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 6e2dd139a5..926eaee062 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -1455,6 +1455,102 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
return ret;
}
+int32_t sxe2_drv_udp_tunnel_add(struct sxe2_adapter *adapter,
+ enum sxe2_udp_tunnel_protocol tunnel_proto,
+ uint16_t udp_port)
+{
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_udp_tunnel_req req = {};
+ struct sxe2_drv_cmd_params cmd = {};
+ int32_t ret = -1;
+
+ req.type = tunnel_proto;
+ req.port = udp_port;
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_ADD,
+ &req, sizeof(req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to add udp proto %d port %d, ret=%d",
+ tunnel_proto, udp_port, ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_udp_tunnel_del(struct sxe2_adapter *adapter,
+ enum sxe2_udp_tunnel_protocol tunnel_proto,
+ uint16_t udp_port)
+{
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_udp_tunnel_req req = {};
+ struct sxe2_drv_cmd_params cmd = {};
+ int32_t ret = -1;
+
+ req.type = tunnel_proto;
+ req.port = udp_port;
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_DEL,
+ &req, sizeof(req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to del udp proto %d port %d, ret=%d",
+ tunnel_proto, udp_port, ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_get_udp_tunnel_port(struct sxe2_adapter *adapter,
+ enum sxe2_flow_udp_tunnel_protocol proto,
+ uint16_t *port)
+{
+ int32_t ret = 0;
+ static const uint16_t flow_proto_to_udp_tunnel_proto[SXE2_FLOW_UDP_TUNNEL_MAX] = {
+ [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN,
+ [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+ [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE] = SXE2_UDP_TUNNEL_PROTOCOL_GENEVE,
+ [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U] = SXE2_UDP_TUNNEL_PROTOCOL_GTP_U,
+ [SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE] = SXE2_UDP_TUNNEL_PROTOCOL_NVGRE,
+ };
+ struct sxe2_udp_tunnel_cfg tunnel_config = {};
+
+ tunnel_config.protocol = flow_proto_to_udp_tunnel_proto[proto];
+ ret = sxe2_drv_udp_tunnel_get(adapter, &tunnel_config);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get udp tunnel port, ret=%d", ret);
+ goto l_end;
+ }
+
+ *port = tunnel_config.fw_port;
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_udp_tunnel_get(struct sxe2_adapter *adapter,
+ struct sxe2_udp_tunnel_cfg *tunnel_config)
+{
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_udp_tunnel_req req = {};
+ struct sxe2_drv_udp_tunnel_resp resp = {};
+ struct sxe2_drv_cmd_params cmd = {};
+ int32_t ret = -1;
+
+ req.type = tunnel_config->protocol;
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_UDPTUNNEL_GET,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to get udp proto %d port, ret=%d", req.type, ret);
+
+ tunnel_config->fw_port = resp.port;
+ tunnel_config->fw_status = resp.enable;
+ tunnel_config->fw_dst_en = resp.dst;
+ tunnel_config->fw_src_en = resp.src;
+ tunnel_config->fw_used = resp.fw_used;
+
+ return ret;
+}
+
int32_t sxe2_drv_queue_info_get_update(struct sxe2_adapter *adapter, struct eth_queue_stats *qstats)
{
struct sxe2_drv_cmd_params param = {0};
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 52cd9922ad..97007c7cfa 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -67,6 +67,23 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
+int32_t sxe2_drv_udp_tunnel_add(struct sxe2_adapter *adapter,
+ enum sxe2_udp_tunnel_protocol tunnel_proto,
+ uint16_t udp_port);
+
+int32_t sxe2_drv_udp_tunnel_del(struct sxe2_adapter *adapter,
+ enum sxe2_udp_tunnel_protocol tunnel_proto,
+ uint16_t udp_port);
+
+int32_t sxe2_drv_udp_tunnel_get(struct sxe2_adapter *adapter,
+ struct sxe2_udp_tunnel_cfg *tunnel_config);
+
+int32_t sxe2_drv_get_udp_tunnel_port(struct sxe2_adapter *adapter,
+ enum sxe2_flow_udp_tunnel_protocol proto,
+ uint16_t *port);
+
+int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi);
+
int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi);
int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index dba4e85789..3e0b70ab02 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -617,6 +617,22 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_query_stat_resp {
uint64_t stat_bytes;
} __rte_packed_end;
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_udp_tunnel_req {
+ uint8_t type;
+ uint8_t rsv;
+ uint16_t port;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_udp_tunnel_resp {
+ uint8_t type;
+ uint8_t enable;
+ uint8_t dst;
+ uint8_t src;
+ uint16_t port;
+ uint8_t fw_used;
+ uint8_t rsv;
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 389bbdab51..9bff741961 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -39,10 +39,11 @@
#include "sxe2_ioctl_chnl_func.h"
#include "sxe2_ethdev_repr.h"
#include "sxe2vf_regs.h"
+#include "sxe2_switchdev.h"
#define SXE2_PCI_VENDOR_ID_1 0x1ff2
#define SXE2_PCI_DEVICE_ID_PF_1 0x10b1
-#define SXE2_PCI_DEVICE_ID_VF_1 0x10b2
+#define SXE2_PCI_DEVICE_ID_VF_1 0x10b
#define SXE2_PCI_VENDOR_ID_2 0x1d94
#define SXE2_PCI_DEVICE_ID_PF_2 0x1260
@@ -114,6 +115,11 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev);
static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info);
static const uint32_t *sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev
__rte_unused, size_t *no_of_elements __rte_unused);
+static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
+ struct rte_eth_udp_tunnel *tunnel_udp);
+static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
+ struct rte_eth_udp_tunnel *tunnel_udp);
+
static const struct eth_dev_ops sxe2_eth_dev_ops = {
.dev_configure = sxe2_dev_configure,
@@ -161,6 +167,9 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.rss_hash_update = sxe2_dev_rss_hash_update,
.rss_hash_conf_get = sxe2_dev_rss_hash_conf_get,
+ .udp_tunnel_port_add = sxe2_udp_tunnel_port_add,
+ .udp_tunnel_port_del = sxe2_udp_tunnel_port_del,
+
.flow_ops_get = sxe2_flow_ops_get,
.tm_ops_get = sxe2_tm_ops_get,
@@ -225,6 +234,12 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
PMD_INIT_FUNC_TRACE();
+ ret = sxe2_flow_init_udp_tunnel_port(dev);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", ret);
+ goto l_end;
+ }
+
ret = sxe2_queues_init(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to init queues.");
@@ -270,6 +285,182 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
return ret;
}
+static enum sxe2_udp_tunnel_protocol
+sxe2_udp_tunnel_type_rte_to_sxe2(enum rte_eth_tunnel_type rte_type)
+{
+ static enum sxe2_udp_tunnel_protocol sxe2_udp_proto_map[RTE_ETH_TUNNEL_TYPE_MAX] = {
+ [RTE_ETH_TUNNEL_TYPE_NONE] = SXE2_UDP_TUNNEL_MAX,
+ [RTE_ETH_TUNNEL_TYPE_VXLAN] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN,
+ [RTE_ETH_TUNNEL_TYPE_GENEVE] = SXE2_UDP_TUNNEL_PROTOCOL_GENEVE,
+ [RTE_ETH_TUNNEL_TYPE_TEREDO] = SXE2_UDP_TUNNEL_PROTOCOL_TEREDO,
+ [RTE_ETH_TUNNEL_TYPE_NVGRE] = SXE2_UDP_TUNNEL_PROTOCOL_NVGRE,
+ [RTE_ETH_TUNNEL_TYPE_IP_IN_GRE] = SXE2_UDP_TUNNEL_MAX,
+ [RTE_ETH_L2_TUNNEL_TYPE_E_TAG] = SXE2_UDP_TUNNEL_MAX,
+ [RTE_ETH_TUNNEL_TYPE_VXLAN_GPE] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE,
+ [RTE_ETH_TUNNEL_TYPE_ECPRI] = SXE2_UDP_TUNNEL_PROTOCOL_ECPRI
+ };
+
+ if (rte_type >= RTE_ETH_TUNNEL_TYPE_MAX) {
+ PMD_LOG_ERR(DRV, "Invalid rte_eth_tunnel_type %d!", rte_type);
+ rte_type = RTE_ETH_TUNNEL_TYPE_NONE;
+ }
+
+ return sxe2_udp_proto_map[rte_type];
+}
+
+int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad,
+ enum sxe2_udp_tunnel_protocol tunnel_proto,
+ uint16_t udp_port)
+{
+ struct sxe2_udp_tunnel_cfg *tunnel_config;
+ int32_t ret = -1;
+
+ rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+
+ tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+
+ if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) {
+ if (udp_port == tunnel_config->dev_port &&
+ tunnel_config->dev_ref_cnt < 0xFFFFU) {
+ tunnel_config->dev_ref_cnt++;
+ ret = 0;
+ goto l_unlock_end;
+ } else {
+ PMD_LOG_ERR(DRV, "Adding multiple ports to the same protocol "
+ "is not supported!");
+ ret = -EINVAL;
+ goto l_unlock_end;
+ }
+ } else {
+ ret = sxe2_drv_udp_tunnel_add(ad, tunnel_proto, udp_port);
+ if (ret != 0)
+ goto l_unlock_end;
+
+ tunnel_config->protocol = tunnel_proto;
+ tunnel_config->dev_port = udp_port;
+ tunnel_config->dev_status = SXE2_UDP_TUNNEL_ENABLE;
+ tunnel_config->dev_ref_cnt++;
+ }
+
+l_unlock_end:
+ rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+ return ret;
+}
+
+int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad,
+ enum sxe2_udp_tunnel_protocol tunnel_proto,
+ uint16_t udp_port)
+{
+ struct sxe2_udp_tunnel_cfg *tunnel_config;
+ int32_t ret = -1;
+
+ rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+ tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+
+ if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE &&
+ udp_port == tunnel_config->dev_port) {
+ if (tunnel_config->dev_ref_cnt > 1) {
+ tunnel_config->dev_ref_cnt--;
+ ret = 0;
+ goto l_unlock_end;
+ } else {
+ ret = sxe2_drv_udp_tunnel_del(ad, tunnel_proto, udp_port);
+ if (ret != 0)
+ goto l_unlock_end;
+
+ tunnel_config->dev_status = SXE2_UDP_TUNNEL_DISABLE;
+ tunnel_config->dev_ref_cnt = 0;
+ }
+ goto l_unlock_end;
+ }
+
+ ret = -EINVAL;
+
+l_unlock_end:
+ rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+ return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_clear(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_udp_tunnel_cfg *tunnel_config;
+ int32_t ret = 0;
+ uint16_t tunnel_proto = 0;
+
+ rte_spinlock_lock(&ad->udp_tunnel_ctx.lock);
+
+ for (tunnel_proto = 0; tunnel_proto < SXE2_UDP_TUNNEL_MAX; tunnel_proto++) {
+ tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto];
+ if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) {
+ ret = sxe2_drv_udp_tunnel_del(ad, tunnel_config->protocol,
+ tunnel_config->dev_port);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to delete udp tunnel port %d, proto %d",
+ tunnel_config->dev_port, tunnel_config->protocol);
+ goto l_unlock_end;
+ }
+
+ tunnel_config->dev_status = SXE2_UDP_TUNNEL_DISABLE;
+ tunnel_config->dev_ref_cnt = 0;
+ }
+ }
+l_unlock_end:
+ rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock);
+ return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
+ struct rte_eth_udp_tunnel *tunnel_udp)
+{
+ int32_t ret = 0;
+ enum sxe2_udp_tunnel_protocol tunnel_proto;
+ struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (tunnel_udp->udp_port == 0) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type);
+ if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_udp_tunnel_port_add_common(ad, tunnel_proto, tunnel_udp->udp_port);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Add tunnel port failed, ret = %d", ret);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
+ struct rte_eth_udp_tunnel *tunnel_udp)
+{
+ int32_t ret = 0;
+ enum sxe2_udp_tunnel_protocol tunnel_proto;
+ struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type);
+ if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_udp_tunnel_port_del_common(ad, tunnel_proto, tunnel_udp->udp_port);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Delete tunnel port failed, ret = %d", ret);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info)
{
@@ -1287,15 +1478,20 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
(void)sxe2_dev_stop(dev);
(void)sxe2_queues_release(dev);
sxe2_mp_uninit(dev);
- (void)sxe2_rss_disable(dev);
(void)sxe2_sched_uinit(dev);
+ (void)sxe2_rss_disable(dev);
+ (void)sxe2_flow_uninit(dev);
+ (void)sxe2_udp_tunnel_port_clear(dev);
sxe2_vsi_uninit(dev);
sxe2_security_uinit(dev);
sxe2_intr_uninit(dev);
(void)sxe2_switchdev_uninit(dev);
sxe2_sw_uninit(dev);
+ (void)sxe2_switchdev_uninit(dev);
+ sxe2_dev_pci_map_uinit(dev);
sxe2_eth_uinit(dev);
sxe2_dev_pci_map_uinit(dev);
+ sxe2_free_repr_info(dev);
l_end:
return 0;
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 06adbf448f..0c7fc56ec5 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -318,6 +318,7 @@ struct sxe2_adapter {
struct sxe2_sched_hw_cap sched_ctxt;
struct sxe2_tm_context tm_ctxt;
struct sxe2_devargs devargs;
+ struct sxe2_udp_tunnel_ctx udp_tunnel_ctx;
struct sxe2_security_ctx security_ctx;
struct sxe2_repr_context repr_ctxt;
struct sxe2_switchdev_info switchdev_info;
@@ -369,6 +370,14 @@ void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
+void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
+
+int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad,
+ enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port);
+
+int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad,
+ enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port);
+
void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
void sxe2_eth_uinit(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_flow.c b/drivers/net/sxe2/sxe2_flow.c
index 6999cb0725..63cfc36968 100644
--- a/drivers/net/sxe2/sxe2_flow.c
+++ b/drivers/net/sxe2/sxe2_flow.c
@@ -523,6 +523,51 @@ static int32_t sxe2_flow_adjust_action(struct rte_eth_dev *dev __rte_unused,
return ret;
}
+int32_t sxe2_flow_init_udp_tunnel_port(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ uint16_t i = 0;
+ uint16_t *flow_udp_tunnel_port = NULL;
+
+ memset(adapter->flow_ctxt.tunnel_port_list, 0,
+ sizeof(adapter->flow_ctxt.tunnel_port_list));
+
+ flow_udp_tunnel_port = adapter->flow_ctxt.tunnel_port_list;
+ for (i = 0; i < SXE2_FLOW_UDP_TUNNEL_MAX; i++) {
+ if (flow_udp_tunnel_port[i] == 0) {
+ ret = sxe2_drv_get_udp_tunnel_port(adapter, i,
+ &flow_udp_tunnel_port[i]);
+ if (ret != 0) {
+ PMD_LOG_ERR(DRV, "Failed to get udp tunnel port, proto: %d,"
+ "ret: %d", i, ret);
+ goto l_end;
+ }
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flowlist_add_tunnel_port(struct rte_eth_dev *dev,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+ enum sxe2_flow_tunnel_type tunnel_type = flow->meta.tunnel_type;
+ DECLARE_BITMAP(flow_type, SXE2_EXPANSION_MAX);
+ sxe2_bitmap_zero(flow_type, SXE2_EXPANSION_MAX);
+ sxe2_bitmap_copy(flow_type, flow->flow_type, SXE2_EXPANSION_MAX);
+ int32_t ret = 0;
+
+ if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV)
+ return sxe2_flow_add_tunnel_port(dev, error, flow, flow_type, tunnel_type);
+
+ return ret;
+}
+
static int32_t sxe2_flow_check_item_empty(uint8_t *item, uint16_t size)
{
uint16_t i = 0;
@@ -679,6 +724,10 @@ static int32_t sxe2_flow_post_proc(struct rte_eth_dev *dev,
{
int32_t ret = 0;
+ ret = sxe2_flowlist_add_tunnel_port(dev, flow_list, error);
+ if (ret)
+ goto l_end;
+
ret = sxe2_flowlist_add_proto_type(dev, flow_list, error);
if (ret)
goto l_end;
@@ -1308,6 +1357,11 @@ int32_t sxe2_flow_init(struct rte_eth_dev *dev)
adapter->flow_ctxt.fnav_inited = 1;
rte_spinlock_init(&adapter->flow_ctxt.flow_list_lock);
+
+ ret = sxe2_flow_init_udp_tunnel_port(dev);
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", ret);
+
return ret;
}
diff --git a/drivers/net/sxe2/sxe2_flow.h b/drivers/net/sxe2/sxe2_flow.h
index 9970fddcf0..daaeedd4dc 100644
--- a/drivers/net/sxe2/sxe2_flow.h
+++ b/drivers/net/sxe2/sxe2_flow.h
@@ -8,7 +8,6 @@
#include "sxe2_osal.h"
#include "sxe2_common.h"
-
int32_t sxe2_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops);
int32_t sxe2_flow_init(struct rte_eth_dev *dev);
@@ -26,4 +25,6 @@ int32_t sxe2_flow_query_mgr(struct sxe2_adapter *adapter,
struct sxe2_flow *flow,
struct sxe2_fnav_cid_mgr **mgr_ptr,
struct rte_flow_error *error);
+
+int32_t sxe2_flow_init_udp_tunnel_port(struct rte_eth_dev *dev);
#endif /* __SXE2_FLOW_H__ */
diff --git a/drivers/net/sxe2/sxe2_flow_define.h b/drivers/net/sxe2/sxe2_flow_define.h
index d2f6000efa..263a573f04 100644
--- a/drivers/net/sxe2/sxe2_flow_define.h
+++ b/drivers/net/sxe2/sxe2_flow_define.h
@@ -119,6 +119,7 @@ struct sxe2_flow_context {
struct rte_flow_list_t rte_flow_list;
rte_spinlock_t flow_list_lock;
struct sxe2_fnav_count_resource hw_res;
+ uint16_t tunnel_port_list[SXE2_FLOW_UDP_TUNNEL_MAX];
uint32_t fnav_inited;
};
#define SXE2_INVALID_RSS_ATTR \
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.c b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
index 189abb1a33..f5bf8922c6 100644
--- a/drivers/net/sxe2/sxe2_flow_parse_pattern.c
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
@@ -1637,6 +1637,119 @@ static int32_t sxe2_flow_parse_pattern_vxlan_gpe(const struct rte_flow_item *ite
return ret;
}
+static int32_t sxe2_flow_parse_pattern_ipip(struct sxe2_flow *flow, BITMAP_TYPE *flow_type)
+{
+ sxe2_set_bit(SXE2_EXPANSION_IPIP, flow_type);
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow_type)) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, flow->pattern_outer.map_spec);
+ if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type))
+ flow->pattern_outer.item_spec.ipv4.protocol = SXE2_FLOW_IP_PROTOCOL_IPV4;
+ if (sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type))
+ flow->pattern_outer.item_spec.ipv4.protocol = SXE2_FLOW_IP_PROTOCOL_IPV6;
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow_type)) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, flow->pattern_outer.map_spec);
+ if (sxe2_test_bit(SXE2_EXPANSION_ETH, flow_type)) {
+ flow->pattern_outer.item_spec.ipv6.nexthdr = SXE2_FLOW_IP_PROTOCOL_ETH;
+ } else {
+ if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type))
+ flow->pattern_outer.item_spec.ipv6.nexthdr =
+ SXE2_FLOW_IP_PROTOCOL_IPV4;
+ if (sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type))
+ flow->pattern_outer.item_spec.ipv6.nexthdr =
+ SXE2_FLOW_IP_PROTOCOL_IPV6;
+ }
+ }
+ return 0;
+}
+
+static int32_t sxe2_flow_add_udp_tunnel_port(struct sxe2_adapter *adapter,
+ enum sxe2_flow_udp_tunnel_protocol proto,
+ struct sxe2_flow *flow,
+ BITMAP_TYPE *flow_type)
+{
+ int32_t ret = 0;
+ uint16_t tun_port;
+
+ tun_port = adapter->flow_ctxt.tunnel_port_list[proto];
+ if (tun_port == 0xffff || tun_port == 0) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(DRV, "UDP tunnel port not initialized, proto: %d", proto);
+ goto l_end;
+ }
+ if (!sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type)) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(DRV, "UDP must be over tunnel");
+ goto l_end;
+ }
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, flow->pattern_outer.map_spec);
+ flow->pattern_outer.item_spec.udp.dest = rte_cpu_to_be_16(tun_port);
+l_end:
+ return ret;
+}
+
+int32_t sxe2_flow_add_tunnel_port(struct rte_eth_dev *dev,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow, BITMAP_TYPE *flow_type,
+ enum sxe2_flow_tunnel_type tunnel_type)
+{
+ int32_t ret = 0;
+ enum sxe2_flow_udp_tunnel_protocol proto = SXE2_FLOW_UDP_TUNNEL_MAX;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_flow_pattern *pattern = &flow->pattern_outer;
+ switch (tunnel_type) {
+ case SXE2_FLOW_TUNNEL_TYPE_VXLAN:
+ if (sxe2_test_bit(SXE2_EXPANSION_ETH, flow_type)) {
+ proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN;
+ } else if (sxe2_test_bit(SXE2_EXPANSION_IPV4, flow_type) ||
+ sxe2_test_bit(SXE2_EXPANSION_IPV6, flow_type)) {
+ proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_VXLAN_GPE;
+ }
+ break;
+ case SXE2_FLOW_TUNNEL_TYPE_GTPU:
+ proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GTP_U;
+ break;
+ case SXE2_FLOW_TUNNEL_TYPE_GENEVE:
+ proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_GENEVE;
+ break;
+ case SXE2_FLOW_TUNNEL_TYPE_GRE:
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type)) {
+ proto = SXE2_FLOW_UDP_TUNNEL_PROTOCOL_NVGRE;
+ } else {
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow_type)) {
+ pattern->item_spec.ipv4.protocol = SXE2_FLOW_IP_PROTOCOL_GRE;
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_spec);
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow_type)) {
+ pattern->item_spec.ipv6.nexthdr = SXE2_FLOW_IP_PROTOCOL_GRE;
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, pattern->map_spec);
+ }
+ }
+ break;
+ case SXE2_FLOW_TUNNEL_TYPE_IPIP:
+ ret = sxe2_flow_parse_pattern_ipip(flow, flow_type);
+ break;
+ default:
+ break;
+ }
+ if (proto != SXE2_FLOW_UDP_TUNNEL_MAX) {
+ ret = sxe2_flow_add_udp_tunnel_port(adapter, proto, flow, flow_type);
+ if (ret != 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ NULL, "Failed to add udp port for tunnel.");
+ PMD_LOG_ERR(DRV, "Failed to add udp port for tunnel, ret %d.", ret);
+ goto l_end;
+ }
+ }
+ if (tunnel_type != SXE2_FLOW_TUNNEL_TYPE_NONE) {
+ if (!sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow_type))
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, pattern->hdrs);
+ }
+l_end:
+ return ret;
+}
+
struct sxe2_flow_parse_pattern_ops sxe2_flow_parse_pattern_list[] = {
[SXE2_EXPANSION_OUTER_ETH] = {
.is_inner = false,
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.h b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
index 69d83a6ea6..8442c35cae 100644
--- a/drivers/net/sxe2/sxe2_flow_parse_pattern.h
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
@@ -37,4 +37,10 @@ int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev,
struct rte_flow_error *error,
struct sxe2_flow *flow);
+int32_t sxe2_flow_add_tunnel_port(struct rte_eth_dev *dev,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ BITMAP_TYPE *flow_type,
+ enum sxe2_flow_tunnel_type tunnel_type);
+
#endif /* SXE2_FLOW_PARSE_PATTERN_H_ */
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index a662bb4375..21925f1cd4 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -234,6 +234,44 @@ sxe2_tx_pkt_data_desc_count(struct rte_mbuf *tx_pkt)
return count;
}
+static __rte_always_inline void sxe2_tx_desc_tunneling_params_fill(uint64_t offloads,
+ union sxe2_tx_offload_info ol_info,
+ uint32_t *desc_tunneling_params)
+{
+ if (offloads & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV4;
+ else if (offloads & RTE_MBUF_F_TX_OUTER_IPV4)
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV4_NO_CSUM;
+ else if (offloads & RTE_MBUF_F_TX_OUTER_IPV6)
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_EIPT_IPV6;
+
+ *desc_tunneling_params |=
+ SXE2_TX_CTXT_DESC_EIPLEN_VAL(ol_info.outer_l3_len);
+ switch (offloads & RTE_MBUF_F_TX_TUNNEL_MASK) {
+ case RTE_MBUF_F_TX_TUNNEL_IPIP:
+ break;
+ case RTE_MBUF_F_TX_TUNNEL_VXLAN:
+ case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+ case RTE_MBUF_F_TX_TUNNEL_GTP:
+ case RTE_MBUF_F_TX_TUNNEL_GENEVE:
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_UDP_TUNNE;
+ break;
+ case RTE_MBUF_F_TX_TUNNEL_GRE:
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_GRE_TUNNE;
+ break;
+ default:
+ PMD_LOG_ERR(TX, "Tunnel type [0x%" PRIx64 "] is not supported.",
+ (uint64_t)(offloads & RTE_MBUF_F_TX_TUNNEL_MASK));
+ return;
+ }
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_NATLEN_VAL(ol_info.l2_len);
+ if (!(*desc_tunneling_params & SXE2_TX_CTXT_DESC_EIPT_NONE) &&
+ (*desc_tunneling_params & SXE2_TX_CTXT_DESC_UDP_TUNNE) &&
+ (offloads & RTE_MBUF_F_TX_OUTER_UDP_CKSUM)) {
+ *desc_tunneling_params |= SXE2_TX_CTXT_DESC_L4T_CS_MASK;
+ }
+}
+
static __rte_always_inline void
sxe2_tx_desc_checksum_fill(uint64_t offloads, uint32_t *desc_cmd, uint32_t *desc_offset,
union sxe2_tx_offload_info ol_info)
@@ -414,7 +452,13 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
}
}
- desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.l2_len);
+ if ((offloads & RTE_MBUF_F_TX_TUNNEL_MASK) && ctxt_desc_num) {
+ desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.outer_l2_len);
+ sxe2_tx_desc_tunneling_params_fill(offloads, ol_info,
+ &desc_tunneling_params);
+ } else {
+ desc_offset |= SXE2_TX_DATA_DESC_MACLEN_VAL(ol_info.l2_len);
+ }
if (offloads & SXE2_TX_OFFLOAD_CKSUM_MASK) {
sxe2_tx_desc_checksum_fill(offloads, &desc_cmd,
--
2.52.0
^ permalink raw reply related
* [PATCH v7 13/23] drivers: add support for VF representors
From: liujie5 @ 2026-06-25 5:54 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260624020249.3687380-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 | 203 ++-
drivers/net/sxe2/sxe2_ethdev.h | 11 +
drivers/net/sxe2/sxe2_ethdev_repr.c | 606 +++++++
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(+), 23 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 f5ab8e9fa2..c000a55cd0 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_BUS_DEVICE(cdev->dev, *pci_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, ¶m, SXE2_DRV_CMD_DEV_GET_SWITCHDEV_INFO,
+ NULL, 0, switchdev_info,
+ sizeof(struct sxe2_switchdev_info));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ 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, ¶m, 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, ¶m, 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, ¶m);
+ 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, ¶m, SXE2_DRV_CMD_SWITCH_UPLINK,
+ &switchdev_uplink_info_req,
+ sizeof(switchdev_uplink_info_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ 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, ¶m, SXE2_DRV_CMD_SWITCH_REPR,
+ &switchdev_repr_info_req,
+ sizeof(switchdev_repr_info_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ 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, ¶m, 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, ¶m);
+ 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, ¶m, SXE2_DRV_CMD_SWITCH_CPVSI,
+ NULL, 0,
+ &switchdev_cpvsi_resp,
+ sizeof(switchdev_cpvsi_resp));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ 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, ¶m, 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, ¶m);
+ 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 d7822c6498..dba4e85789 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 89c6f28adc..389bbdab51 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -32,9 +32,13 @@
#include "sxe2_common.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
@@ -82,6 +86,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);
@@ -136,6 +161,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,
@@ -555,7 +581,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);
@@ -596,6 +622,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)
{
@@ -625,20 +661,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.primary && switchdev_info.representor) {
+ PMD_LOG_ERR(INIT, "device could not be both primary 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;
}
@@ -924,7 +987,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);
@@ -1082,7 +1148,7 @@ static int32_t sxe2_sched_uinit(struct rte_eth_dev *dev)
}
static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
- struct sxe2_dev_kvargs_info *kvargs __rte_unused)
+ __rte_unused struct sxe2_dev_kvargs_info *kvargs)
{
int32_t ret = 0;
@@ -1125,6 +1191,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);
@@ -1155,6 +1227,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);
@@ -1178,15 +1256,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:
@@ -1201,6 +1283,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);
@@ -1209,6 +1292,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);
@@ -1220,10 +1304,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);
@@ -1257,6 +1360,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,
@@ -1298,10 +1460,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:
@@ -1371,6 +1557,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 0734c10059..06adbf448f 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
@@ -309,16 +312,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;
struct rte_ether_addr mac_addr;
@@ -336,6 +343,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,
@@ -362,6 +371,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..15b839bb74
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.c
@@ -0,0 +1,606 @@
+/* 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_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 = ð_mask->hdr.dst_addr;
+ src_addr_mask = ð_mask->hdr.src_addr;
+ dst_addr_spec = ð_spec->hdr.dst_addr;
+ src_addr_spec = ð_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 6dab2f8cd8..d8e0b19463 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 e1ba7e3958..3ad8fe2fe9 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;
}
@@ -226,7 +231,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;
@@ -359,7 +364,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;
@@ -382,7 +387,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);
@@ -426,7 +431,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 {
@@ -471,7 +476,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 798863dad9..82b2e4fb7c 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 dcb8faf4ed..a662bb4375 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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox