net/mlx5: DR, Modify set action limitation extension
authorHamdan Igbaria <hamdani@mellanox.com>
Tue, 24 Dec 2019 16:07:41 +0000 (18:07 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Thu, 23 Jan 2020 06:28:32 +0000 (22:28 -0800)
Modify set actions are not supported on both tx
and rx, added a check for that.
Also refactored the code in a way that every modify
action has his own functions, this needed so in the
future we could add copy action more smoothly.

Signed-off-by: Hamdan Igbaria <hamdani@mellanox.com>
Signed-off-by: Alex Vesker <valex@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c

index 9359eed..ad32b88 100644 (file)
@@ -1314,58 +1314,85 @@ not_found:
 }
 
 static int
-dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
-                         __be64 *sw_action,
-                         __be64 *hw_action,
-                         const struct dr_action_modify_field_conv **ret_hw_info)
+dr_action_modify_sw_to_hw_add(struct mlx5dr_domain *dmn,
+                             __be64 *sw_action,
+                             __be64 *hw_action,
+                             const struct dr_action_modify_field_conv **ret_hw_info)
 {
        const struct dr_action_modify_field_conv *hw_action_info;
-       u8 offset, length, max_length, action;
+       u8 max_length;
        u16 sw_field;
-       u8 hw_opcode;
        u32 data;
 
        /* Get SW modify action data */
-       action = MLX5_GET(set_action_in, sw_action, action_type);
-       length = MLX5_GET(set_action_in, sw_action, length);
-       offset = MLX5_GET(set_action_in, sw_action, offset);
        sw_field = MLX5_GET(set_action_in, sw_action, field);
        data = MLX5_GET(set_action_in, sw_action, data);
 
        /* Convert SW data to HW modify action format */
        hw_action_info = dr_action_modify_get_hw_info(sw_field);
        if (!hw_action_info) {
-               mlx5dr_dbg(dmn, "Modify action invalid field given\n");
+               mlx5dr_dbg(dmn, "Modify add action invalid field given\n");
                return -EINVAL;
        }
 
        max_length = hw_action_info->end - hw_action_info->start + 1;
 
-       switch (action) {
-       case MLX5_ACTION_TYPE_SET:
-               hw_opcode = MLX5DR_ACTION_MDFY_HW_OP_SET;
-               /* PRM defines that length zero specific length of 32bits */
-               if (!length)
-                       length = 32;
+       MLX5_SET(dr_action_hw_set, hw_action,
+                opcode, MLX5DR_ACTION_MDFY_HW_OP_ADD);
 
-               if (length + offset > max_length) {
-                       mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n");
-                       return -EINVAL;
-               }
-               break;
+       MLX5_SET(dr_action_hw_set, hw_action, destination_field_code,
+                hw_action_info->hw_field);
 
-       case MLX5_ACTION_TYPE_ADD:
-               hw_opcode = MLX5DR_ACTION_MDFY_HW_OP_ADD;
-               offset = 0;
-               length = max_length;
-               break;
+       MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter,
+                hw_action_info->start);
 
-       default:
-               mlx5dr_info(dmn, "Unsupported action_type for modify action\n");
-               return -EOPNOTSUPP;
+       /* PRM defines that length zero specific length of 32bits */
+       MLX5_SET(dr_action_hw_set, hw_action, destination_length,
+                max_length == 32 ? 0 : max_length);
+
+       MLX5_SET(dr_action_hw_set, hw_action, inline_data, data);
+
+       *ret_hw_info = hw_action_info;
+
+       return 0;
+}
+
+static int
+dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn,
+                             __be64 *sw_action,
+                             __be64 *hw_action,
+                             const struct dr_action_modify_field_conv **ret_hw_info)
+{
+       const struct dr_action_modify_field_conv *hw_action_info;
+       u8 offset, length, max_length;
+       u16 sw_field;
+       u32 data;
+
+       /* Get SW modify action data */
+       length = MLX5_GET(set_action_in, sw_action, length);
+       offset = MLX5_GET(set_action_in, sw_action, offset);
+       sw_field = MLX5_GET(set_action_in, sw_action, field);
+       data = MLX5_GET(set_action_in, sw_action, data);
+
+       /* Convert SW data to HW modify action format */
+       hw_action_info = dr_action_modify_get_hw_info(sw_field);
+       if (!hw_action_info) {
+               mlx5dr_dbg(dmn, "Modify set action invalid field given\n");
+               return -EINVAL;
        }
 
-       MLX5_SET(dr_action_hw_set, hw_action, opcode, hw_opcode);
+       /* PRM defines that length zero specific length of 32bits */
+       length = length ? length : 32;
+
+       max_length = hw_action_info->end - hw_action_info->start + 1;
+
+       if (length + offset > max_length) {
+               mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n");
+               return -EINVAL;
+       }
+
+       MLX5_SET(dr_action_hw_set, hw_action,
+                opcode, MLX5DR_ACTION_MDFY_HW_OP_SET);
 
        MLX5_SET(dr_action_hw_set, hw_action, destination_field_code,
                 hw_action_info->hw_field);
@@ -1384,48 +1411,120 @@ dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
 }
 
 static int
