mlxsw: spectrum_flower: Offload FLOW_ACTION_MANGLE
authorPetr Machata <petrm@mellanox.com>
Thu, 26 Mar 2020 14:01:12 +0000 (16:01 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 26 Mar 2020 18:55:40 +0000 (11:55 -0700)
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>
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c

index 3ae0a91875ef2ab05f0ff3ed4b40d778b43aa821..70a104e728f622656b1bd878b7a4994d2788502e 100644 (file)
@@ -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)
index 2125d7d6bcb0d70ab822ed3f868d2a8d12a8c708..8c2705e16ef752bffd1683d8e4547bbf8e90f86c 100644 (file)
@@ -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,
index bbd8bec8fee4c602df3205a1d81ba0a296aea60d..273e373a37b61bf16f5b999c19a24a378c79477e 100644 (file)
@@ -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);
index 01324d002680acdab77fb25c7909df76e4d68796..6fc1496b9514cf2fb1a373c0602f7086c9f100f4 100644 (file)
@@ -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)
index 3d3cad3784e5c8272437814a4c166976964fc14a..33a5e2a0a1adf8898bac3d804907fdaea8132f55 100644 (file)
@@ -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");