Add support for modify field in tunnel MPLS header.
For now it is supported only to copy from.

Signed-off-by: Michael Baum <michae...@nvidia.com>
Acked-by: Matan Azrad <ma...@nvidia.com>
---
 doc/guides/nics/mlx5.rst        |  2 ++
 drivers/common/mlx5/mlx5_prm.h  |  5 +++++
 drivers/net/mlx5/mlx5_flow.h    |  1 +
 drivers/net/mlx5/mlx5_flow_dv.c | 23 +++++++++++++++++++++++
 drivers/net/mlx5/mlx5_flow_hw.c | 10 +++++++---
 5 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index 85db539f19..67f7c407fc 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -538,6 +538,8 @@ Limitations
 
   - Supports the 'set' and 'add' operations for 
``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD`` action.
   - Modification of an arbitrary place in a packet via the special 
``RTE_FLOW_FIELD_START`` Field ID is not supported.
+  - Modification of the MPLS header is supported only in HWS and only to copy
+    from, the encapsulation level is always 0.
   - Modification of the 802.1Q Tag, VXLAN Network or GENEVE Network ID's is 
not supported.
   - Encapsulation levels are not supported, can modify outermost header fields 
only.
   - Offsets cannot skip past the boundary of a field.
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index d67c4336e6..4a8e1a10e5 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -787,6 +787,11 @@ enum mlx5_modification_field {
        MLX5_MODI_TUNNEL_HDR_DW_1 = 0x75,
        MLX5_MODI_GTPU_FIRST_EXT_DW_0 = 0x76,
        MLX5_MODI_HASH_RESULT = 0x81,
+       MLX5_MODI_IN_MPLS_LABEL_0 = 0x8a,
+       MLX5_MODI_IN_MPLS_LABEL_1,
+       MLX5_MODI_IN_MPLS_LABEL_2,
+       MLX5_MODI_IN_MPLS_LABEL_3,
+       MLX5_MODI_IN_MPLS_LABEL_4,
        MLX5_MODI_OUT_IPV6_NEXT_HDR = 0x4A,
        MLX5_MODI_INVALID = INT_MAX,
 };
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 568dae751e..ca9d7ac40c 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1113,6 +1113,7 @@ flow_modify_field_support_tag_array(enum 
rte_flow_field_id field)
 {
        switch (field) {
        case RTE_FLOW_FIELD_TAG:
+       case RTE_FLOW_FIELD_MPLS:
                return true;
        default:
                break;
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index f6278935c1..8e89b41c2d 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -1388,6 +1388,7 @@ mlx5_flow_item_field_width(struct rte_eth_dev *dev,
        case RTE_FLOW_FIELD_GENEVE_VNI:
                return 24;
        case RTE_FLOW_FIELD_GTP_TEID:
+       case RTE_FLOW_FIELD_MPLS:
        case RTE_FLOW_FIELD_TAG:
                return 32;
        case RTE_FLOW_FIELD_MARK:
@@ -1435,6 +1436,12 @@ flow_modify_info_mask_32_masked(uint32_t length, 
uint32_t off, uint32_t post_mas
        return rte_cpu_to_be_32(mask & post_mask);
 }
 
+static __rte_always_inline enum mlx5_modification_field
+mlx5_mpls_modi_field_get(const struct rte_flow_action_modify_data *data)
+{
+       return MLX5_MODI_IN_MPLS_LABEL_0 + data->tag_index;
+}
+
 static void
 mlx5_modify_flex_item(const struct rte_eth_dev *dev,
                      const struct mlx5_flex_item *flex,
@@ -1893,6 +1900,16 @@ mlx5_flow_field_id_to_modify_info
                else
                        info[idx].offset = off_be;
                break;
+       case RTE_FLOW_FIELD_MPLS:
+               MLX5_ASSERT(data->offset + width <= 32);
+               off_be = 32 - (data->offset + width);
+               info[idx] = (struct field_modify_info){4, 0,
+                                       mlx5_mpls_modi_field_get(data)};
+               if (mask)
+                       mask[idx] = flow_modify_info_mask_32(width, off_be);
+               else
+                       info[idx].offset = off_be;
+               break;
        case RTE_FLOW_FIELD_TAG:
                {
                        MLX5_ASSERT(data->offset + width <= 32);
@@ -5362,6 +5379,12 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev 
*dev,
                                RTE_FLOW_ERROR_TYPE_ACTION, action,
                                "modifications of the GENEVE Network"
                                " Identifier is not supported");
+       if (dst_data->field == RTE_FLOW_FIELD_MPLS ||
+           src_data->field == RTE_FLOW_FIELD_MPLS)
+               return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_ACTION, action,
+                               "modifications of the MPLS header "
+                               "is not supported");
        if (dst_data->field == RTE_FLOW_FIELD_MARK ||
            src_data->field == RTE_FLOW_FIELD_MARK)
                if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 0c76ee7446..8f35356c41 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -3713,6 +3713,11 @@ flow_hw_validate_action_modify_field(const struct 
rte_flow_action *action,
                return rte_flow_error_set(error, EINVAL,
                                RTE_FLOW_ERROR_TYPE_ACTION, action,
                                "modifying Geneve VNI is not supported");
+       /* Due to HW bug, tunnel MPLS header is read only. */
+       if (action_conf->dst.field == RTE_FLOW_FIELD_MPLS)
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ACTION, action,
+                               "MPLS cannot be used as destination");
        return 0;
 }
 
@@ -4243,9 +4248,8 @@ mlx5_flow_hw_actions_validate(struct rte_eth_dev *dev,
                        action_flags |= MLX5_FLOW_ACTION_METER;
                        break;
                case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
-                       ret = flow_hw_validate_action_modify_field(action,
-                                                                       mask,
-                                                                       error);
+                       ret = flow_hw_validate_action_modify_field(action, mask,
+                                                                  error);
                        if (ret < 0)
                                return ret;
                        action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
-- 
2.25.1

Reply via email to