-dr_action_modify_check_field_limitation(struct mlx5dr_domain *dmn,
-                                       const __be64 *sw_action)
+dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
+                         __be64 *sw_action,
+                         __be64 *hw_action,
+                         const struct dr_action_modify_field_conv **ret_hw_info)
 {
-       u16 sw_field;
        u8 action;
+       int ret;
 
-       sw_field = MLX5_GET(set_action_in, sw_action, field);
+       *hw_action = 0;
+
+       /* Get SW modify action type */
        action = MLX5_GET(set_action_in, sw_action, action_type);
 
-       /* Check if SW field is supported in current domain (RX/TX) */
-       if (action == MLX5_ACTION_TYPE_SET) {
-               if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_A) {
-                       if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) {
-                               mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n",
-                                          sw_field);
-                               return -EINVAL;
-                       }
-               }
+       switch (action) {
+       case MLX5_ACTION_TYPE_SET:
+               ret = dr_action_modify_sw_to_hw_set(dmn, sw_action,
+                                                   hw_action,
+                                                   ret_hw_info);
+               break;
 
-               if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) {
-                       if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) {
-                               mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n",
-                                          sw_field);
-                               return -EINVAL;
-                       }
+       case MLX5_ACTION_TYPE_ADD:
+               ret = dr_action_modify_sw_to_hw_add(dmn, sw_action,
+                                                   hw_action,
+                                                   ret_hw_info);
+               break;
+
+       default:
+               mlx5dr_info(dmn, "Unsupported action_type for modify action\n");
+               ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+static int
+dr_action_modify_check_set_field_limitation(struct mlx5dr_action *action,
+                                           const __be64 *sw_action)
+{
+       u16 sw_field = MLX5_GET(set_action_in, sw_action, field);
+       struct mlx5dr_domain *dmn = action->rewrite.dmn;
+
+       if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_A) {
+               action->rewrite.allow_rx = 0;
+               if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) {
+                       mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n",
+                                  sw_field);
+                       return -EINVAL;
                }
-       } else if (action == MLX5_ACTION_TYPE_ADD) {
-               if (sw_field != MLX5_ACTION_IN_FIELD_OUT_IP_TTL &&
-                   sw_field != MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT &&
-                   sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM &&
-                   sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM) {
-                       mlx5dr_dbg(dmn, "Unsupported field %d for add action\n", sw_field);
+       } else if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) {
+               action->rewrite.allow_tx = 0;
+               if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) {
+                       mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n",
+                                  sw_field);
                        return -EINVAL;
                }
-       } else {
-               mlx5dr_info(dmn, "Unsupported action %d modify action\n", action);
-               return -EOPNOTSUPP;
+       }
+
+       if (!action->rewrite.allow_rx && !action->rewrite.allow_tx) {
+               mlx5dr_dbg(dmn, "Modify SET actions not supported on both RX and TX\n");
+               return -EINVAL;
        }
 
        return 0;
 }
 
+static int
+dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action,
+                                           const __be64 *sw_action)
+{
+       u16 sw_field = MLX5_GET(set_action_in, sw_action, field);
+       struct mlx5dr_domain *dmn = action->rewrite.dmn;
+
+       if (sw_field != MLX5_ACTION_IN_FIELD_OUT_IP_TTL &&
+           sw_field != MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT &&
+           sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM &&
+           sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM) {
+               mlx5dr_dbg(dmn, "Unsupported field %d for add action\n",
+                          sw_field);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+dr_action_modify_check_field_limitation(struct mlx5dr_action *action,
+                                       const __be64 *sw_action)
+{
+       struct mlx5dr_domain *dmn = action->rewrite.dmn;
+       u8 action_type;
+       int ret;
+
+       action_type = MLX5_GET(set_action_in, sw_action, action_type);
+
+       switch (action_type) {
+       case MLX5_ACTION_TYPE_SET:
+               ret = dr_action_modify_check_set_field_limitation(action,
+                                                                 sw_action);
+               break;
+
+       case MLX5_ACTION_TYPE_ADD:
+               ret = dr_action_modify_check_add_field_limitation(action,
+                                                                 sw_action);
+               break;
+
+       default:
+               mlx5dr_info(dmn, "Unsupported action %d modify action\n",
+                           action_type);
+               ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
 static bool
 dr_action_modify_check_is_ttl_modify(const u64 *sw_action)
 {
@@ -1434,7 +1533,7 @@ dr_action_modify_check_is_ttl_modify(const u64 *sw_action)
        return sw_field == MLX5_ACTION_IN_FIELD_OUT_IP_TTL;
 }
 
-static int dr_actions_convert_modify_header(struct mlx5dr_domain *dmn,
+static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
                                            u32 max_hw_actions,
                                            u32 num_sw_actions,
                                            __be64 sw_actions[],
@@ -1446,16 +1545,21 @@ static int dr_actions_convert_modify_header(struct mlx5dr_domain *dmn,
        u16 hw_field = MLX5DR_ACTION_MDFY_HW_FLD_RESERVED;
        u32 l3_type = MLX5DR_ACTION_MDFY_HW_HDR_L3_NONE;
        u32 l4_type = MLX5DR_ACTION_MDFY_HW_HDR_L4_NONE;
+       struct mlx5dr_domain *dmn = action->rewrite.dmn;
        int ret, i, hw_idx = 0;
        __be64 *sw_action;
        __be64 hw_action;
 
        *modify_ttl = false;
 
+       action->rewrite.allow_rx = 1;
+       action->rewrite.allow_tx = 1;
+
        for (i = 0; i < num_sw_actions; i++) {
                sw_action = &sw_actions[i];
 
-               ret = dr_action_modify_check_field_limitation(dmn, sw_action);
+               ret = dr_action_modify_check_field_limitation(action,
+                                                             sw_action);
                if (ret)
                        return ret;
 
@@ -1544,7 +1648,7 @@ static int dr_action_create_modify_action(struct mlx5dr_domain *dmn,
                goto free_chunk;
        }
 
-       ret = dr_actions_convert_modify_header(dmn,
+       ret = dr_actions_convert_modify_header(action,
                                               max_hw_actions,
                                               num_sw_actions,
                                               actions,