From b1e455260c9187b16dd4ebc428b817ebac322043 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 30 Apr 2017 19:47:14 +0300 Subject: mlxsw: spectrum_router: Simplify VRF enslavement When a netdev is enslaved to a VRF master, its router interface (RIF) needs to be destroyed (if exists) and a new one created using the corresponding virtual router (VR). >From the driver's perspective, the above is equivalent to an inetaddr event sent for this netdev. Therefore, when a port netdev (or its uppers) are enslaved to a VRF master, call the same function that would've been called had a NETDEV_UP was sent for this netdev in the inetaddr notification chain. This patch also fixes a bug when a LAG netdev with an existing RIF is enslaved to a VRF. Before this patch, each LAG port would drop the reference on the RIF, but would re-join the same one (in the wrong VR) soon after. With this patch, the corresponding RIF is first destroyed and a new one is created using the correct VR. Fixes: 7179eb5acd59 ("mlxsw: spectrum_router: Add support for VRFs") Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 107 +++++++++------------ 1 file changed, 48 insertions(+), 59 deletions(-) (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 146f8c7d1120..33cec1cc1642 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3345,6 +3345,21 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, return 0; } +static int __mlxsw_sp_inetaddr_event(struct net_device *dev, + unsigned long event) +{ + if (mlxsw_sp_port_dev_check(dev)) + return mlxsw_sp_inetaddr_port_event(dev, event); + else if (netif_is_lag_master(dev)) + return mlxsw_sp_inetaddr_lag_event(dev, event); + else if (netif_is_bridge_master(dev)) + return mlxsw_sp_inetaddr_bridge_event(dev, dev, event); + else if (is_vlan_dev(dev)) + return mlxsw_sp_inetaddr_vlan_event(dev, event); + else + return 0; +} + int mlxsw_sp_inetaddr_event(struct notifier_block *unused, unsigned long event, void *ptr) { @@ -3362,15 +3377,7 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused, if (!mlxsw_sp_rif_should_config(rif, ifa->ifa_dev, event)) goto out; - if (mlxsw_sp_port_dev_check(dev)) - err = mlxsw_sp_inetaddr_port_event(dev, event); - else if (netif_is_lag_master(dev)) - err = mlxsw_sp_inetaddr_lag_event(dev, event); - else if (netif_is_bridge_master(dev)) - err = mlxsw_sp_inetaddr_bridge_event(dev, dev, event); - else if (is_vlan_dev(dev)) - err = mlxsw_sp_inetaddr_vlan_event(dev, event); - + err = __mlxsw_sp_inetaddr_event(dev, event); out: return notifier_from_errno(err); } @@ -3433,71 +3440,53 @@ err_rif_edit: return err; } -int mlxsw_sp_vport_vrf_join(struct mlxsw_sp_port *mlxsw_sp_vport) +static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp, + struct net_device *l3_dev) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - struct net_device *dev = mlxsw_sp_vport->dev; + struct mlxsw_sp_rif *rif; - /* In case vPort already has a RIF, then we need to drop it. - * A new one will be created using the VRF's VR. + /* If netdev is already associated with a RIF, then we need to + * destroy it and create a new one with the new virtual router ID. */ - if (f && f->rif) - mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport); - - return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, dev); -} - -void mlxsw_sp_vport_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_vport) -{ - mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport); -} - -int mlxsw_sp_port_vrf_join(struct mlxsw_sp_port *mlxsw_sp_port) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1); - if (WARN_ON(!mlxsw_sp_vport)) - return -EINVAL; + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); + if (rif) + __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN); - return mlxsw_sp_vport_vrf_join(mlxsw_sp_vport); + return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP); } -void mlxsw_sp_port_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_port) +static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp, + struct net_device *l3_dev) { - struct mlxsw_sp_port *mlxsw_sp_vport; + struct mlxsw_sp_rif *rif; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1); - if (WARN_ON(!mlxsw_sp_vport)) + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); + if (!rif) return; - - mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport); + __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN); } -int mlxsw_sp_bridge_vrf_join(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev) +int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, + struct netdev_notifier_changeupper_info *info) { - struct mlxsw_sp_fid *f; - - f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev); - if (WARN_ON(!f)) - return -EINVAL; - - if (f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev); + int err = 0; - return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f); -} + if (!mlxsw_sp) + return 0; -void mlxsw_sp_bridge_vrf_leave(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev) -{ - struct mlxsw_sp_fid *f; + switch (event) { + case NETDEV_PRECHANGEUPPER: + return 0; + case NETDEV_CHANGEUPPER: + if (info->linking) + err = mlxsw_sp_port_vrf_join(mlxsw_sp, l3_dev); + else + mlxsw_sp_port_vrf_leave(mlxsw_sp, l3_dev); + break; + } - f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev); - if (WARN_ON(!f)) - return; - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); + return err; } static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb) -- cgit v1.2.3-55-g7522