Merge tag 'mlx5-updates-2019-11-01' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index da7555f..bb970b2 100644 (file)
@@ -1278,8 +1278,10 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
        mlx5_eswitch_del_vlan_action(esw, attr);
 
        for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
-               if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)
+               if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP) {
                        mlx5e_detach_encap(priv, flow, out_index);
+                       kfree(attr->parse_attr->tun_info[out_index]);
+               }
        kvfree(attr->parse_attr);
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
@@ -1559,6 +1561,7 @@ static void mlx5e_encap_dealloc(struct mlx5e_priv *priv, struct mlx5e_encap_entr
                        mlx5_packet_reformat_dealloc(priv->mdev, e->pkt_reformat);
        }
 
+       kfree(e->tun_info);
        kfree(e->encap_header);
        kfree_rcu(e, rcu);
 }
@@ -1664,46 +1667,63 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
                return err;
        }
 
-       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
-               struct flow_match_ipv4_addrs match;
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
+               struct flow_match_control match;
+               u16 addr_type;
 
-               flow_rule_match_enc_ipv4_addrs(rule, &match);
-               MLX5_SET(fte_match_set_lyr_2_4, headers_c,
-                        src_ipv4_src_ipv6.ipv4_layout.ipv4,
-                        ntohl(match.mask->src));
-               MLX5_SET(fte_match_set_lyr_2_4, headers_v,
-                        src_ipv4_src_ipv6.ipv4_layout.ipv4,
-                        ntohl(match.key->src));
-
-               MLX5_SET(fte_match_set_lyr_2_4, headers_c,
-                        dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
-                        ntohl(match.mask->dst));
-               MLX5_SET(fte_match_set_lyr_2_4, headers_v,
-                        dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
-                        ntohl(match.key->dst));
-
-               MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
-               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
-       } else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
-               struct flow_match_ipv6_addrs match;
+               flow_rule_match_enc_control(rule, &match);
+               addr_type = match.key->addr_type;
 
-               flow_rule_match_enc_ipv6_addrs(rule, &match);
-               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
-                                   src_ipv4_src_ipv6.ipv6_layout.ipv6),
-                      &match.mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
-               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
-                                   src_ipv4_src_ipv6.ipv6_layout.ipv6),
-                      &match.key->src, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
+               /* For tunnel addr_type used same key id`s as for non-tunnel */
+               if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+                       struct flow_match_ipv4_addrs match;
 
-               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
-                                   dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
-                      &match.mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
-               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
-                                   dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
-                      &match.key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6));
+                       flow_rule_match_enc_ipv4_addrs(rule, &match);
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                                src_ipv4_src_ipv6.ipv4_layout.ipv4,
+                                ntohl(match.mask->src));
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                                src_ipv4_src_ipv6.ipv4_layout.ipv4,
+                                ntohl(match.key->src));
 
-               MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
-               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6);
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                                dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
+                                ntohl(match.mask->dst));
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                                dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
+                                ntohl(match.key->dst));
+
+                       MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c,
+                                        ethertype);
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
+                                ETH_P_IP);
+               } else if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+                       struct flow_match_ipv6_addrs match;
+
+                       flow_rule_match_enc_ipv6_addrs(rule, &match);
+                       memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                           src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                              &match.mask->src, MLX5_FLD_SZ_BYTES(ipv6_layout,
+                                                                  ipv6));
+                       memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                           src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                              &match.key->src, MLX5_FLD_SZ_BYTES(ipv6_layout,
+                                                                 ipv6));
+
+                       memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                           dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                              &match.mask->dst, MLX5_FLD_SZ_BYTES(ipv6_layout,
+                                                                  ipv6));
+                       memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                           dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                              &match.key->dst, MLX5_FLD_SZ_BYTES(ipv6_layout,
+                                                                 ipv6));
+
+                       MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c,
+                                        ethertype);
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
+                                ETH_P_IPV6);
+               }
        }
 
        if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IP)) {
@@ -2221,13 +2241,14 @@ out_err:
 
 struct mlx5_fields {
        u8  field;
-       u8  size;
+       u8  field_bsize;
+       u32 field_mask;
        u32 offset;
        u32 match_offset;
 };
 
-#define OFFLOAD(fw_field, size, field, off, match_field) \
-               {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, size, \
+#define OFFLOAD(fw_field, field_bsize, field_mask, field, off, match_field) \
+               {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, field_bsize, field_mask, \
                 offsetof(struct pedit_headers, field) + (off), \
                 MLX5_BYTE_OFF(fte_match_set_lyr_2_4, match_field)}
 
@@ -2245,18 +2266,18 @@ struct mlx5_fields {
 })
 
 static bool cmp_val_mask(void *valp, void *maskp, void *matchvalp,
-                        void *matchmaskp, int size)
+                        void *matchmaskp, u8 bsize)
 {
        bool same = false;
 
-       switch (size) {
-       case sizeof(u8):
+       switch (bsize) {
+       case 8:
                same = SAME_VAL_MASK(u8, valp, maskp, matchvalp, matchmaskp);
                break;
-       case sizeof(u16):
+       case 16:
                same = SAME_VAL_MASK(u16, valp, maskp, matchvalp, matchmaskp);
                break;
-       case sizeof(u32):
+       case 32:
                same = SAME_VAL_MASK(u32, valp, maskp, matchvalp, matchmaskp);
                break;
        }
@@ -2265,41 +2286,43 @@ static bool cmp_val_mask(void *valp, void *maskp, void *matchvalp,
 }
 
 static struct mlx5_fields fields[] = {
-       OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0, dmac_47_16),
-       OFFLOAD(DMAC_15_0,  2, eth.h_dest[4], 0, dmac_15_0),
-       OFFLOAD(SMAC_47_16, 4, eth.h_source[0], 0, smac_47_16),
-       OFFLOAD(SMAC_15_0,  2, eth.h_source[4], 0, smac_15_0),
-       OFFLOAD(ETHERTYPE,  2, eth.h_proto, 0, ethertype),
-       OFFLOAD(FIRST_VID,  2, vlan.h_vlan_TCI, 0, first_vid),
-
-       OFFLOAD(IP_TTL, 1, ip4.ttl,   0, ttl_hoplimit),
-       OFFLOAD(SIPV4,  4, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4),
-       OFFLOAD(DIPV4,  4, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
-
-       OFFLOAD(SIPV6_127_96, 4, ip6.saddr.s6_addr32[0], 0,
+       OFFLOAD(DMAC_47_16, 32, U32_MAX, eth.h_dest[0], 0, dmac_47_16),
+       OFFLOAD(DMAC_15_0,  16, U16_MAX, eth.h_dest[4], 0, dmac_15_0),
+       OFFLOAD(SMAC_47_16, 32, U32_MAX, eth.h_source[0], 0, smac_47_16),
+       OFFLOAD(SMAC_15_0,  16, U16_MAX, eth.h_source[4], 0, smac_15_0),
+       OFFLOAD(ETHERTYPE,  16, U16_MAX, eth.h_proto, 0, ethertype),
+       OFFLOAD(FIRST_VID,  16, U16_MAX, vlan.h_vlan_TCI, 0, first_vid),
+
+       OFFLOAD(IP_DSCP, 8,    0xfc, ip4.tos,   0, ip_dscp),
+       OFFLOAD(IP_TTL,  8,  U8_MAX, ip4.ttl,   0, ttl_hoplimit),
+       OFFLOAD(SIPV4,  32, U32_MAX, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4),
+       OFFLOAD(DIPV4,  32, U32_MAX, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
+
+       OFFLOAD(SIPV6_127_96, 32, U32_MAX, ip6.saddr.s6_addr32[0], 0,
                src_ipv4_src_ipv6.ipv6_layout.ipv6[0]),
-       OFFLOAD(SIPV6_95_64,  4, ip6.saddr.s6_addr32[1], 0,
+       OFFLOAD(SIPV6_95_64,  32, U32_MAX, ip6.saddr.s6_addr32[1], 0,
                src_ipv4_src_ipv6.ipv6_layout.ipv6[4]),
-       OFFLOAD(SIPV6_63_32,  4, ip6.saddr.s6_addr32[2], 0,
+       OFFLOAD(SIPV6_63_32,  32, U32_MAX, ip6.saddr.s6_addr32[2], 0,
                src_ipv4_src_ipv6.ipv6_layout.ipv6[8]),
-       OFFLOAD(SIPV6_31_0,   4, ip6.saddr.s6_addr32[3], 0,
+       OFFLOAD(SIPV6_31_0,   32, U32_MAX, ip6.saddr.s6_addr32[3], 0,
                src_ipv4_src_ipv6.ipv6_layout.ipv6[12]),
-       OFFLOAD(DIPV6_127_96, 4, ip6.daddr.s6_addr32[0], 0,
+       OFFLOAD(DIPV6_127_96, 32, U32_MAX, ip6.daddr.s6_addr32[0], 0,
                dst_ipv4_dst_ipv6.ipv6_layout.ipv6[0]),
-       OFFLOAD(DIPV6_95_64,  4, ip6.daddr.s6_addr32[1], 0,
+       OFFLOAD(DIPV6_95_64,  32, U32_MAX, ip6.daddr.s6_addr32[1], 0,
                dst_ipv4_dst_ipv6.ipv6_layout.ipv6[4]),
-       OFFLOAD(DIPV6_63_32,  4, ip6.daddr.s6_addr32[2], 0,
+       OFFLOAD(DIPV6_63_32,  32, U32_MAX, ip6.daddr.s6_addr32[2], 0,
                dst_ipv4_dst_ipv6.ipv6_layout.ipv6[8]),
-       OFFLOAD(DIPV6_31_0,   4, ip6.daddr.s6_addr32[3], 0,
+       OFFLOAD(DIPV6_31_0,   32, U32_MAX, ip6.daddr.s6_addr32[3], 0,
                dst_ipv4_dst_ipv6.ipv6_layout.ipv6[12]),
-       OFFLOAD(IPV6_HOPLIMIT, 1, ip6.hop_limit, 0, ttl_hoplimit),
+       OFFLOAD(IPV6_HOPLIMIT, 8,  U8_MAX, ip6.hop_limit, 0, ttl_hoplimit),
 
-       OFFLOAD(TCP_SPORT, 2, tcp.source,  0, tcp_sport),
-       OFFLOAD(TCP_DPORT, 2, tcp.dest,    0, tcp_dport),
-       OFFLOAD(TCP_FLAGS, 1, tcp.ack_seq, 5, tcp_flags),
+       OFFLOAD(TCP_SPORT, 16, U16_MAX, tcp.source,  0, tcp_sport),
+       OFFLOAD(TCP_DPORT, 16, U16_MAX, tcp.dest,    0, tcp_dport),
+       /* in linux iphdr tcp_flags is 8 bits long */
+       OFFLOAD(TCP_FLAGS,  8,  U8_MAX, tcp.ack_seq, 5, tcp_flags),
 
-       OFFLOAD(UDP_SPORT, 2, udp.source, 0, udp_sport),
-       OFFLOAD(UDP_DPORT, 2, udp.dest,   0, udp_dport),
+       OFFLOAD(UDP_SPORT, 16, U16_MAX, udp.source, 0, udp_sport),
+       OFFLOAD(UDP_DPORT, 16, U16_MAX, udp.dest,   0, udp_dport),
 };
 
 /* On input attr->max_mod_hdr_actions tells how many HW actions can be parsed at
@@ -2312,19 +2335,17 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs,
                                struct netlink_ext_ack *extack)
 {
        struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals;
-       void *headers_c = get_match_headers_criteria(*action_flags,
-                                                    &parse_attr->spec);
-       void *headers_v = get_match_headers_value(*action_flags,
-                                                 &parse_attr->spec);
        int i, action_size, nactions, max_actions, first, last, next_z;
-       void *s_masks_p, *a_masks_p, *vals_p;
+       void *headers_c, *headers_v, *action, *vals_p;
+       u32 *s_masks_p, *a_masks_p, s_mask, a_mask;
        struct mlx5_fields *f;
-       u8 cmd, field_bsize;
-       u32 s_mask, a_mask;
        unsigned long mask;
        __be32 mask_be32;
        __be16 mask_be16;
-       void *action;
+       u8 cmd;
+
+       headers_c = get_match_headers_criteria(*action_flags, &parse_attr->spec);
+       headers_v = get_match_headers_value(*action_flags, &parse_attr->spec);
 
        set_masks = &hdrs[0].masks;
        add_masks = &hdrs[1].masks;
@@ -2349,8 +2370,8 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs,
                s_masks_p = (void *)set_masks + f->offset;
                a_masks_p = (void *)add_masks + f->offset;
 
-               memcpy(&s_mask, s_masks_p, f->size);
-               memcpy(&a_mask, a_masks_p, f->size);
+               s_mask = *s_masks_p & f->field_mask;
+               a_mask = *a_masks_p & f->field_mask;
 
                if (!s_mask && !a_mask) /* nothing to offload here */
                        continue;
@@ -2379,38 +2400,34 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs,
                        vals_p = (void *)set_vals + f->offset;
                        /* don't rewrite if we have a match on the same value */
                        if (cmp_val_mask(vals_p, s_masks_p, match_val,
-                                        match_mask, f->size))
+                                        match_mask, f->field_bsize))
                                skip = true;
                        /* clear to denote we consumed this field */
-                       memset(s_masks_p, 0, f->size);
+                       *s_masks_p &= ~f->field_mask;
                } else {
-                       u32 zero = 0;
-
                        cmd  = MLX5_ACTION_TYPE_ADD;
                        mask = a_mask;
                        vals_p = (void *)add_vals + f->offset;
                        /* add 0 is no change */
-                       if (!memcmp(vals_p, &zero, f->size))
+                       if ((*(u32 *)vals_p & f->field_mask) == 0)
                                skip = true;
                        /* clear to denote we consumed this field */
-                       memset(a_masks_p, 0, f->size);
+                       *a_masks_p &= ~f->field_mask;
                }
                if (skip)
                        continue;
 
-               field_bsize = f->size * BITS_PER_BYTE;
-
-               if (field_bsize == 32) {
+               if (f->field_bsize == 32) {
                        mask_be32 = *(__be32 *)&mask;
                        mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32));
-               } else if (field_bsize == 16) {
+               } else if (f->field_bsize == 16) {
                        mask_be16 = *(__be16 *)&mask;
                        mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16));
                }
 
-               first = find_first_bit(&mask, field_bsize);
-               next_z = find_next_zero_bit(&mask, field_bsize, first);
-               last  = find_last_bit(&mask, field_bsize);
+               first = find_first_bit(&mask, f->field_bsize);
+               next_z = find_next_zero_bit(&mask, f->field_bsize, first);
+               last  = find_last_bit(&mask, f->field_bsize);
                if (first < next_z && next_z < last) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "rewrite of few sub-fields isn't supported");
@@ -2423,16 +2440,22 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs,
                MLX5_SET(set_action_in, action, field, f->field);
 
                if (cmd == MLX5_ACTION_TYPE_SET) {
-                       MLX5_SET(set_action_in, action, offset, first);
+                       int start;
+
+                       /* if field is bit sized it can start not from first bit */
+                       start = find_first_bit((unsigned long *)&f->field_mask,
+                                              f->field_bsize);
+
+                       MLX5_SET(set_action_in, action, offset, first - start);
                        /* length is num of bits to be written, zero means length of 32 */
                        MLX5_SET(set_action_in, action, length, (last - first + 1));
                }
 
-               if (field_bsize == 32)
+               if (f->field_bsize == 32)
                        MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p) >> first);
-               else if (field_bsize == 16)
+               else if (f->field_bsize == 16)
                        MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p) >> first);
