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: Petr Machata <petrm@mellanox.com> Reviewed-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
50e4ee4b92
commit
9b4b16bba2
@ -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");
|
||||
|
Reference in New Issue
Block a user