Commit a51dcc10 authored by Hamdan Igbaria's avatar Hamdan Igbaria Committed by Saeed Mahameed
Browse files

net/mlx5: DR, Modify set action limitation extension



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: default avatarHamdan Igbaria <hamdani@mellanox.com>
Signed-off-by: default avatarAlex Vesker <valex@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 6d65bc64
Loading
Loading
Loading
Loading
+165 −61
Original line number Diff line number Diff line
@@ -1314,58 +1314,85 @@ not_found:
}

static int
dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
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;
	MLX5_SET(dr_action_hw_set, hw_action,
		 opcode, MLX5DR_ACTION_MDFY_HW_OP_ADD);

	MLX5_SET(dr_action_hw_set, hw_action, destination_field_code,
		 hw_action_info->hw_field);

	MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter,
		 hw_action_info->start);

	/* PRM defines that length zero specific length of 32bits */
		if (!length)
			length = 32;
	MLX5_SET(dr_action_hw_set, hw_action, destination_length,
		 max_length == 32 ? 0 : max_length);

		if (length + offset > max_length) {
			mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n");
	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;
	}
		break;

	case MLX5_ACTION_TYPE_ADD:
		hw_opcode = MLX5DR_ACTION_MDFY_HW_OP_ADD;
		offset = 0;
		length = max_length;
		break;
	/* PRM defines that length zero specific length of 32bits */
	length = length ? length : 32;

	default:
		mlx5dr_info(dmn, "Unsupported action_type for modify action\n");
		return -EOPNOTSUPP;
	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, hw_opcode);
	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) {
	switch (action) {
	case MLX5_ACTION_TYPE_SET:
		ret = dr_action_modify_sw_to_hw_set(dmn, sw_action,
						    hw_action,
						    ret_hw_info);
		break;

	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;
		}
		}

		if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) {
	} 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 if (action == MLX5_ACTION_TYPE_ADD) {

	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);
		mlx5dr_dbg(dmn, "Unsupported field %d for add action\n",
			   sw_field);
		return -EINVAL;
	}
	} else {
		mlx5dr_info(dmn, "Unsupported action %d modify action\n", action);
		return -EOPNOTSUPP;
	}

	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,