Currently, in switch mode, mlx5 PMD only supports match with
dedicated vport. There is a use case which user may want to
offload the rules only to match with all the packet sent by
application not from vport.

Since the port_id info of packet sent by application is
E-Switch manager, and kernel driver has exposed the E-Switch
manager register value, this commit adds the support of
register matching for E-Switch manager.

Signed-off-by: Suanming Mou <suanmi...@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnow...@nvidia.com>
---

v3:
 - update dependency.

v2:
 - align to single patch.
 - update doc.

---
 doc/guides/nics/mlx5.rst               |  7 +++++
 doc/guides/rel_notes/release_24_07.rst |  1 +
 drivers/common/mlx5/linux/meson.build  |  2 ++
 drivers/net/mlx5/hws/mlx5dr_definer.c  |  3 ++-
 drivers/net/mlx5/hws/mlx5dr_definer.h  |  5 +++-
 drivers/net/mlx5/hws/mlx5dr_rule.c     |  2 +-
 drivers/net/mlx5/linux/mlx5_os.c       | 12 +++++++++
 drivers/net/mlx5/mlx5.h                | 14 ++++++++++
 drivers/net/mlx5/mlx5_flow.h           | 36 ++++++++++++++++++++------
 drivers/net/mlx5/mlx5_flow_dv.c        | 24 +++++++++++++----
 10 files changed, 90 insertions(+), 16 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index 5cd41d3c7f..8e8a19f64d 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -170,6 +170,7 @@ Features
 - Matching on represented port.
 - Matching on aggregated affinity.
 - Matching on external Tx queue.
+- Matching on E-Switch manager.
 
 
 Limitations
@@ -910,6 +911,11 @@ Limitations
   The flow engine of a process cannot move from active to standby mode
   if preceding active application rules are still present and vice versa.
 
+- In switch mode, flow rule matching ``RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT``
+  item with port_id ``UINT16_MAX`` means matching with packets sent by E-Switch
+  manager from software.
+  Need upstream Linux 6.7+ and rdma-core 50.0+ or MLNX_OFED 24.04+.
+
 
 Statistics
 ----------
@@ -1585,6 +1591,7 @@ entities on the HCA.
 With this configuration, mlx5 PMD supports:
 
 - matching traffic coming from physical port, PF, VF or SF using 
REPRESENTED_PORT items;
+- matching traffic coming from E-Switch manager using REPRESENTED_PORT item 
with port_id UINT16_MAX;
 - forwarding traffic to physical port, PF, VF or SF using REPRESENTED_PORT 
actions;
 
 Requirements
diff --git a/doc/guides/rel_notes/release_24_07.rst 
b/doc/guides/rel_notes/release_24_07.rst
index 3a3257fcd5..7688ed2764 100644
--- a/doc/guides/rel_notes/release_24_07.rst
+++ b/doc/guides/rel_notes/release_24_07.rst
@@ -85,6 +85,7 @@ New Features
 
   * Added match with Tx queue.
   * Added match with external Tx queue.
+  * Added match with E-Switch manager.
 
 
 Removed Items
diff --git a/drivers/common/mlx5/linux/meson.build 
b/drivers/common/mlx5/linux/meson.build
index cdee40c553..82e8046e0c 100644
--- a/drivers/common/mlx5/linux/meson.build
+++ b/drivers/common/mlx5/linux/meson.build
@@ -201,6 +201,8 @@ has_sym_args = [
             'mlx5dv_create_steering_anchor'],
         [ 'HAVE_IBV_FORK_UNNEEDED', 'infiniband/verbs.h',
             'ibv_is_fork_initialized'],
