Commit 9b4b16bb authored by Petr Machata's avatar Petr Machata Committed by David S. Miller
Browse files

mlxsw: spectrum_flower: Offload FLOW_ACTION_MANGLE



Offload action pedit ex munge when used with a flower classifier. Only
allow setting of DSCP, ECN, or the whole DSField in IPv4 and IPv6 packets.

Signed-off-by: default avatarPetr Machata <petrm@mellanox.com>
Reviewed-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 50e4ee4b
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -1337,6 +1337,62 @@ mlxsw_afa_qos_switch_prio_pack(char *payload,
	mlxsw_afa_qos_switch_prio_set(payload, prio);
}

static int __mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block,
						bool set_dscp, u8 dscp,
						bool set_ecn, u8 ecn,
						struct netlink_ext_ack *extack)
{
	char *act = mlxsw_afa_block_append_action(block,
						  MLXSW_AFA_QOS_CODE,
						  MLXSW_AFA_QOS_SIZE);

	if (IS_ERR(act)) {
		NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action");
		return PTR_ERR(act);
	}

	if (set_ecn)
		mlxsw_afa_qos_ecn_pack(act, MLXSW_AFA_QOS_ECN_CMD_SET, ecn);
	if (set_dscp) {
		mlxsw_afa_qos_dscp_pack(act, MLXSW_AFA_QOS_DSCP_CMD_SET_ALL,
					dscp);
		mlxsw_afa_qos_dscp_rw_set(act, MLXSW_AFA_QOS_DSCP_RW_CLEAR);
	}

	return 0;
}

int mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block,
				       u8 dsfield,
				       struct netlink_ext_ack *extack)
{
	return __mlxsw_afa_block_append_qos_dsfield(block,
						    true, dsfield >> 2,
						    true, dsfield & 0x03,
						    extack);
}
EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dsfield);

int mlxsw_afa_block_append_qos_dscp(struct mlxsw_afa_block *block,
				    u8 dscp, struct netlink_ext_ack *extack)
{
	return __mlxsw_afa_block_append_qos_dsfield(block,
						    true, dscp,
						    false, 0,
						    extack);
}
EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dscp);

int mlxsw_afa_block_append_qos_ecn(struct mlxsw_afa_block *block,
				   u8 ecn, struct netlink_ext_ack *extack)
{
	return __mlxsw_afa_block_append_qos_dsfield(block,
						    false, 0,
						    true, ecn,
						    extack);
}
EXPORT_SYMBOL(mlxsw_afa_block_append_qos_ecn);

int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block,
					   u8 prio,
					   struct netlink_ext_ack *extack)
+7 −0
Original line number Diff line number Diff line
@@ -65,6 +65,13 @@ int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block,
int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block,
					   u8 prio,
					   struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block,
				       u8 dsfield,
				       struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_qos_dscp(struct mlxsw_afa_block *block,
				    u8 dscp, struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_qos_ecn(struct mlxsw_afa_block *block,
				   u8 ecn, struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block,
					     u32 counter_index);
int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block,
+5 −0
Original line number Diff line number Diff line
@@ -749,6 +749,11 @@ int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp,
int mlxsw_sp_acl_rulei_act_priority(struct mlxsw_sp *mlxsw_sp,
				    struct mlxsw_sp_acl_rule_info *rulei,
				    u32 prio, struct netlink_ext_ack *extack);
int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
				  struct mlxsw_sp_acl_rule_info *rulei,
				  enum flow_action_mangle_base htype,
				  u32 offset, u32 mask, u32 val,
				  struct netlink_ext_ack *extack);
int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_acl_rule_info *rulei,
				 struct netlink_ext_ack *extack);
+91 −0
Original line number Diff line number Diff line
@@ -655,6 +655,97 @@ int mlxsw_sp_acl_rulei_act_priority(struct mlxsw_sp *mlxsw_sp,
						      extack);
}

enum mlxsw_sp_acl_mangle_field {
	MLXSW_SP_ACL_MANGLE_FIELD_IP_DSFIELD,
	MLXSW_SP_ACL_MANGLE_FIELD_IP_DSCP,
	MLXSW_SP_ACL_MANGLE_FIELD_IP_ECN,
};

struct mlxsw_sp_acl_mangle_action {
	enum flow_action_mangle_base htype;
	/* Offset is u32-aligned. */
	u32 offset;
	/* Mask bits are unset for the modified field. */
	u32 mask;
	/* Shift required to extract the set value. */
	u32 shift;
	enum mlxsw_sp_acl_mangle_field field;
};