-               else if (field_bsize == 8)
+               else if (f->field_bsize == 8)
                        MLX5_SET(set_action_in, action, data, *(u8 *)vals_p >> first);
 
                action += action_size;
@@ -2955,6 +2978,13 @@ mlx5e_encap_get(struct mlx5e_priv *priv, struct encap_key *key,
        return NULL;
 }
 
+static struct ip_tunnel_info *dup_tun_info(const struct ip_tunnel_info *tun_info)
+{
+       size_t tun_size = sizeof(*tun_info) + tun_info->options_len;
+
+       return kmemdup(tun_info, tun_size, GFP_KERNEL);
+}
+
 static int mlx5e_attach_encap(struct mlx5e_priv *priv,
                              struct mlx5e_tc_flow *flow,
                              struct net_device *mirred_dev,
@@ -3011,13 +3041,15 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
        refcount_set(&e->refcnt, 1);
        init_completion(&e->res_ready);
 
+       tun_info = dup_tun_info(tun_info);
+       if (!tun_info) {
+               err = -ENOMEM;
+               goto out_err_init;
+       }
        e->tun_info = tun_info;
        err = mlx5e_tc_tun_init_encap_attr(mirred_dev, priv, e, extack);
-       if (err) {
-               kfree(e);
-               e = NULL;
-               goto out_err;
-       }
+       if (err)
+               goto out_err_init;
 
        INIT_LIST_HEAD(&e->flows);
        hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key);
