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

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
......@@ -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)
......
......@@ -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,
......
......@@ -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);
......
......@@ -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)
......
......@@ -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");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment