Add support for represented_port item in pattern. And if the spec and mask
both are NULL, translate function will not add source vport to matcher.

For example, testpmd starts with PF, VF-rep0 and VF-rep1, below command
will redirect packets from VF0 and VF1 to wire:
testpmd> flow create 0 ingress transfer group 0 pattern eth /
represented_port / end actions represented_port ethdev_id is 0 / end

Signed-off-by: Sean Zhang <xiazh...@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viachesl...@nvidia.com>
---
v2 -- add missing doc
---
 doc/guides/nics/features/mlx5.ini      |   1 +
 doc/guides/nics/mlx5.rst               |   1 +
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/net/mlx5/mlx5_flow.h           |   4 +
 drivers/net/mlx5/mlx5_flow_dv.c        | 160 ++++++++++++++++++++++++++++++++-
 5 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/features/mlx5.ini 
b/doc/guides/nics/features/mlx5.ini
index 5738f35..e056516 100644
--- a/doc/guides/nics/features/mlx5.ini
+++ b/doc/guides/nics/features/mlx5.ini
@@ -84,6 +84,7 @@ udp                  = Y
 vlan                 = Y
 vxlan                = Y
 vxlan_gpe            = Y
+represented_port     = Y
 
 [rte_flow actions]
 age                  = I
diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index d83c56d..1e13a93 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -93,6 +93,7 @@ Features
 - Connection tracking.
 - Sub-Function representors.
 - Sub-Function.
+- Matching on represented port.
 
 
 Limitations
