net/mlx5e: TC, Refactor mlx5e_tc_add_flow_mod_hdr() to get flow attr
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index 3d908a7..9201ba8 100644 (file)
@@ -1038,6 +1038,21 @@ err_ft_get:
        return ERR_CAST(rule);
 }
 
+static int
+alloc_flow_attr_counter(struct mlx5_core_dev *counter_dev,
+                       struct mlx5_flow_attr *attr)
+
+{
+       struct mlx5_fc *counter;
+
+       counter = mlx5_fc_create(counter_dev, true);
+       if (IS_ERR(counter))
+               return PTR_ERR(counter);
+
+       attr->counter = counter;
+       return 0;
+}
+
 static int
 mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
                      struct mlx5e_tc_flow *flow,
@@ -1046,7 +1061,6 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5_flow_attr *attr = flow->attr;
        struct mlx5_core_dev *dev = priv->mdev;
-       struct mlx5_fc *counter;
        int err;
 
        parse_attr = attr->parse_attr;
@@ -1058,11 +1072,9 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
        }
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
-               counter = mlx5_fc_create(dev, true);
-               if (IS_ERR(counter))
-                       return PTR_ERR(counter);
-
-               attr->counter = counter;
+               err = alloc_flow_attr_counter(dev, attr);
+               if (err)
+                       return err;
        }
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
@@ -1348,10 +1360,10 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro
 }
 
 int mlx5e_tc_add_flow_mod_hdr(struct mlx5e_priv *priv,
-                             struct mlx5e_tc_flow_parse_attr *parse_attr,
-                             struct mlx5e_tc_flow *flow)
+                             struct mlx5e_tc_flow *flow,
+                             struct mlx5_flow_attr *attr)
 {
-       struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts = &parse_attr->mod_hdr_acts;
+       struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts = &attr->parse_attr->mod_hdr_acts;
        struct mlx5_modify_hdr *mod_hdr;
 
        mod_hdr = mlx5_modify_header_alloc(priv->mdev,
@@ -1361,12 +1373,100 @@ int mlx5e_tc_add_flow_mod_hdr(struct mlx5e_priv *priv,
        if (IS_ERR(mod_hdr))
                return PTR_ERR(mod_hdr);
 
-       WARN_ON(flow->attr->modify_hdr);
-       flow->attr->modify_hdr = mod_hdr;
+       WARN_ON(attr->modify_hdr);
+       attr->modify_hdr = mod_hdr;
 
        return 0;
 }
 
+static int
+set_encap_dests(struct mlx5e_priv *priv,
+               struct mlx5e_tc_flow *flow,
+               struct mlx5_flow_attr *attr,
+               struct netlink_ext_ack *extack,
+               bool *encap_valid,
+               bool *vf_tun)
+{
+       struct mlx5e_tc_flow_parse_attr *parse_attr;
+       struct mlx5_esw_flow_attr *esw_attr;
+       struct net_device *encap_dev = NULL;
+       struct mlx5e_rep_priv *rpriv;
+       struct mlx5e_priv *out_priv;
+       int out_index;
+       int err = 0;
+
+       parse_attr = attr->parse_attr;
+       esw_attr = attr->esw_attr;
+       *vf_tun = false;
+       *encap_valid = true;
+
+       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
+               struct net_device *out_dev;
+               int mirred_ifindex;
+
+               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
+                       continue;
+
+               mirred_ifindex = parse_attr->mirred_ifindex[out_index];
+               out_dev = dev_get_by_index(dev_net(priv->netdev), mirred_ifindex);
+               if (!out_dev) {
+                       NL_SET_ERR_MSG_MOD(extack, "Requested mirred device not found");
+                       err = -ENODEV;
+                       goto out;
+               }
+               err = mlx5e_attach_encap(priv, flow, attr, out_dev, out_index,
+                                        extack, &encap_dev, encap_valid);
+               dev_put(out_dev);
+               if (err)
+                       goto out;
+
+               if (esw_attr->dests[out_index].flags &
+                   MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
+                   !esw_attr->dest_int_port)
+                       *vf_tun = true;
+
+               out_priv = netdev_priv(encap_dev);
+               rpriv = out_priv->ppriv;
+               esw_attr->dests[out_index].rep = rpriv->rep;
+               esw_attr->dests[out_index].mdev = out_priv->mdev;
+       }
+
+       if (*vf_tun && esw_attr->out_count > 1) {
+               NL_SET_ERR_MSG_MOD(extack, "VF tunnel encap with mirroring is not supported");
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+out:
+       return err;
+}
+
+static void
+clean_encap_dests(struct mlx5e_priv *priv,
+                 struct mlx5e_tc_flow *flow,
+                 struct mlx5_flow_attr *attr,
+                 bool *vf_tun)
+{
+       struct mlx5_esw_flow_attr *esw_attr;
+       int out_index;
+
+       esw_attr = attr->esw_attr;
+       *vf_tun = false;
+
+       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
+               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
+                       continue;
+
+               if (esw_attr->dests[out_index].flags &
+                   MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
+                   !esw_attr->dest_int_port)
+                       *vf_tun = true;
+
+               mlx5e_detach_encap(priv, flow, attr, out_index);
+               kfree(attr->parse_attr->tun_info[out_index]);
+       }
+}
+
 static int
 mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                      struct mlx5e_tc_flow *flow,
@@ -1375,15 +1475,10 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5_flow_attr *attr = flow->attr;
-       bool vf_tun = false, encap_valid = true;
-       struct net_device *encap_dev = NULL;
        struct mlx5_esw_flow_attr *esw_attr;
-       struct mlx5e_rep_priv *rpriv;
-       struct mlx5e_priv *out_priv;
-       struct mlx5_fc *counter;
+       bool vf_tun, encap_valid;
        u32 max_prio, max_chain;
        int err = 0;
-       int out_index;
 
        parse_attr = attr->parse_attr;
        esw_attr = attr->esw_attr;
@@ -1471,41 +1566,9 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                esw_attr->int_port = int_port;
        }
 