+        [ 'HAVE_IBV_DEVICE_ATTR_ESW_MGR_REG_C0', 'infiniband/mlx5dv.h',
+            'MLX5DV_CONTEXT_MASK_REG_C0' ],
 ]
 if  libmtcr_ul_found
     has_sym_args += [
diff --git a/drivers/net/mlx5/hws/mlx5dr_definer.c 
b/drivers/net/mlx5/hws/mlx5dr_definer.c
index 67cfba1c10..9ebda9267d 100644
--- a/drivers/net/mlx5/hws/mlx5dr_definer.c
+++ b/drivers/net/mlx5/hws/mlx5dr_definer.c
@@ -723,7 +723,7 @@ mlx5dr_definer_vport_set(struct mlx5dr_definer_fc *fc,
        const struct flow_hw_port_info *port_info;
        uint32_t regc_value;
 
-       port_info = flow_hw_conv_port_id(v->port_id);
+       port_info = flow_hw_conv_port_id(fc->dr_ctx, v->port_id);
        if (unlikely(!port_info))
                regc_value = BAD_PORT;
        else
@@ -1550,6 +1550,7 @@ mlx5dr_definer_conv_item_port(struct 
mlx5dr_definer_conv_data *cd,
                DR_CALC_SET_HDR(fc, registers, register_c_0);
                fc->bit_off = __builtin_ctz(caps->wire_regc_mask);
                fc->bit_mask = caps->wire_regc_mask >> fc->bit_off;
+               fc->dr_ctx = cd->ctx;
        } else {
                DR_LOG(ERR, "Pord ID item mask must specify ID mask");
                rte_errno = EINVAL;
diff --git a/drivers/net/mlx5/hws/mlx5dr_definer.h 
b/drivers/net/mlx5/hws/mlx5dr_definer.h
index 463e22732e..b583f78943 100644
--- a/drivers/net/mlx5/hws/mlx5dr_definer.h
+++ b/drivers/net/mlx5/hws/mlx5dr_definer.h
@@ -223,9 +223,12 @@ enum mlx5dr_definer_type {
 struct mlx5dr_definer_fc {
        uint8_t item_idx;
        uint8_t is_range;
-       uint16_t extra_data;
        uint8_t compare_idx;
        bool compare_set_base;
+       union {
+               uint32_t extra_data;
+               void *dr_ctx;
+       };
        uint32_t byte_off;
        int bit_off;
        uint32_t bit_mask;
diff --git a/drivers/net/mlx5/hws/mlx5dr_rule.c 
b/drivers/net/mlx5/hws/mlx5dr_rule.c
index 74abb38163..06d8e66f63 100644
--- a/drivers/net/mlx5/hws/mlx5dr_rule.c
+++ b/drivers/net/mlx5/hws/mlx5dr_rule.c
@@ -28,7 +28,7 @@ static void mlx5dr_rule_skip(struct mlx5dr_matcher *matcher,
 
        if (mt->item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) {
                v = items[mt->vport_item_id].spec;
-               vport = flow_hw_conv_port_id(v->port_id);
+               vport = flow_hw_conv_port_id(matcher->tbl->ctx, v->port_id);
                if (unlikely(!vport)) {
                        DR_LOG(ERR, "Fail to map port ID %d, ignoring", 
v->port_id);
                        return;
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 2c3d5bd6cd..1753acd050 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -160,6 +160,9 @@ mlx5_os_capabilities_prepare(struct mlx5_dev_ctx_shared *sh)
 #endif
 #ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
        dv_attr.comp_mask |= MLX5DV_CONTEXT_MASK_STRIDING_RQ;
+#endif
+#ifdef HAVE_IBV_DEVICE_ATTR_ESW_MGR_REG_C0
+       dv_attr.comp_mask |= MLX5DV_CONTEXT_MASK_REG_C0;
 #endif
        err = mlx5_glue->dv_query_device(cdev->ctx, &dv_attr);
        if (err) {
@@ -374,6 +377,15 @@ mlx5_os_capabilities_prepare(struct mlx5_dev_ctx_shared 
*sh)
                                        hca_attr->scatter_fcs_w_decap_disable;
        sh->dev_cap.rq_delay_drop_en = hca_attr->rq_delay_drop;
        mlx5_rt_timestamp_config(sh, hca_attr);
+#ifdef HAVE_IBV_DEVICE_ATTR_ESW_MGR_REG_C0
+       if (dv_attr.comp_mask & MLX5DV_CONTEXT_MASK_REG_C0) {
+               sh->dev_cap.esw_info.regc_value = dv_attr.reg_c0.value;
+               sh->dev_cap.esw_info.regc_mask = dv_attr.reg_c0.mask;
+       }
+#else
+       sh->dev_cap.esw_info.regc_value = 0;
+       sh->dev_cap.esw_info.regc_mask = 0;
+#endif
        return 0;
 }
 
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 6af367b36b..c9a3837bd2 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -141,6 +141,19 @@ struct mlx5_flow_cb_ctx {
        void *data2;
 };
 
+struct flow_hw_port_info {
+       uint32_t regc_mask;
+       uint32_t regc_value;
+       uint32_t is_wire:1;
+       uint32_t direction:2;
+};
+
+enum mlx5_vport_direction {
+       MLX5_VPORT_DIRECTION_ANY = 0,
+       MLX5_VPORT_DIRECTION_NORTH,
+       MLX5_VPORT_DIRECTION_SOUTH,
+};
+
 /* Device capabilities structure which isn't changed in any stage. */
 struct mlx5_dev_cap {
        int max_cq; /* Maximum number of supported CQs */
@@ -184,6 +197,7 @@ struct mlx5_dev_cap {
                /* Log min WQE size, (size of single stride)*(num of strides).*/
        } mprq; /* Capability for Multi-Packet RQ. */
        char fw_ver[64]; /* Firmware version of this device. */
+       struct flow_hw_port_info esw_info; /* E-switch manager reg_c0. */
 };
 
 #define MLX5_MPESW_PORT_INVALID (-1)
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 8ab92dc4a6..92e2ecedb3 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1977,12 +1977,6 @@ struct mlx5_hl_data {
        uint32_t dw_mask;
 };
 
-struct flow_hw_port_info {
-       uint32_t regc_mask;
-       uint32_t regc_value;
-       uint32_t is_wire:1;
-};
-
 extern struct flow_hw_port_info mlx5_flow_hw_port_infos[RTE_MAX_ETHPORTS];
 
 /*
@@ -2048,15 +2042,41 @@ flow_hw_get_port_id(void *dr_ctx)
        return UINT16_MAX;
 }
 
+/*
+ * Get given eswitch manager id.
+ * Used in HWS match with port creation.
+ */
+static __rte_always_inline const struct flow_hw_port_info *
+flow_hw_get_esw_mgr_id(void *dr_ctx)
+{
+#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
+       uint16_t port_id;
+
+       MLX5_ETH_FOREACH_DEV(port_id, NULL) {
+               struct mlx5_priv *priv;
+
+               priv = rte_eth_devices[port_id].data->dev_private;
+               if (priv->dr_ctx == dr_ctx)
+                       return &priv->sh->dev_cap.esw_info;
+       }
+#else
+       RTE_SET_USED(dr_ctx);
+#endif
+       return NULL;
+}
+
 /*
  * Get metadata match tag and mask for given rte_eth_dev port.
  * Used in HWS rule creation.
  */
 static __rte_always_inline const struct flow_hw_port_info *
-flow_hw_conv_port_id(const uint16_t port_id)
+flow_hw_conv_port_id(void *ctx, const uint16_t port_id)
 {
        struct flow_hw_port_info *port_info;
 
+       if (port_id == UINT16_MAX && ctx)
+               return flow_hw_get_esw_mgr_id(ctx);
+
        if (port_id >= RTE_MAX_ETHPORTS)
                return NULL;
        port_info = &mlx5_flow_hw_port_infos[port_id];
@@ -2082,7 +2102,7 @@ flow_hw_get_wire_port(struct ibv_context *ibctx)
                        struct ibv_context *port_ibctx = priv->sh->cdev->ctx;
 
                        if (port_ibctx->device == ibdev)
-                               return flow_hw_conv_port_id(port_id);
+                               return flow_hw_conv_port_id(priv->dr_ctx, 
port_id);
                }
        }
        return NULL;
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 4436b6f4c9..27f15817b4 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -10947,17 +10947,31 @@ flow_dv_translate_item_represented_port(struct 
rte_eth_dev *dev, void *key,
        const struct rte_flow_item_ethdev *pid_m = item ? item->mask : NULL;
        const struct rte_flow_item_ethdev *pid_v = item ? item->spec : NULL;
        struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
-       struct mlx5_priv *priv;
+       struct mlx5_priv *priv = dev->data->dev_private;
        uint16_t mask, id;
        uint32_t vport_meta;
+       bool vport_match = false;
 
        MLX5_ASSERT(wks);
+#ifndef HAVE_IBV_DEVICE_ATTR_ESW_MGR_REG_C0
+       if (priv->sh->config.dv_flow_en == 2)
+               vport_match = true;
+#endif
        if (!pid_m && !pid_v)
                return 0;
        if (pid_v && pid_v->port_id == UINT16_MAX) {
-               flow_dv_translate_item_source_vport(key,
-                       key_type & MLX5_SET_MATCHER_V ?
-                       mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff);
+               if (priv->sh->config.dv_flow_en != 2 || vport_match) {
+                       flow_dv_translate_item_source_vport
+                               (key, key_type & MLX5_SET_MATCHER_V ?
+                                mlx5_flow_get_esw_manager_vport_id(dev) : 
0xffff);
+               } else {
+                       if (key_type & MLX5_SET_MATCHER_M)
+                               vport_meta = 
priv->sh->dev_cap.esw_info.regc_mask;
+                       else
+                               vport_meta = 
priv->sh->dev_cap.esw_info.regc_value;
+                       flow_dv_translate_item_meta_vport(key, vport_meta,
+                                                         
priv->sh->dev_cap.esw_info.regc_mask);
+               }
                return 0;
        }
        mask = pid_m ? pid_m->port_id : UINT16_MAX;
@@ -10978,7 +10992,7 @@ flow_dv_translate_item_represented_port(struct 
rte_eth_dev *dev, void *key,
         * Kernel can use either misc.source_port or half of C0 metadata
         * register.
         */
-       if (priv->vport_meta_mask) {
+       if (priv->vport_meta_mask && !vport_match) {
                /*
                 * Provide the hint for SW steering library
                 * to insert the flow into ingress domain and
-- 
2.34.1

Reply via email to