diff --git a/doc/guides/rel_notes/release_22_07.rst 
b/doc/guides/rel_notes/release_22_07.rst
index d46f773..28f25b1 100644
--- a/doc/guides/rel_notes/release_22_07.rst
+++ b/doc/guides/rel_notes/release_22_07.rst
@@ -116,6 +116,7 @@ New Features
   * Added support for promiscuous mode on Windows.
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
+  * Added matching on represented port.
 
 * **Updated VMware vmxnet3 networking driver.**
 
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index eb13365..85e55eb 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -189,6 +189,10 @@ enum mlx5_feature_name {
 /* ESP item */
 #define MLX5_FLOW_ITEM_ESP (UINT64_C(1) << 40)
 
+/* Port Representor/Represented Port item */
+#define MLX5_FLOW_ITEM_PORT_REPRESENTOR (UINT64_C(1) << 41)
+#define MLX5_FLOW_ITEM_REPRESENTED_PORT (UINT64_C(1) << 42)
+
 /* Outer Masks. */
 #define MLX5_FLOW_LAYER_OUTER_L3 \
        (MLX5_FLOW_LAYER_OUTER_L3_IPV4 | MLX5_FLOW_LAYER_OUTER_L3_IPV6)
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index a575e31..ee0a4bd 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -2211,6 +2211,80 @@ struct field_modify_info modify_tcp[] = {
 }
 
 /**
+ * Validate represented port item.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ * @param[in] item
+ *   Item specification.
+ * @param[in] attr
+ *   Attributes of flow that includes this item.
+ * @param[in] item_flags
+ *   Bit-fields that holds the items detected until now.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_validate_item_represented_port(struct rte_eth_dev *dev,
+                                      const struct rte_flow_item *item,
+                                      const struct rte_flow_attr *attr,
+                                      uint64_t item_flags,
+                                      struct rte_flow_error *error)
+{
+       const struct rte_flow_item_ethdev *spec = item->spec;
+       const struct rte_flow_item_ethdev *mask = item->mask;
+       const struct rte_flow_item_ethdev switch_mask = {
+                       .port_id = UINT16_MAX,
+       };
+       struct mlx5_priv *esw_priv;
+       struct mlx5_priv *dev_priv;
+       int ret;
+
+       if (!attr->transfer)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+                                         "match on port id is valid only when 
transfer flag is enabled");
+       if (item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT)
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                         "multiple source ports are not 
supported");
+       if (!mask)
+               mask = &switch_mask;
+       if (mask->port_id != UINT16_MAX)
+               return rte_flow_error_set(error, ENOTSUP,
+                                          RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
+                                          "no support for partial mask on 
\"id\" field");
+       ret = mlx5_flow_item_acceptable
+                               (item, (const uint8_t *)mask,
+                                (const uint8_t *)&rte_flow_item_ethdev_mask,
+                                sizeof(struct rte_flow_item_ethdev),
+                                MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
+       if (ret)
+               return ret;
+       if (!spec || spec->port_id == UINT16_MAX)
+               return 0;
+       esw_priv = mlx5_port_to_eswitch_info(spec->port_id, false);
+       if (!esw_priv)
+               return rte_flow_error_set(error, rte_errno,
+                                         RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
+                                         "failed to obtain E-Switch info for 
port");
+       dev_priv = mlx5_dev_to_eswitch_info(dev);
+       if (!dev_priv)
+               return rte_flow_error_set(error, rte_errno,
+                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                         NULL,
+                                         "failed to obtain E-Switch info");
+       if (esw_priv->domain_id != dev_priv->domain_id)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
+                                         "cannot match on a port from a 
different E-Switch");
+       return 0;
+}
+
+/**
  * Validate VLAN item.
  *
  * @param[in] item
@@ -6972,6 +7046,13 @@ struct mlx5_list_entry *
                        last_item = MLX5_FLOW_ITEM_PORT_ID;
                        port_id_item = items;
                        break;
+               case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT:
+                       ret = flow_dv_validate_item_represented_port
+                                       (dev, items, attr, item_flags, error);
+                       if (ret < 0)
+                               return ret;
+                       last_item = MLX5_FLOW_ITEM_REPRESENTED_PORT;
+                       break;
                case RTE_FLOW_ITEM_TYPE_ETH:
                        ret = mlx5_flow_validate_item_eth(items, item_flags,
                                                          true, error);
@@ -9980,6 +10061,77 @@ struct mlx5_list_entry *
 }
 
 /**
+ * Translate represented port item to eswitch match on port id.
+ *
+ * @param[in] dev
+ *   The devich to configure through.
+ * @param[in, out] matcher
+ *   Flow matcher.
+ * @param[in, out] key
+ *   Flow matcher value.
+ * @param[in] item
+ *   Flow pattern to translate.
+ * @param[in]
+ *   Flow attributes.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+flow_dv_translate_item_represented_port(struct rte_eth_dev *dev, void *matcher,
+                                       void *key,
+                                       const struct rte_flow_item *item,
+                                       const struct rte_flow_attr *attr)
+{
+       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_priv *priv;
+       uint16_t mask, id;
+
+       if (!pid_m && !pid_v)
+               return 0;
+       if (pid_v && pid_v->port_id == UINT16_MAX) {
+               flow_dv_translate_item_source_vport(matcher, key,
+                       flow_dv_get_esw_manager_vport_id(dev), UINT16_MAX);
+               return 0;
+       }
+       mask = pid_m ? pid_m->port_id : UINT16_MAX;
+       id = pid_v ? pid_v->port_id : dev->data->port_id;
+       priv = mlx5_port_to_eswitch_info(id, item == NULL);
+       if (!priv)
+               return -rte_errno;
+       /*
+        * Translate to vport field or to metadata, depending on mode.
+        * Kernel can use either misc.source_port or half of C0 metadata
+        * register.
+        */
+       if (priv->vport_meta_mask) {
+               /*
+                * Provide the hint for SW steering library
+                * to insert the flow into ingress domain and
+                * save the extra vport match.
+                */
+               if (mask == UINT16_MAX && priv->vport_id == UINT16_MAX &&
+                   priv->pf_bond < 0 && attr->transfer)
+                       flow_dv_translate_item_source_vport
+                               (matcher, key, priv->vport_id, mask);
+               /*
+                * We should always set the vport metadata register,
+                * otherwise the SW steering library can drop
+                * the rule if wire vport metadata value is not zero,
+                * it depends on kernel configuration.
+                */
+               flow_dv_translate_item_meta_vport(matcher, key,
+                                                 priv->vport_meta_tag,
+                                                 priv->vport_meta_mask);
+       } else {
+               flow_dv_translate_item_source_vport(matcher, key,
+                                                   priv->vport_id, mask);
+       }
+       return 0;
+}
+
+/**
  * Add ICMP6 item to matcher and to the value.
  *
  * @param[in, out] matcher
@@ -13615,6 +13767,11 @@ struct mlx5_list_entry *
                                (dev, match_mask, match_value, items, attr);
                        last_item = MLX5_FLOW_ITEM_PORT_ID;
                        break;
+               case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT:
+                       flow_dv_translate_item_represented_port
+                               (dev, match_mask, match_value, items, attr);
+                       last_item = MLX5_FLOW_ITEM_REPRESENTED_PORT;
+                       break;
                case RTE_FLOW_ITEM_TYPE_ETH:
                        flow_dv_translate_item_eth(match_mask, match_value,
                                                   items, tunnel,
@@ -13873,7 +14030,8 @@ struct mlx5_list_entry *
         * In both cases the source port is set according the current port
         * in use.
         */
-       if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) && priv->sh->esw_mode &&
+       if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
+           !(item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) && 
priv->sh->esw_mode &&
            !(attr->egress && !attr->transfer)) {
                if (flow_dv_translate_item_port_id(dev, match_mask,
                                                   match_value, NULL, attr))
-- 
1.8.3.1

Reply via email to