net/mlx5e: Fix cb_ident duplicate in indirect block register
authorEli Britstein <elibr@mellanox.com>
Wed, 19 Dec 2018 05:36:51 +0000 (07:36 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Sat, 19 Jan 2019 00:15:31 +0000 (16:15 -0800)
Previously the identifier used for indirect block callback registry
and for block rule cb registry (when done via indirect blocks) was the
pointer to the tunnel netdev we were interested in receiving updates on.
This worked fine if a single PF existed that registered one callback for
the tunnel netdev of interest. However, if multiple PFs are in place then
the 2nd PF tries to register with the same tunnel netdev identifier. This
leads to EEXIST errors and/or incorrect cb deletions.

Prevent this conflict by using the rpriv pointer as the identifier for
netdev indirect block cb registry, allowing each PF to register a unique
callback per tunnel netdev. For block cb registry, the same PF may
register multiple cbs to the same block if using TC shared blocks.
Instead of the rpriv, use the pointer to the allocated indr_priv data as
the identifier here. This means that there can be a unique block callback
for each PF/tunnel netdev combo.

Fixes: f5bc2c5de101 ("net/mlx5e: Support TC indirect block notifications
for eswitch uplink reprs")
Signed-off-by: Eli Britstein <elibr@mellanox.com>
Reviewed-by: Oz Shlomo <ozsh@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c

index c9a7081a532996dd5f50e77c52e4ff80e90fd626..04736212a21c9eb0f72c9ca7b5a95b8590626f84 100644 (file)
@@ -58,7 +58,8 @@ struct mlx5e_rep_indr_block_priv {
        struct list_head list;
 };
 
-static void mlx5e_rep_indr_unregister_block(struct net_device *netdev);
+static void mlx5e_rep_indr_unregister_block(struct mlx5e_rep_priv *rpriv,
+                                           struct net_device *netdev);
 
 static void mlx5e_rep_get_drvinfo(struct net_device *dev,
                                  struct ethtool_drvinfo *drvinfo)
@@ -664,7 +665,7 @@ static void mlx5e_rep_indr_clean_block_privs(struct mlx5e_rep_priv *rpriv)
        struct list_head *head = &rpriv->uplink_priv.tc_indr_block_priv_list;
 
        list_for_each_entry_safe(cb_priv, temp, head, list) {
-               mlx5e_rep_indr_unregister_block(cb_priv->netdev);
+               mlx5e_rep_indr_unregister_block(rpriv, cb_priv->netdev);
                kfree(cb_priv);
        }
 }
@@ -736,7 +737,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
 
                err = tcf_block_cb_register(f->block,
                                            mlx5e_rep_indr_setup_block_cb,
-                                           netdev, indr_priv, f->extack);
+                                           indr_priv, indr_priv, f->extack);
                if (err) {
                        list_del(&indr_priv->list);
                        kfree(indr_priv);
@@ -744,14 +745,15 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
 
                return err;
        case TC_BLOCK_UNBIND:
+               indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
+               if (!indr_priv)
+                       return -ENOENT;
+
                tcf_block_cb_unregister(f->block,
                                        mlx5e_rep_indr_setup_block_cb,
-                                       netdev);
-               indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
-               if (indr_priv) {
-                       list_del(&indr_priv->list);
-                       kfree(indr_priv);
-               }
+                                       indr_priv);
+               list_del(&indr_priv->list);
+               kfree(indr_priv);
 
                return 0;
        default:
@@ -780,7 +782,7 @@ static int mlx5e_rep_indr_register_block(struct mlx5e_rep_priv *rpriv,
 
        err = __tc_indr_block_cb_register(netdev, rpriv,
                                          mlx5e_rep_indr_setup_tc_cb,
-                                         netdev);
+                                         rpriv);
        if (err) {
                struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
 
@@ -790,10 +792,11 @@ static int mlx5e_rep_indr_register_block(struct mlx5e_rep_priv *rpriv,
        return err;
 }
 
-static void mlx5e_rep_indr_unregister_block(struct net_device *netdev)
+static void mlx5e_rep_indr_unregister_block(struct mlx5e_rep_priv *rpriv,
+                                           struct net_device *netdev)
 {
        __tc_indr_block_cb_unregister(netdev, mlx5e_rep_indr_setup_tc_cb,
-                                     netdev);
+                                     rpriv);
 }
 
 static int mlx5e_nic_rep_netdevice_event(struct notifier_block *nb,
@@ -812,7 +815,7 @@ static int mlx5e_nic_rep_netdevice_event(struct notifier_block *nb,
                mlx5e_rep_indr_register_block(rpriv, netdev);
                break;
        case NETDEV_UNREGISTER:
-               mlx5e_rep_indr_unregister_block(netdev);
+               mlx5e_rep_indr_unregister_block(rpriv, netdev);
                break;
        }
        return NOTIFY_OK;