mlxsw: spectrum_router: Take router lock from netdev listener
authorIdo Schimmel <idosch@mellanox.com>
Fri, 21 Feb 2020 17:54:12 +0000 (19:54 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 23 Feb 2020 05:24:51 +0000 (21:24 -0800)
One entry point into the routing code is from the netdev listener block.
Some netdev events require access to internal router structures. For
example, changing the MTU of a netdev requires looking-up the backing
RIF and adjusting its MTU.

In order to serialize access to shared router structures, take the
router lock when processing netdev events that require access to it.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

index 66cfe27..bb02a03 100644 (file)
@@ -548,7 +548,7 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
                                 struct netdev_notifier_changeupper_info *info);
 bool mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp *mlxsw_sp,
                                const struct net_device *dev);
-bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp,
+bool mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp *mlxsw_sp,
                                const struct net_device *dev);
 int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp,
                                     struct net_device *l3_dev,
index 601fa4a..7ad5cb5 100644 (file)
@@ -1346,10 +1346,16 @@ mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp,
        return NULL;
 }
 
-bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp,
+bool mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp *mlxsw_sp,
                                const struct net_device *dev)
 {
-       return mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL);
+       bool is_ipip_ul;
+
+       mutex_lock(&mlxsw_sp->router->lock);
+       is_ipip_ul = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL);
+       mutex_unlock(&mlxsw_sp->router->lock);
+
+       return is_ipip_ul;
 }
 
 static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp,
@@ -1721,35 +1727,41 @@ int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp,
 {
        struct netdev_notifier_changeupper_info *chup;
        struct netlink_ext_ack *extack;
+       int err = 0;
 
+       mutex_lock(&mlxsw_sp->router->lock);
        switch (event) {
        case NETDEV_REGISTER:
-               return mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev);
+               err = mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev);
+               break;
        case NETDEV_UNREGISTER:
                mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev);
-               return 0;
+               break;
        case NETDEV_UP:
                mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev);
-               return 0;
+               break;
        case NETDEV_DOWN:
                mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev);
-               return 0;
+               break;
        case NETDEV_CHANGEUPPER:
                chup = container_of(info, typeof(*chup), info);
                extack = info->extack;
                if (netif_is_l3_master(chup->upper_dev))
-                       return mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp,
-                                                                   ol_dev,
-                                                                   extack);
-               return 0;
+                       err = mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp,
+                                                                  ol_dev,
+                                                                  extack);
+               break;
        case NETDEV_CHANGE:
                extack = info->extack;
-               return mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp,
-                                                              ol_dev, extack);
+               err = mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp,
+                                                             ol_dev, extack);
+               break;
        case NETDEV_CHANGEMTU:
-               return mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev);
+               err = mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev);
+               break;
        }
-       return 0;
+       mutex_unlock(&mlxsw_sp->router->lock);
+       return err;
 }
 
 static int
@@ -1793,8 +1805,9 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
                                 struct netdev_notifier_info *info)
 {
        struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
-       int err;
+       int err = 0;
 
+       mutex_lock(&mlxsw_sp->router->lock);
        while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp,
                                                                ul_dev,
                                                                ipip_entry))) {
@@ -1807,7 +1820,7 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
                if (err) {
                        mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp,
                                                                 ul_dev);
-                       return err;
+                       break;
                }
 
                if (demote_this) {
@@ -1824,8 +1837,9 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
                        ipip_entry = prev;
                }
        }
+       mutex_unlock(&mlxsw_sp->router->lock);
 
-       return 0;
+       return err;
 }
 
 int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
@@ -7223,24 +7237,30 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
 {
        struct mlxsw_sp *mlxsw_sp;
        struct mlxsw_sp_rif *rif;
+       int err = 0;
 
        mlxsw_sp = mlxsw_sp_lower_get(dev);
        if (!mlxsw_sp)
                return 0;
 
+       mutex_lock(&mlxsw_sp->router->lock);
        rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
        if (!rif)
-               return 0;
+               goto out;
 
        switch (event) {
        case NETDEV_CHANGEMTU: /* fall through */
        case NETDEV_CHANGEADDR:
-               return mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
+               err = mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
+               break;
        case NETDEV_PRE_CHANGEADDR:
-               return mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
+               err = mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
+               break;
        }
 
-       return 0;
+out:
+       mutex_unlock(&mlxsw_sp->router->lock);
+       return err;
 }
 
 static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
@@ -7283,9 +7303,10 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
        if (!mlxsw_sp || netif_is_macvlan(l3_dev))
                return 0;
 
+       mutex_lock(&mlxsw_sp->router->lock);
        switch (event) {
        case NETDEV_PRECHANGEUPPER:
-               return 0;
+               break;
        case NETDEV_CHANGEUPPER:
                if (info->linking) {
                        struct netlink_ext_ack *extack;
@@ -7297,6 +7318,7 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
                }
                break;
        }
+       mutex_unlock(&mlxsw_sp->router->lock);
 
        return err;
 }