net/mlx5: Refactor tc flow attributes structure
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index 4b810ad9d6d6a3e209a316f17d7b6ffc63a1d6c7..a54821107566e0d3c97f745ac874c9ea260cccc1 100644 (file)
 
 #define nic_chains(priv) ((priv)->fs.tc.chains)
 #define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)
-
-struct mlx5_nic_flow_attr {
-       u32 action;
-       u32 flow_tag;
-       struct mlx5_modify_hdr *modify_hdr;
-       u32 hairpin_tirn;
-       u8 match_level;
-       struct mlx5_flow_table  *hairpin_ft;
-       struct mlx5_fc          *counter;
-};
-
 #define MLX5E_TC_FLOW_BASE (MLX5E_TC_FLAG_LAST_EXPORTED_BIT + 1)
 
 enum {
@@ -154,11 +143,7 @@ struct mlx5e_tc_flow {
        struct rcu_head         rcu_head;
        struct completion       init_done;
        int tunnel_id; /* the mapped tunnel id of this flow */
-
-       union {
-               struct mlx5_esw_flow_attr esw_attr[0];
-               struct mlx5_nic_flow_attr nic_attr[0];
-       };
+       struct mlx5_flow_attr *attr;
 };
 
 struct mlx5e_tc_flow_parse_attr {
@@ -416,10 +401,7 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
                return PTR_ERR(mh);
 
        modify_hdr = mlx5e_mod_hdr_get(mh);
-       if (mlx5e_is_eswitch_flow(flow))
-               flow->esw_attr->modify_hdr = modify_hdr;
-       else
-               flow->nic_attr->modify_hdr = modify_hdr;
+       flow->attr->modify_hdr = modify_hdr;
        flow->mh = mh;
 
        return 0;
@@ -859,9 +841,9 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
 attach_flow:
        if (hpe->hp->num_channels > 1) {
                flow_flag_set(flow, HAIRPIN_RSS);
-               flow->nic_attr->hairpin_ft = hpe->hp->ttc.ft.t;
+               flow->attr->nic_attr->hairpin_ft = hpe->hp->ttc.ft.t;
        } else {
-               flow->nic_attr->hairpin_tirn = hpe->hp->tirn;
+               flow->attr->nic_attr->hairpin_tirn = hpe->hp->tirn;
        }
 
        flow->hpe = hpe;
@@ -894,9 +876,10 @@ static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv,
 struct mlx5_flow_handle *
 mlx5e_add_offloaded_nic_rule(struct mlx5e_priv *priv,
                             struct mlx5_flow_spec *spec,
-                            struct mlx5_nic_flow_attr *attr)
+                            struct mlx5_flow_attr *attr)
 {
        struct mlx5_flow_context *flow_context = &spec->flow_context;
+       struct mlx5_nic_flow_attr *nic_attr = attr->nic_attr;
        struct mlx5e_tc_table *tc = &priv->fs.tc;
        struct mlx5_flow_destination dest[2] = {};
        struct mlx5_flow_act flow_act = {
@@ -907,15 +890,15 @@ mlx5e_add_offloaded_nic_rule(struct mlx5e_priv *priv,
        int dest_ix = 0;
 
        flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
-       flow_context->flow_tag = attr->flow_tag;
+       flow_context->flow_tag = nic_attr->flow_tag;
 
-       if (attr->hairpin_ft) {
+       if (nic_attr->hairpin_ft) {
                dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
-               dest[dest_ix].ft = attr->hairpin_ft;
+               dest[dest_ix].ft = nic_attr->hairpin_ft;
                dest_ix++;
-       } else if (attr->hairpin_tirn) {
+       } else if (nic_attr->hairpin_tirn) {
                dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_TIR;
-               dest[dest_ix].tir_num = attr->hairpin_tirn;
+               dest[dest_ix].tir_num = nic_attr->hairpin_tirn;
                dest_ix++;
        } else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
                dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
@@ -947,7 +930,7 @@ mlx5e_add_offloaded_nic_rule(struct mlx5e_priv *priv,
        }
        mutex_unlock(&tc->t_lock);
 
-       if (attr->match_level != MLX5_MATCH_NONE)
+       if (attr->outer_match_level != MLX5_MATCH_NONE)
                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
 
        rule = mlx5_add_flow_rules(tc->t, spec,
@@ -964,7 +947,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
                      struct mlx5e_tc_flow *flow,
                      struct netlink_ext_ack *extack)
 {
-       struct mlx5_nic_flow_attr *attr = flow->nic_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
        struct mlx5_core_dev *dev = priv->mdev;
        struct mlx5_fc *counter = NULL;
        int err;
@@ -1005,7 +988,7 @@ void mlx5e_del_offloaded_nic_rule(struct mlx5e_priv *priv,
 static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
                                  struct mlx5e_tc_flow *flow)
 {
-       struct mlx5_nic_flow_attr *attr = flow->nic_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
        struct mlx5e_tc_table *tc = &priv->fs.tc;
 
        if (!IS_ERR_OR_NULL(flow->rule[0]))
@@ -1025,6 +1008,8 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
 
        if (flow_flag_test(flow, HAIRPIN))
                mlx5e_hairpin_flow_del(priv, flow);
+
+       kfree(flow->attr);
 }
 
 static void mlx5e_detach_encap(struct mlx5e_priv *priv,
@@ -1047,7 +1032,7 @@ static struct mlx5_flow_handle *
 mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
                           struct mlx5e_tc_flow *flow,
                           struct mlx5_flow_spec *spec,
-                          struct mlx5_esw_flow_attr *attr)
+                          struct mlx5_flow_attr *attr)
 {
        struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts;
        struct mlx5_flow_handle *rule;
@@ -1063,7 +1048,7 @@ mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
        if (IS_ERR(rule))
                return rule;
 
-       if (attr->split_count) {
+       if (attr->esw_attr->split_count) {
                flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, spec, attr);
                if (IS_ERR(flow->rule[1])) {
                        mlx5_eswitch_del_offloaded_rule(esw, rule, attr);
@@ -1077,7 +1062,7 @@ mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
 static void
 mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
                             struct mlx5e_tc_flow *flow,
-                            struct mlx5_esw_flow_attr *attr)
+                            struct mlx5_flow_attr *attr)
 {
        flow_flag_clear(flow, OFFLOADED);
 
@@ -1086,7 +1071,7 @@ mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
                return;
        }
 
-       if (attr->split_count)
+       if (attr->esw_attr->split_count)
                mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr);
 
        mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
@@ -1097,18 +1082,24 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw,
                              struct mlx5e_tc_flow *flow,
                              struct mlx5_flow_spec *spec)
 {
-       struct mlx5_esw_flow_attr slow_attr;
+       struct mlx5_flow_attr *slow_attr;
        struct mlx5_flow_handle *rule;
 
-       memcpy(&slow_attr, flow->esw_attr, sizeof(slow_attr));
-       slow_attr.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
-       slow_attr.split_count = 0;
-       slow_attr.flags |= MLX5_ESW_ATTR_FLAG_SLOW_PATH;
+       slow_attr = mlx5_alloc_flow_attr(MLX5_FLOW_NAMESPACE_FDB);
+       if (!slow_attr)
+               return ERR_PTR(-ENOMEM);
 
-       rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, &slow_attr);
+       memcpy(slow_attr, flow->attr, ESW_FLOW_ATTR_SZ);
+       slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       slow_attr->esw_attr->split_count = 0;
+       slow_attr->flags |= MLX5_ESW_ATTR_FLAG_SLOW_PATH;
+
+       rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr);
        if (!IS_ERR(rule))
                flow_flag_set(flow, SLOW);
 
+       kfree(slow_attr);
+
        return rule;
 }
 
@@ -1116,14 +1107,19 @@ static void
 mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw,
                                  struct mlx5e_tc_flow *flow)
 {
-       struct mlx5_esw_flow_attr slow_attr;
+       struct mlx5_flow_attr *slow_attr;
 
-       memcpy(&slow_attr, flow->esw_attr, sizeof(slow_attr));
-       slow_attr.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
-       slow_attr.split_count = 0;
-       slow_attr.flags |= MLX5_ESW_ATTR_FLAG_SLOW_PATH;
-       mlx5e_tc_unoffload_fdb_rules(esw, flow, &slow_attr);
+       slow_attr = mlx5_alloc_flow_attr(MLX5_FLOW_NAMESPACE_FDB);
+       if (!slow_attr)
+               mlx5_core_warn(flow->priv->mdev, "Unable to unoffload slow path rule\n");
+
+       memcpy(slow_attr, flow->attr, ESW_FLOW_ATTR_SZ);
+       slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       slow_attr->esw_attr->split_count = 0;
+       slow_attr->flags |= MLX5_ESW_ATTR_FLAG_SLOW_PATH;
+       mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr);
        flow_flag_clear(flow, SLOW);
+       kfree(slow_attr);
 }
 
 /* Caller must obtain uplink_priv->unready_flows_lock mutex before calling this
@@ -1181,9 +1177,10 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                      struct netlink_ext_ack *extack)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
-       struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
        struct net_device *out_dev, *encap_dev = NULL;
+       struct mlx5e_tc_flow_parse_attr *parse_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
+       struct mlx5_esw_flow_attr *esw_attr;
        struct mlx5_fc *counter = NULL;
        struct mlx5e_rep_priv *rpriv;
        struct mlx5e_priv *out_priv;
@@ -1223,10 +1220,13 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                        return err;
        }
 
+       parse_attr = attr->parse_attr;
+       esw_attr = attr->esw_attr;
+
        for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
                int mirred_ifindex;
 
-               if (!(attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
+               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
                        continue;
 
                mirred_ifindex = parse_attr->mirred_ifindex[out_index];
@@ -1239,8 +1239,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
 
                out_priv = netdev_priv(encap_dev);
                rpriv = out_priv->ppriv;
-               attr->dests[out_index].rep = rpriv->rep;
-               attr->dests[out_index].mdev = out_priv->mdev;
+               esw_attr->dests[out_index].rep = rpriv->rep;
+               esw_attr->dests[out_index].mdev = out_priv->mdev;
        }
 
        err = mlx5_eswitch_add_vlan_action(esw, attr);
@@ -1256,7 +1256,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        }
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
-               counter = mlx5_fc_create(attr->counter_dev, true);
+               counter = mlx5_fc_create(esw_attr->counter_dev, true);
                if (IS_ERR(counter))
                        return PTR_ERR(counter);
 
@@ -1282,7 +1282,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
 
 static bool mlx5_flow_has_geneve_opt(struct mlx5e_tc_flow *flow)
 {
-       struct mlx5_flow_spec *spec = &flow->esw_attr->parse_attr->spec;
+       struct mlx5_flow_spec *spec = &flow->attr->parse_attr->spec;
        void *headers_v = MLX5_ADDR_OF(fte_match_param,
                                       spec->match_value,
                                       misc_parameters_3);
@@ -1297,7 +1297,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
                                  struct mlx5e_tc_flow *flow)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
        int out_index;
 
        mlx5e_put_flow_tunnel_id(flow);
@@ -1318,22 +1318,24 @@ 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->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]);
                }
        kvfree(attr->parse_attr);
 
-       mlx5_tc_ct_match_del(priv, &flow->esw_attr->ct_attr);
+       mlx5_tc_ct_match_del(priv, &flow->attr->ct_attr);
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                mlx5e_detach_mod_hdr(priv, flow);
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
-               mlx5_fc_destroy(attr->counter_dev, attr->counter);
+               mlx5_fc_destroy(attr->esw_attr->counter_dev, attr->counter);
 
        if (flow_flag_test(flow, L3_TO_L2_DECAP))
                mlx5e_detach_decap(priv, flow);
+
+       kfree(flow->attr);
 }
 
 void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
@@ -1343,6 +1345,7 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct mlx5_esw_flow_attr *esw_attr;
        struct mlx5_flow_handle *rule;
+       struct mlx5_flow_attr *attr;
        struct mlx5_flow_spec *spec;
        struct mlx5e_tc_flow *flow;
        int err;
@@ -1365,8 +1368,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
 
                if (!mlx5e_is_offloaded_flow(flow))
                        continue;
-               esw_attr = flow->esw_attr;
-               spec = &esw_attr->parse_attr->spec;
+               attr = flow->attr;
+               esw_attr = attr->esw_attr;
+               spec = &attr->parse_attr->spec;
 
                esw_attr->dests[flow->tmp_efi_index].pkt_reformat = e->pkt_reformat;
                esw_attr->dests[flow->tmp_efi_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
@@ -1386,7 +1390,7 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
                if (!all_flow_encaps_valid)
                        continue;
                /* update from slow path rule to encap rule */
-               rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr);
+               rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, attr);
                if (IS_ERR(rule)) {
                        err = PTR_ERR(rule);
                        mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
@@ -1406,7 +1410,9 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
                              struct list_head *flow_list)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       struct mlx5_esw_flow_attr *esw_attr;
        struct mlx5_flow_handle *rule;
+       struct mlx5_flow_attr *attr;
        struct mlx5_flow_spec *spec;
        struct mlx5e_tc_flow *flow;
        int err;
@@ -1414,12 +1420,14 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
        list_for_each_entry(flow, flow_list, tmp_list) {
                if (!mlx5e_is_offloaded_flow(flow))
                        continue;
-               spec = &flow->esw_attr->parse_attr->spec;
+               attr = flow->attr;
+               esw_attr = attr->esw_attr;
+               spec = &attr->parse_attr->spec;
 
                /* update from encap rule to slow path rule */
                rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec);
                /* mark the flow's encap dest as non-valid */
-               flow->esw_attr->dests[flow->tmp_efi_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
+               esw_attr->dests[flow->tmp_efi_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
 
                if (IS_ERR(rule)) {
                        err = PTR_ERR(rule);
@@ -1428,7 +1436,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
                        continue;
                }
 
-               mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr);
+               mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
                flow->rule[0] = rule;
                /* was unset when fast path rule removed */
                flow_flag_set(flow, OFFLOADED);
@@ -1441,10 +1449,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
 
 static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow)
 {
-       if (mlx5e_is_eswitch_flow(flow))
-               return flow->esw_attr->counter;
-       else
-               return flow->nic_attr->counter;
+       return flow->attr->counter;
 }
 
 /* Takes reference to all flows attached to encap and adds the flows to
@@ -1810,11 +1815,11 @@ static int mlx5e_get_flow_tunnel_id(struct mlx5e_priv *priv,
 {
        struct flow_rule *rule = flow_cls_offload_flow_rule(f);
        struct netlink_ext_ack *extack = f->common.extack;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
        struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts;
        struct flow_match_enc_opts enc_opts_match;
        struct tunnel_match_enc_opts tun_enc_opts;
        struct mlx5_rep_uplink_priv *uplink_priv;
+       struct mlx5_flow_attr *attr = flow->attr;
        struct mlx5e_rep_priv *uplink_rpriv;
        struct tunnel_match_key tunnel_key;
        bool enc_opts_is_dont_care = true;
@@ -1964,8 +1969,8 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
        if (!mlx5e_is_eswitch_flow(flow))
                return -EOPNOTSUPP;
 
-       needs_mapping = !!flow->esw_attr->chain;
-       sets_mapping = !flow->esw_attr->chain && flow_has_tc_fwd_action(f);
+       needs_mapping = !!flow->attr->chain;
+       sets_mapping = !flow->attr->chain && flow_has_tc_fwd_action(f);
        *match_inner = !needs_mapping;
 
        if ((needs_mapping || sets_mapping) &&
@@ -1977,7 +1982,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
                return -EOPNOTSUPP;
        }
 
-       if (!flow->esw_attr->chain) {
+       if (!flow->attr->chain) {
                err = mlx5e_tc_tun_parse(filter_dev, priv, spec, f,
                                         match_level);
                if (err) {
@@ -1992,7 +1997,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
                 * object
                 */
                if (!netif_is_bareudp(filter_dev))
-                       flow->esw_attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
+                       flow->attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
        }
 
        if (!needs_mapping && !sets_mapping)
@@ -2495,12 +2500,9 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
                }
        }
 
-       if (is_eswitch_flow) {
-               flow->esw_attr->inner_match_level = inner_match_level;
-               flow->esw_attr->outer_match_level = outer_match_level;
-       } else {
-               flow->nic_attr->match_level = non_tunnel_match_level;
-       }
+       flow->attr->inner_match_level = inner_match_level;
+       flow->attr->outer_match_level = outer_match_level;
+
 
        return err;
 }
@@ -3134,12 +3136,13 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
        bool ct_flow = false, ct_clear = false;
        u32 actions;
 
+       ct_clear = flow->attr->ct_attr.ct_action &
+               TCA_CT_ACT_CLEAR;
+       ct_flow = flow_flag_test(flow, CT) && !ct_clear;
+       actions = flow->attr->action;
+
        if (mlx5e_is_eswitch_flow(flow)) {
-               actions = flow->esw_attr->action;
-               ct_clear = flow->esw_attr->ct_attr.ct_action &
-                          TCA_CT_ACT_CLEAR;
-               ct_flow = flow_flag_test(flow, CT) && !ct_clear;
-               if (flow->esw_attr->split_count && ct_flow) {
+               if (flow->attr->esw_attr->split_count && ct_flow) {
                        /* All registers used by ct are cleared when using
                         * split rules.
                         */
@@ -3147,8 +3150,6 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
                                           "Can't offload mirroring with action ct");
                        return false;
                }
-       } else {
-               actions = flow->nic_attr->action;
        }
 
        if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
@@ -3252,9 +3253,10 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
                                struct mlx5e_tc_flow *flow,
                                struct netlink_ext_ack *extack)
 {
-       struct mlx5_nic_flow_attr *attr = flow->nic_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
        struct pedit_headers_action hdrs[2] = {};
        const struct flow_action_entry *act;
+       struct mlx5_nic_flow_attr *nic_attr;
        u32 action = 0;
        int err, i;
 
@@ -3265,7 +3267,9 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
                                        FLOW_ACTION_HW_STATS_DELAYED_BIT))
                return -EOPNOTSUPP;
 
-       attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
+       nic_attr = attr->nic_attr;
+
+       nic_attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
 
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
@@ -3332,7 +3336,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
                                return -EINVAL;
                        }
 
-                       attr->flow_tag = mark;
+                       nic_attr->flow_tag = mark;
                        action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
                        }
                        break;
@@ -3489,8 +3493,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
                              bool *encap_valid)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
        const struct ip_tunnel_info *tun_info;
        struct encap_key key;
        struct mlx5e_encap_entry *e;
@@ -3576,8 +3580,8 @@ attach_flow:
        flow->encaps[out_index].index = out_index;
        *encap_dev = e->out_dev;
        if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
-               attr->dests[out_index].pkt_reformat = e->pkt_reformat;
-               attr->dests[out_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
+               attr->esw_attr->dests[out_index].pkt_reformat = e->pkt_reformat;
+               attr->esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
                *encap_valid = true;
        } else {
                *encap_valid = false;
@@ -3604,14 +3608,14 @@ static int mlx5e_attach_decap(struct mlx5e_priv *priv,
                              struct netlink_ext_ack *extack)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
+       struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5e_decap_entry *d;
        struct mlx5e_decap_key key;
        uintptr_t hash_key;
        int err = 0;
 
-       parse_attr = attr->parse_attr;
+       parse_attr = flow->attr->parse_attr;
        if (sizeof(parse_attr->eth) > MLX5_CAP_ESW(priv->mdev, max_encap_header_size)) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "encap header larger than max supported");
@@ -3753,7 +3757,7 @@ static struct net_device *get_fdb_out_dev(struct net_device *uplink_dev,
 }
 
 static int add_vlan_push_action(struct mlx5e_priv *priv,
-                               struct mlx5_esw_flow_attr *attr,
+                               struct mlx5_flow_attr *attr,
                                struct net_device **out_dev,
                                u32 *action)
 {
@@ -3766,7 +3770,7 @@ static int add_vlan_push_action(struct mlx5e_priv *priv,
        };
        int err;
 
-       err = parse_tc_vlan_action(priv, &vlan_act, attr, action);
+       err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, action);
        if (err)
                return err;
 
@@ -3779,7 +3783,7 @@ static int add_vlan_push_action(struct mlx5e_priv *priv,
 }
 
 static int add_vlan_pop_action(struct mlx5e_priv *priv,
-                              struct mlx5_esw_flow_attr *attr,
+                              struct mlx5_flow_attr *attr,
                               u32 *action)
 {
        struct flow_action_entry vlan_act = {
@@ -3790,7 +3794,7 @@ static int add_vlan_pop_action(struct mlx5e_priv *priv,
        nest_level = attr->parse_attr->filter_dev->lower_level -
                                                priv->netdev->lower_level;
        while (nest_level--) {
-               err = parse_tc_vlan_action(priv, &vlan_act, attr, action);
+               err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, action);
                if (err)
                        return err;
        }
@@ -3858,7 +3862,7 @@ static int mlx5_validate_goto_chain(struct mlx5_eswitch *esw,
                                    struct netlink_ext_ack *extack)
 {
        u32 max_chain = mlx5_chains_get_chain_range(esw_chains(esw));
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
        bool ft_flow = mlx5e_is_ft_flow(flow);
        u32 dest_chain = act->chain_index;
 
@@ -3895,15 +3899,15 @@ static int verify_uplink_forwarding(struct mlx5e_priv *priv,
                                    struct net_device *out_dev,
                                    struct netlink_ext_ack *extack)
 {
+       struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
        struct mlx5e_rep_priv *rep_priv;
 
        /* Forwarding non encapsulated traffic between
         * uplink ports is allowed only if
         * termination_table_raw_traffic cap is set.
         *
-        * Input vport was stored esw_attr->in_rep.
+        * Input vport was stored attr->in_rep.
         * In LAG case, *priv* is the private data of
         * uplink which may be not the input vport.
         */
@@ -3938,13 +3942,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
 {
        struct pedit_headers_action hdrs[2] = {};
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
-       struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
+       struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        const struct ip_tunnel_info *info = NULL;
+       struct mlx5_flow_attr *attr = flow->attr;
        int ifindexes[MLX5_MAX_FLOW_FWD_VPORTS];
        bool ft_flow = mlx5e_is_ft_flow(flow);
        const struct flow_action_entry *act;
+       struct mlx5_esw_flow_attr *esw_attr;
        bool encap = false, decap = false;
        u32 action = attr->action;
        int err, i, if_count = 0;
@@ -3957,6 +3962,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                                        FLOW_ACTION_HW_STATS_DELAYED_BIT))
                return -EOPNOTSUPP;
 
+       esw_attr = attr->esw_attr;
+       parse_attr = attr->parse_attr;
+
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_DROP:
@@ -4013,7 +4021,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
 
                        if (!flow_flag_test(flow, L3_TO_L2_DECAP)) {
                                action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
-                               attr->split_count = attr->out_count;
+                               esw_attr->split_count = esw_attr->out_count;
                        }
                        break;
                case FLOW_ACTION_CSUM:
@@ -4050,27 +4058,27 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                                return -EOPNOTSUPP;
                        }
 
-                       if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
+                       if (esw_attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
                                NL_SET_ERR_MSG_MOD(extack,
                                                   "can't support more output ports, can't offload forwarding");
                                netdev_warn(priv->netdev,
                                            "can't support more than %d output ports, can't offload forwarding\n",
-                                           attr->out_count);
+                                           esw_attr->out_count);
                                return -EOPNOTSUPP;
                        }
 
                        action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
                                  MLX5_FLOW_CONTEXT_ACTION_COUNT;
                        if (encap) {
-                               parse_attr->mirred_ifindex[attr->out_count] =
+                               parse_attr->mirred_ifindex[esw_attr->out_count] =
                                        out_dev->ifindex;
-                               parse_attr->tun_info[attr->out_count] = dup_tun_info(info);
-                               if (!parse_attr->tun_info[attr->out_count])
+                               parse_attr->tun_info[esw_attr->out_count] = dup_tun_info(info);
+                               if (!parse_attr->tun_info[esw_attr->out_count])
                                        return -ENOMEM;
                                encap = false;
-                               attr->dests[attr->out_count].flags |=
+                               esw_attr->dests[esw_attr->out_count].flags |=
                                        MLX5_ESW_DEST_ENCAP;
-                               attr->out_count++;
+                               esw_attr->out_count++;
                                /* attr->dests[].rep is resolved when we
                                 * handle encap
                                 */
@@ -4119,9 +4127,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
 
                                out_priv = netdev_priv(out_dev);
                                rpriv = out_priv->ppriv;
-                               attr->dests[attr->out_count].rep = rpriv->rep;
-                               attr->dests[attr->out_count].mdev = out_priv->mdev;
-                               attr->out_count++;
+                               esw_attr->dests[esw_attr->out_count].rep = rpriv->rep;
+                               esw_attr->dests[esw_attr->out_count].mdev = out_priv->mdev;
+                               esw_attr->out_count++;
                        } else if (parse_attr->filter_dev != priv->netdev) {
                                /* All mlx5 devices are called to configure
                                 * high level device filters. Therefore, the
@@ -4159,12 +4167,12 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                                                              act, parse_attr, hdrs,
                                                              &action, extack);
                        } else {
-                               err = parse_tc_vlan_action(priv, act, attr, &action);
+                               err = parse_tc_vlan_action(priv, act, esw_attr, &action);
                        }
                        if (err)
                                return err;
 
-                       attr->split_count = attr->out_count;
+                       esw_attr->split_count = esw_attr->out_count;
                        break;
                case FLOW_ACTION_VLAN_MANGLE:
                        err = add_vlan_rewrite_action(priv,
@@ -4174,7 +4182,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                        if (err)
                                return err;
 
-                       attr->split_count = attr->out_count;
+                       esw_attr->split_count = esw_attr->out_count;
                        break;
                case FLOW_ACTION_TUNNEL_DECAP:
                        decap = true;
@@ -4228,7 +4236,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                        dealloc_mod_hdr_actions(&parse_attr->mod_hdr_acts);
                        if (!((action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) ||
                              (action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH)))
-                               attr->split_count = 0;
+                               esw_attr->split_count = 0;
                }
        }
 
@@ -4268,7 +4276,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                return -EOPNOTSUPP;
        }
 
-       if (attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
+       if (esw_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");
                netdev_warn_once(priv->netdev, "current firmware doesn't support split rule for port mirroring\n");
@@ -4319,25 +4327,37 @@ static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv,
 
 static bool is_peer_flow_needed(struct mlx5e_tc_flow *flow)
 {
-       struct mlx5_esw_flow_attr *attr = flow->esw_attr;
-       bool is_rep_ingress = attr->in_rep->vport != MLX5_VPORT_UPLINK &&
+       struct mlx5_esw_flow_attr *esw_attr = flow->attr->esw_attr;
+       struct mlx5_flow_attr *attr = flow->attr;
+       bool is_rep_ingress = esw_attr->in_rep->vport != MLX5_VPORT_UPLINK &&
                flow_flag_test(flow, INGRESS);
        bool act_is_encap = !!(attr->action &
                               MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT);
-       bool esw_paired = mlx5_devcom_is_paired(attr->in_mdev->priv.devcom,
+       bool esw_paired = mlx5_devcom_is_paired(esw_attr->in_mdev->priv.devcom,
                                                MLX5_DEVCOM_ESW_OFFLOADS);
 
        if (!esw_paired)
                return false;
 
-       if ((mlx5_lag_is_sriov(attr->in_mdev) ||
-            mlx5_lag_is_multipath(attr->in_mdev)) &&
+       if ((mlx5_lag_is_sriov(esw_attr->in_mdev) ||
+            mlx5_lag_is_multipath(esw_attr->in_mdev)) &&
            (is_rep_ingress || act_is_encap))
                return true;
 
        return false;
 }
 
+struct mlx5_flow_attr *
+mlx5_alloc_flow_attr(enum mlx5_flow_namespace_type type)
+{
+       u32 ex_attr_size = (type == MLX5_FLOW_NAMESPACE_FDB)  ?
+                               sizeof(struct mlx5_esw_flow_attr) :
+                               sizeof(struct mlx5_nic_flow_attr);
+       struct mlx5_flow_attr *attr;
+
+       return kzalloc(sizeof(*attr) + ex_attr_size, GFP_KERNEL);
+}
+
 static int
 mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
                 struct flow_cls_offload *f, unsigned long flow_flags,
@@ -4345,19 +4365,24 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
                 struct mlx5e_tc_flow **__flow)
 {
        struct mlx5e_tc_flow_parse_attr *parse_attr;
+       struct mlx5_flow_attr *attr;
        struct mlx5e_tc_flow *flow;
        int out_index, err;
 
-       flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL);
+       flow = kzalloc(sizeof(*flow), GFP_KERNEL);
        parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL);
-       if (!parse_attr || !flow) {
+
+       flow->flags = flow_flags;
+       flow->cookie = f->cookie;
+       flow->priv = priv;
+
+       attr = mlx5_alloc_flow_attr(get_flow_name_space(flow));
+       if (!parse_attr || !flow || !attr) {
                err = -ENOMEM;
                goto err_free;
        }
+       flow->attr = attr;
 
-       flow->cookie = f->cookie;
-       flow->flags = flow_flags;
-       flow->priv = priv;
        for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
                INIT_LIST_HEAD(&flow->encaps[out_index].list);
        INIT_LIST_HEAD(&flow->hairpin);
@@ -4373,11 +4398,12 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
 err_free:
        kfree(flow);
        kvfree(parse_attr);
+       kfree(attr);
        return err;
 }
 
 static void
-mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
+mlx5e_flow_esw_attr_init(struct mlx5_flow_attr *attr,
                         struct mlx5e_priv *priv,
                         struct mlx5e_tc_flow_parse_attr *parse_attr,
                         struct flow_cls_offload *f,
@@ -4385,10 +4411,11 @@ mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
                         struct mlx5_core_dev *in_mdev)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 
-       esw_attr->parse_attr = parse_attr;
-       esw_attr->chain = f->common.chain_index;
-       esw_attr->prio = f->common.prio;
+       attr->parse_attr = parse_attr;
+       attr->chain = f->common.chain_index;
+       attr->prio = f->common.prio;
 
        esw_attr->in_rep = in_rep;
        esw_attr->in_mdev = in_mdev;
@@ -4422,7 +4449,7 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
                goto out;
 
        parse_attr->filter_dev = filter_dev;
-       mlx5e_flow_esw_attr_init(flow->esw_attr,
+       mlx5e_flow_esw_attr_init(flow->attr,
                                 priv, parse_attr,
                                 f, in_rep, in_mdev);
 
@@ -4433,7 +4460,7 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
 
        /* actions validation depends on parsing the ct matches first */
        err = mlx5_tc_ct_match_add(priv, &parse_attr->spec, f,
-                                  &flow->esw_attr->ct_attr, extack);
+                                  &flow->attr->ct_attr, extack);
        if (err)
                goto err_free;
 
@@ -4464,6 +4491,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
 {
        struct mlx5e_priv *priv = flow->priv, *peer_priv;
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch, *peer_esw;
+       struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
        struct mlx5_devcom *devcom = priv->mdev->priv.devcom;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5e_rep_priv *peer_urpriv;
@@ -4483,15 +4511,15 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
         * original flow and packets redirected from uplink use the
         * peer mdev.
         */
-       if (flow->esw_attr->in_rep->vport == MLX5_VPORT_UPLINK)
+       if (attr->in_rep->vport == MLX5_VPORT_UPLINK)
                in_mdev = peer_priv->mdev;
        else
                in_mdev = priv->mdev;
 
-       parse_attr = flow->esw_attr->parse_attr;
+       parse_attr = flow->attr->parse_attr;
        peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags,
                                         parse_attr->filter_dev,
-                                        flow->esw_attr->in_rep, in_mdev);
+                                        attr->in_rep, in_mdev);
        if (IS_ERR(peer_flow)) {
                err = PTR_ERR(peer_flow);
                goto out;