summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
diff options
context:
space:
mode:
authorPetr Machata <petrm@nvidia.com>2023-07-19 13:01:30 +0200
committerDavid S. Miller <davem@davemloft.net>2023-07-21 08:54:05 +0100
commit31618b22f2c4c0a4491554a2d879141efdffe88f (patch)
treeb4b4db0517cfb5a9d089ce14702dd1790db12c08 /drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
parent8fdb09a7674c61c4f0e5faf0d63b3ce500a341b0 (diff)
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: Petr Machata <petrm@nvidia.com> Reviewed-by: Danielle Ratson <danieller@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c')
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 9263a914bcc7..18d1bcbb3fdf 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -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 @@ err_router_join_dev:
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)
{