-       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
-               struct net_device *out_dev;
-               int mirred_ifindex;
-
-               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
-                       continue;
-
-               mirred_ifindex = parse_attr->mirred_ifindex[out_index];
-               out_dev = dev_get_by_index(dev_net(priv->netdev), mirred_ifindex);
-               if (!out_dev) {
-                       NL_SET_ERR_MSG_MOD(extack, "Requested mirred device not found");
-                       err = -ENODEV;
-                       goto err_out;
-               }
-               err = mlx5e_attach_encap(priv, flow, out_dev, out_index,
-                                        extack, &encap_dev, &encap_valid);
-               dev_put(out_dev);
-               if (err)
-                       goto err_out;
-
-               if (esw_attr->dests[out_index].flags &
-                   MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
-                   !esw_attr->dest_int_port)
-                       vf_tun = true;
-               out_priv = netdev_priv(encap_dev);
-               rpriv = out_priv->ppriv;
-               esw_attr->dests[out_index].rep = rpriv->rep;
-               esw_attr->dests[out_index].mdev = out_priv->mdev;
-       }
-
-       if (vf_tun && esw_attr->out_count > 1) {
-               NL_SET_ERR_MSG_MOD(extack, "VF tunnel encap with mirroring is not supported");
-               err = -EOPNOTSUPP;
+       err = set_encap_dests(priv, flow, attr, extack, &encap_valid, &vf_tun);
+       if (err)
                goto err_out;
-       }
 
        err = mlx5_eswitch_add_vlan_action(esw, attr);
        if (err)
@@ -1514,7 +1577,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
            !(attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR)) {
                if (vf_tun) {
-                       err = mlx5e_tc_add_flow_mod_hdr(priv, parse_attr, flow);
+                       err = mlx5e_tc_add_flow_mod_hdr(priv, flow, attr);
                        if (err)
                                goto err_out;
                } else {
@@ -1525,13 +1588,9 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        }
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
-               counter = mlx5_fc_create(esw_attr->counter_dev, true);
-               if (IS_ERR(counter)) {
-                       err = PTR_ERR(counter);
+               err = alloc_flow_attr_counter(esw_attr->counter_dev, attr);
+               if (err)
                        goto err_out;
-               }
-
-               attr->counter = counter;
        }
 
        /* we get here if one of the following takes place:
@@ -1575,8 +1634,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct mlx5_flow_attr *attr = flow->attr;
        struct mlx5_esw_flow_attr *esw_attr;
-       bool vf_tun = false;
-       int out_index;
+       bool vf_tun;
 
        esw_attr = attr->esw_attr;
        mlx5e_put_flow_tunnel_id(flow);
@@ -1600,16 +1658,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
        if (flow->decap_route)
                mlx5e_detach_decap_route(priv, flow);
 
-       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
-               if (esw_attr->dests[out_index].flags &
-                   MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
-                   !esw_attr->dest_int_port)
-                       vf_tun = true;
-               if (esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP) {
-                       mlx5e_detach_encap(priv, flow, out_index);
-                       kfree(attr->parse_attr->tun_info[out_index]);
-               }
-       }
+       clean_encap_dests(priv, flow, attr, &vf_tun);
 
        mlx5_tc_ct_match_del(get_ct_priv(priv), &flow->attr->ct_attr);
 
@@ -2810,14 +2859,15 @@ static unsigned long mask_to_le(unsigned long mask, int size)
 
        return mask;
 }
+
 static int offload_pedit_fields(struct mlx5e_priv *priv,
                                int namespace,
-                               struct pedit_headers_action *hdrs,
                                struct mlx5e_tc_flow_parse_attr *parse_attr,
                                u32 *action_flags,
                                struct netlink_ext_ack *extack)
 {
        struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals;
+       struct pedit_headers_action *hdrs = parse_attr->hdrs;
        void *headers_c, *headers_v, *action, *vals_p;
        u32 *s_masks_p, *a_masks_p, s_mask, a_mask;
        struct mlx5e_tc_mod_hdr_acts *mod_acts;
@@ -2943,35 +2993,43 @@ static int offload_pedit_fields(struct mlx5e_priv *priv,
 
 static const struct pedit_headers zero_masks = {};
 
-static int alloc_tc_pedit_action(struct mlx5e_priv *priv, int namespace,
-                                struct mlx5e_tc_flow_parse_attr *parse_attr,
-                                struct pedit_headers_action *hdrs,
-                                u32 *action_flags,
-                                struct netlink_ext_ack *extack)
+static int verify_offload_pedit_fields(struct mlx5e_priv *priv,
+                                      struct mlx5e_tc_flow_parse_attr *parse_attr,
+                                      struct netlink_ext_ack *extack)
 {
        struct pedit_headers *cmd_masks;
-       int err;
        u8 cmd;
 
-       err = offload_pedit_fields(priv, namespace, hdrs, parse_attr,
-                                  action_flags, extack);
-       if (err < 0)
-               goto out_dealloc_parsed_actions;
-
        for (cmd = 0; cmd < __PEDIT_CMD_MAX; cmd++) {
-               cmd_masks = &hdrs[cmd].masks;
+               cmd_masks = &parse_attr->hdrs[cmd].masks;
                if (memcmp(cmd_masks, &zero_masks, sizeof(zero_masks))) {
-                       NL_SET_ERR_MSG_MOD(extack,
-                                          "attempt to offload an unsupported field");
+                       NL_SET_ERR_MSG_MOD(extack, "attempt to offload an unsupported field");
                        netdev_warn(priv->netdev, "attempt to offload an unsupported field (cmd %d)\n", cmd);
                        print_hex_dump(KERN_WARNING, "mask: ", DUMP_PREFIX_ADDRESS,
                                       16, 1, cmd_masks, sizeof(zero_masks), true);
-                       err = -EOPNOTSUPP;
-                       goto out_dealloc_parsed_actions;
+                       return -EOPNOTSUPP;
                }
        }
 
        return 0;
+}
+
+static int alloc_tc_pedit_action(struct mlx5e_priv *priv, int namespace,
+                                struct mlx5e_tc_flow_parse_attr *parse_attr,
+                                u32 *action_flags,
+                                struct netlink_ext_ack *extack)
+{
+       int err;
+
+       err = offload_pedit_fields(priv, namespace, parse_attr, action_flags, extack);
+       if (err)
+               goto out_dealloc_parsed_actions;
+
+       err = verify_offload_pedit_fields(priv, parse_attr, extack);
+       if (err)
+               goto out_dealloc_parsed_actions;
+
+       return 0;
 
 out_dealloc_parsed_actions:
        mlx5e_mod_hdr_dealloc(&parse_attr->mod_hdr_acts);
@@ -3244,7 +3302,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
                        return -EOPNOTSUPP;
                }
 
-               if (!tc_act->can_offload(parse_state, act, i))
+               if (!tc_act->can_offload(parse_state, act, i, attr))
                        return -EOPNOTSUPP;
 
                err = tc_act->parse_action(parse_state, act, priv, attr);
@@ -3255,7 +3313,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
        flow_action_for_each(i, act, flow_action) {
                tc_act = mlx5e_tc_act_get(act->id, ns_type);
                if (!tc_act || !tc_act->post_parse ||
-                   !tc_act->can_offload(parse_state, act, i))
+                   !tc_act->can_offload(parse_state, act, i, attr))
                        continue;
 
                err = tc_act->post_parse(parse_state, priv, attr);
@@ -3270,10 +3328,10 @@ static int
 actions_prepare_mod_hdr_actions(struct mlx5e_priv *priv,
                                struct mlx5e_tc_flow *flow,
                                struct mlx5_flow_attr *attr,
-                               struct pedit_headers_action *hdrs,
                                struct netlink_ext_ack *extack)
 {
        struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
+       struct pedit_headers_action *hdrs = parse_attr->hdrs;
        enum mlx5_flow_namespace_type ns_type;
        int err;
 
@@ -3283,8 +3341,7 @@ actions_prepare_mod_hdr_actions(struct mlx5e_priv *priv,
 
        ns_type = mlx5e_get_flow_namespace(flow);
 
-       err = alloc_tc_pedit_action(priv, ns_type, parse_attr, hdrs,
-                                   &attr->action, extack);
+       err = alloc_tc_pedit_action(priv, ns_type, parse_attr, &attr->action, extack);
        if (err)
                return err;
 
@@ -3332,7 +3389,6 @@ parse_tc_nic_actions(struct mlx5e_priv *priv,
        struct mlx5e_tc_act_parse_state *parse_state;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5_flow_attr *attr = flow->attr;
-       struct pedit_headers_action *hdrs;
        int err;
 
        err = flow_action_supported(flow_action, extack);
@@ -3344,13 +3400,12 @@ parse_tc_nic_actions(struct mlx5e_priv *priv,
        parse_state = &parse_attr->parse_state;
        mlx5e_tc_act_init_parse_state(parse_state, flow, flow_action, extack);
        parse_state->ct_priv = get_ct_priv(priv);
-       hdrs = parse_state->hdrs;
 
        err = parse_tc_actions(parse_state, flow_action);
        if (err)
                return err;
 
-       err = actions_prepare_mod_hdr_actions(priv, flow, attr, hdrs, extack);
+       err = actions_prepare_mod_hdr_actions(priv, flow, attr, extack);
        if (err)
                return err;
 
@@ -3455,7 +3510,6 @@ parse_tc_fdb_actions(struct mlx5e_priv *priv,
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5_flow_attr *attr = flow->attr;
        struct mlx5_esw_flow_attr *esw_attr;
-       struct pedit_headers_action *hdrs;
        int err;
 
        err = flow_action_supported(flow_action, extack);
@@ -3467,7 +3521,6 @@ parse_tc_fdb_actions(struct mlx5e_priv *priv,
        parse_state = &parse_attr->parse_state;
        mlx5e_tc_act_init_parse_state(parse_state, flow, flow_action, extack);
        parse_state->ct_priv = get_ct_priv(priv);
-       hdrs = parse_state->hdrs;
 
        err = parse_tc_actions(parse_state, flow_action);
        if (err)
@@ -3481,7 +3534,7 @@ parse_tc_fdb_actions(struct mlx5e_priv *priv,
                return -EOPNOTSUPP;
        }
 
-       err = actions_prepare_mod_hdr_actions(priv, flow, attr, hdrs, extack);
+       err = actions_prepare_mod_hdr_actions(priv, flow, attr, extack);
        if (err)
                return err;