Commit 31618b22 authored by Petr Machata's avatar Petr Machata Committed by David S. Miller

mlxsw: spectrum_router: Replay IP NETDEV_UP on device enslavement

Enslaving of front panel ports (and their uppers) to netdevices that
already have uppers is currently forbidden. When this is permitted, any
uppers with IP addresses need to have the NETDEV_UP inetaddr event
replayed, so that any RIFs are created.
Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Reviewed-by: default avatarDanielle Ratson <danieller@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8fdb09a7
......@@ -4469,8 +4469,14 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
if (err)
goto err_router_join;
err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, lag_dev, extack);
if (err)
goto err_replay;
return 0;
err_replay:
mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
err_router_join:
lag->ref_count--;
mlxsw_sp_port->lagged = 0;
......
......@@ -9781,6 +9781,97 @@ mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
return err;
}
struct mlxsw_sp_router_replay_inetaddr_up {
struct mlxsw_sp *mlxsw_sp;
struct netlink_ext_ack *extack;
unsigned int done;
};
static int mlxsw_sp_router_replay_inetaddr_up(struct net_device *dev,
struct netdev_nested_priv *priv)
{
struct mlxsw_sp_router_replay_inetaddr_up *ctx = priv->data;
struct mlxsw_sp_crif *crif;
int err;
if (mlxsw_sp_dev_addr_list_empty(dev))
return 0;
crif = mlxsw_sp_crif_lookup(ctx->mlxsw_sp->router, dev);
if (!crif || crif->rif)
return 0;
if (!mlxsw_sp_rif_should_config(crif->rif, dev, NETDEV_UP))
return 0;
err = __mlxsw_sp_inetaddr_event(ctx->mlxsw_sp, dev, NETDEV_UP,
false, ctx->extack);
if (err)
return err;
ctx->done++;
return 0;
}
static int mlxsw_sp_router_unreplay_inetaddr_up(struct net_device *dev,
struct netdev_nested_priv *priv)
{
struct mlxsw_sp_router_replay_inetaddr_up *ctx = priv->data;
struct mlxsw_sp_crif *crif;
if (!ctx->done)
return 0;
if (mlxsw_sp_dev_addr_list_empty(dev))
return 0;
crif = mlxsw_sp_crif_lookup(ctx->mlxsw_sp->router, dev);
if (!crif || !crif->rif)
return 0;
/* We are rolling back NETDEV_UP, so ask for that. */
if (!mlxsw_sp_rif_should_config(crif->rif, dev, NETDEV_UP))
return 0;
__mlxsw_sp_inetaddr_event(ctx->mlxsw_sp, dev, NETDEV_DOWN, false, NULL);
ctx->done--;
return 0;
}
int mlxsw_sp_netdevice_enslavement_replay(struct mlxsw_sp *mlxsw_sp,
struct net_device *upper_dev,
struct netlink_ext_ack *extack)
{
struct mlxsw_sp_router_replay_inetaddr_up ctx = {
.mlxsw_sp = mlxsw_sp,
.extack = extack,
};
struct netdev_nested_priv priv = {
.data = &ctx,
};
int err;
err = mlxsw_sp_router_replay_inetaddr_up(upper_dev, &priv);
if (err)
return err;
err = netdev_walk_all_upper_dev_rcu(upper_dev,
mlxsw_sp_router_replay_inetaddr_up,
&priv);
if (err)
goto err_replay_up;
return 0;
err_replay_up:
netdev_walk_all_upper_dev_rcu(upper_dev,
mlxsw_sp_router_unreplay_inetaddr_up,
&priv);
mlxsw_sp_router_unreplay_inetaddr_up(upper_dev, &priv);
return err;
}
static int
mlxsw_sp_port_vid_router_join_existing(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid, struct net_device *dev,
......@@ -9857,6 +9948,26 @@ static int __mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}
static void
__mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev)
{
u16 default_vid = MLXSW_SP_DEFAULT_VID;
struct net_device *upper_dev;
struct list_head *iter;
u16 vid;
netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
if (!is_vlan_dev(upper_dev))
continue;
vid = vlan_dev_vlan_id(upper_dev);
mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, vid, upper_dev);
}
mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, default_vid, lag_dev);
}
int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev,
struct netlink_ext_ack *extack)
......@@ -9870,6 +9981,14 @@ int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}
void mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev)
{
mutex_lock(&mlxsw_sp_port->mlxsw_sp->router->lock);
__mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
mutex_unlock(&mlxsw_sp_port->mlxsw_sp->router->lock);
}
static int mlxsw_sp_router_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
......
......@@ -178,5 +178,10 @@ int mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp *mlxsw_sp,
int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev,
struct netlink_ext_ack *extack);
void mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev);
int mlxsw_sp_netdevice_enslavement_replay(struct mlxsw_sp *mlxsw_sp,
struct net_device *upper_dev,
struct netlink_ext_ack *extack);
#endif /* _MLXSW_ROUTER_H_*/
......@@ -2894,8 +2894,15 @@ int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
if (err)
goto err_port_join;
err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, br_dev, extack);
if (err)
goto err_replay;
return 0;
err_replay:
bridge_device->ops->port_leave(bridge_device, bridge_port,
mlxsw_sp_port);
err_port_join:
mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment