]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
net/mlx5e: Remove flow encap entry in the correct place
[karo-tx-linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_tc.c
index 4b991124bc57b23c3bacc46b20bb61b54aad4e12..f07ef8c7da559985112d202cf9b26e2b82d4b3ca 100644 (file)
@@ -142,19 +142,39 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
        return mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
 }
 
+static void mlx5e_detach_encap(struct mlx5e_priv *priv,
+                              struct mlx5e_tc_flow *flow) {
+       struct list_head *next = flow->encap.next;
+
+       list_del(&flow->encap);
+       if (list_empty(next)) {
+               struct mlx5_encap_entry *e;
+
+               e = list_entry(next, struct mlx5_encap_entry, flows);
+               if (e->n) {
+                       mlx5_encap_dealloc(priv->mdev, e->encap_id);
+                       neigh_release(e->n);
+               }
+               hlist_del_rcu(&e->encap_hlist);
+               kfree(e);
+       }
+}
+
 static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
-                             struct mlx5_flow_handle *rule,
-                             struct mlx5_esw_flow_attr *attr)
+                             struct mlx5e_tc_flow *flow)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct mlx5_fc *counter = NULL;
 
-       counter = mlx5_flow_rule_counter(rule);
+       counter = mlx5_flow_rule_counter(flow->rule);
 
-       if (esw && esw->mode == SRIOV_OFFLOADS)
-               mlx5_eswitch_del_vlan_action(esw, attr);
+       mlx5_del_flow_rules(flow->rule);
 
-       mlx5_del_flow_rules(rule);
+       if (esw && esw->mode == SRIOV_OFFLOADS) {
+               mlx5_eswitch_del_vlan_action(esw, flow->attr);
+               if (flow->attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
+                       mlx5e_detach_encap(priv, flow);
+       }
 
        mlx5_fc_destroy(priv->mdev, counter);
 
@@ -279,8 +299,10 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
        return 0;
 }
 
-static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec,
-                           struct tc_cls_flower_offload *f)
+static int __parse_cls_flower(struct mlx5e_priv *priv,
+                             struct mlx5_flow_spec *spec,
+                             struct tc_cls_flower_offload *f,
+                             u8 *min_inline)
 {
        void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
                                       outer_headers);
@@ -289,6 +311,8 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
        u16 addr_type = 0;
        u8 ip_proto = 0;
 
+       *min_inline = MLX5_INLINE_MODE_L2;
+
        if (f->dissector->used_keys &
            ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
              BIT(FLOW_DISSECTOR_KEY_BASIC) |
@@ -362,6 +386,9 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
                         mask->ip_proto);
                MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
                         key->ip_proto);
+
+               if (mask->ip_proto)
+                       *min_inline = MLX5_INLINE_MODE_IP;
        }
 
        if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
@@ -432,6 +459,9 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
                memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
                                    dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
                       &key->dst, sizeof(key->dst));
+
+               if (mask->src || mask->dst)
+                       *min_inline = MLX5_INLINE_MODE_IP;
        }
 
        if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
@@ -457,6 +487,10 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
                memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
                                    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
                       &key->dst, sizeof(key->dst));
+
+               if (ipv6_addr_type(&mask->src) != IPV6_ADDR_ANY ||
+                   ipv6_addr_type(&mask->dst) != IPV6_ADDR_ANY)
+                       *min_inline = MLX5_INLINE_MODE_IP;
        }
 
        if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
@@ -497,11 +531,39 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
                                   "Only UDP and TCP transport are supported\n");
                        return -EINVAL;
                }
+
+               if (mask->src || mask->dst)
+                       *min_inline = MLX5_INLINE_MODE_TCP_UDP;
        }
 
        return 0;
 }
 
+static int parse_cls_flower(struct mlx5e_priv *priv,
+                           struct mlx5_flow_spec *spec,
+                           struct tc_cls_flower_offload *f)
+{
+       struct mlx5_core_dev *dev = priv->mdev;
+       struct mlx5_eswitch *esw = dev->priv.eswitch;
+       struct mlx5_eswitch_rep *rep = priv->ppriv;
+       u8 min_inline;
+       int err;
+
+       err = __parse_cls_flower(priv, spec, f, &min_inline);
+
+       if (!err && esw->mode == SRIOV_OFFLOADS &&
+           rep->vport != FDB_UPLINK_VPORT) {
+               if (min_inline > esw->offloads.inline_mode) {
+                       netdev_warn(priv->netdev,
+                                   "Flow is not offloaded due to min inline setting, required %d actual %d\n",
+                                   min_inline, esw->offloads.inline_mode);
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       return err;
+}
+
 static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                                u32 *action, u32 *flow_tag)
 {
@@ -873,25 +935,17 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
        u32 flow_tag, action;
        struct mlx5e_tc_flow *flow;
        struct mlx5_flow_spec *spec;
-       struct mlx5_flow_handle *old = NULL;
-       struct mlx5_esw_flow_attr *old_attr = NULL;
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
 
        if (esw && esw->mode == SRIOV_OFFLOADS)
                fdb_flow = true;
 
-       flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
-                                     tc->ht_params);
-       if (flow) {
-               old = flow->rule;
-               old_attr = flow->attr;
-       } else {
-               if (fdb_flow)
-                       flow = kzalloc(sizeof(*flow) + sizeof(struct mlx5_esw_flow_attr),
-                                      GFP_KERNEL);
-               else
-                       flow = kzalloc(sizeof(*flow), GFP_KERNEL);
-       }
+       if (fdb_flow)
+               flow = kzalloc(sizeof(*flow) +
+                              sizeof(struct mlx5_esw_flow_attr),
+                              GFP_KERNEL);
+       else
+               flow = kzalloc(sizeof(*flow), GFP_KERNEL);
 
        spec = mlx5_vzalloc(sizeof(*spec));
        if (!spec || !flow) {
@@ -928,40 +982,18 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
        if (err)
                goto err_del_rule;
 
-       if (old)
-               mlx5e_tc_del_flow(priv, old, old_attr);
-
        goto out;
 
 err_del_rule:
        mlx5_del_flow_rules(flow->rule);
 
 err_free:
-       if (!old)
-               kfree(flow);
+       kfree(flow);
 out:
        kvfree(spec);
        return err;
 }
 
-static void mlx5e_detach_encap(struct mlx5e_priv *priv,
-                              struct mlx5e_tc_flow *flow) {
-       struct list_head *next = flow->encap.next;
-
-       list_del(&flow->encap);
-       if (list_empty(next)) {
-               struct mlx5_encap_entry *e;
-
-               e = list_entry(next, struct mlx5_encap_entry, flows);
-               if (e->n) {
-                       mlx5_encap_dealloc(priv->mdev, e->encap_id);
-                       neigh_release(e->n);
-               }
-               hlist_del_rcu(&e->encap_hlist);
-               kfree(e);
-       }
-}
-
 int mlx5e_delete_flower(struct mlx5e_priv *priv,
                        struct tc_cls_flower_offload *f)
 {
@@ -975,10 +1007,8 @@ int mlx5e_delete_flower(struct mlx5e_priv *priv,
 
        rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
 
-       mlx5e_tc_del_flow(priv, flow->rule, flow->attr);
+       mlx5e_tc_del_flow(priv, flow);
 
-       if (flow->attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
-               mlx5e_detach_encap(priv, flow);
 
        kfree(flow);
 
@@ -1035,7 +1065,7 @@ static void _mlx5e_tc_del_flow(void *ptr, void *arg)
        struct mlx5e_tc_flow *flow = ptr;
        struct mlx5e_priv *priv = arg;
 
-       mlx5e_tc_del_flow(priv, flow->rule, flow->attr);
+       mlx5e_tc_del_flow(priv, flow);
        kfree(flow);
 }