#define MLXSW_SP_ACL_MANGLE_ACTION(_htype, _offset, _mask, _shift, _field) \
	{								\
		.htype = _htype,					\
		.offset = _offset,					\
		.mask = _mask,						\
		.shift = _shift,					\
		.field = MLXSW_SP_ACL_MANGLE_FIELD_##_field,		\
	}

#define MLXSW_SP_ACL_MANGLE_ACTION_IP4(_offset, _mask, _shift, _field) \
	MLXSW_SP_ACL_MANGLE_ACTION(FLOW_ACT_MANGLE_HDR_TYPE_IP4,       \
				   _offset, _mask, _shift, _field)

#define MLXSW_SP_ACL_MANGLE_ACTION_IP6(_offset, _mask, _shift, _field) \
	MLXSW_SP_ACL_MANGLE_ACTION(FLOW_ACT_MANGLE_HDR_TYPE_IP6,       \
				   _offset, _mask, _shift, _field)

static struct mlxsw_sp_acl_mangle_action mlxsw_sp_acl_mangle_actions[] = {
	MLXSW_SP_ACL_MANGLE_ACTION_IP4(0, 0xff00ffff, 16, IP_DSFIELD),
	MLXSW_SP_ACL_MANGLE_ACTION_IP4(0, 0xff03ffff, 18, IP_DSCP),
	MLXSW_SP_ACL_MANGLE_ACTION_IP4(0, 0xfffcffff, 16, IP_ECN),
	MLXSW_SP_ACL_MANGLE_ACTION_IP6(0, 0xf00fffff, 20, IP_DSFIELD),
	MLXSW_SP_ACL_MANGLE_ACTION_IP6(0, 0xf03fffff, 22, IP_DSCP),
	MLXSW_SP_ACL_MANGLE_ACTION_IP6(0, 0xffcfffff, 20, IP_ECN),
};

static int
mlxsw_sp_acl_rulei_act_mangle_field(struct mlxsw_sp *mlxsw_sp,
				    struct mlxsw_sp_acl_rule_info *rulei,
				    struct mlxsw_sp_acl_mangle_action *mact,
				    u32 val, struct netlink_ext_ack *extack)
{
	switch (mact->field) {
	case MLXSW_SP_ACL_MANGLE_FIELD_IP_DSFIELD:
		return mlxsw_afa_block_append_qos_dsfield(rulei->act_block,
							  val, extack);
	case MLXSW_SP_ACL_MANGLE_FIELD_IP_DSCP:
		return mlxsw_afa_block_append_qos_dscp(rulei->act_block,
						       val, extack);
	case MLXSW_SP_ACL_MANGLE_FIELD_IP_ECN:
		return mlxsw_afa_block_append_qos_ecn(rulei->act_block,
						      val, extack);
	}

	/* We shouldn't have gotten a match in the first place! */
	WARN_ONCE(1, "Unhandled mangle field");
	return -EINVAL;
}

int mlxsw_sp_acl_rulei_act_mangle(struct mlxsw_sp *mlxsw_sp,
				  struct mlxsw_sp_acl_rule_info *rulei,
				  enum flow_action_mangle_base htype,
				  u32 offset, u32 mask, u32 val,
				  struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_acl_mangle_action *mact;
	size_t i;

	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_acl_mangle_actions); ++i) {
		mact = &mlxsw_sp_acl_mangle_actions[i];
		if (mact->htype == htype &&
		    mact->offset == offset &&
		    mact->mask == mask) {
			val >>= mact->shift;
			return mlxsw_sp_acl_rulei_act_mangle_field(mlxsw_sp,
								   rulei, mact,
								   val, extack);
		}
	}

	NL_SET_ERR_MSG_MOD(extack, "Unsupported mangle field");
	return -EINVAL;
}

int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_acl_rule_info *rulei,
				 struct netlink_ext_ack *extack)
+15 −0
Original line number Diff line number Diff line
@@ -158,6 +158,21 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
			return mlxsw_sp_acl_rulei_act_priority(mlxsw_sp, rulei,
							       act->priority,
							       extack);
		case FLOW_ACTION_MANGLE: {
			enum flow_action_mangle_base htype = act->mangle.htype;
			__be32 be_mask = (__force __be32) act->mangle.mask;
			__be32 be_val = (__force __be32) act->mangle.val;
			u32 offset = act->mangle.offset;
			u32 mask = be32_to_cpu(be_mask);
			u32 val = be32_to_cpu(be_val);

			err = mlxsw_sp_acl_rulei_act_mangle(mlxsw_sp, rulei,
							    htype, offset,
							    mask, val, extack);
			if (err)
				return err;
			break;
			}
		default:
			NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
			dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");