@@ -3058,6 +3090,12 @@ out_err:
        if (e)
                mlx5e_encap_put(priv, e);
        return err;
+
+out_err_init:
+       mutex_unlock(&esw->offloads.encap_tbl_lock);
+       kfree(tun_info);
+       kfree(e);
+       return err;
 }
 
 static int parse_tc_vlan_action(struct mlx5e_priv *priv,
@@ -3143,7 +3181,7 @@ static int add_vlan_pop_action(struct mlx5e_priv *priv,
                               struct mlx5_esw_flow_attr *attr,
                               u32 *action)
 {
-       int nest_level = vlan_get_encap_level(attr->parse_attr->filter_dev);
+       int nest_level = attr->parse_attr->filter_dev->lower_level;
        struct flow_action_entry vlan_act = {
                .id = FLOW_ACTION_VLAN_POP,
        };
@@ -3278,7 +3316,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                        } else if (encap) {
                                parse_attr->mirred_ifindex[attr->out_count] =
                                        out_dev->ifindex;
-                               parse_attr->tun_info[attr->out_count] = info;
+                               parse_attr->tun_info[attr->out_count] = dup_tun_info(info);
+                               if (!parse_attr->tun_info[attr->out_count])
+                                       return -ENOMEM;
                                encap = false;
                                attr->dests[attr->out_count].flags |=
                                        MLX5_ESW_DEST_ENCAP;
@@ -3406,6 +3446,12 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
        }
 
+       if (!(attr->action &
+             (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+               NL_SET_ERR_MSG(extack, "Rule must have at least one forward/drop action");
+               return -EOPNOTSUPP;
+       }
+
        if (attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "current firmware doesn't support split rule for port mirroring");