Commit 7179eb5a authored by Ido Schimmel's avatar Ido Schimmel Committed by David S. Miller

mlxsw: spectrum_router: Add support for VRFs

Allow port netdevs, LAG and VLAN devices stacked on top of these to be
enslaved to a VRF master device.

Upon enslavement, create a router interface (RIF) for the enslaved
netdev and associate it with a virtual router (VR) based on the VRF's
table ID.

If a RIF already exists for the netdev (f.e., due to the existence of an
IP address), then it's deleted and a new one is created with the
appropriate VR binding.
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9db032bb
...@@ -3951,7 +3951,8 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, ...@@ -3951,7 +3951,8 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
upper_dev = info->upper_dev; upper_dev = info->upper_dev;
if (!is_vlan_dev(upper_dev) && if (!is_vlan_dev(upper_dev) &&
!netif_is_lag_master(upper_dev) && !netif_is_lag_master(upper_dev) &&
!netif_is_bridge_master(upper_dev)) !netif_is_bridge_master(upper_dev) &&
!netif_is_l3_master(upper_dev))
return -EINVAL; return -EINVAL;
if (!info->linking) if (!info->linking)
break; break;
...@@ -3991,6 +3992,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, ...@@ -3991,6 +3992,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
else else
mlxsw_sp_port_lag_leave(mlxsw_sp_port, mlxsw_sp_port_lag_leave(mlxsw_sp_port,
upper_dev); upper_dev);
} else if (netif_is_l3_master(upper_dev)) {
if (info->linking)
err = mlxsw_sp_port_vrf_join(mlxsw_sp_port);
else
mlxsw_sp_port_vrf_leave(mlxsw_sp_port);
} else { } else {
err = -EINVAL; err = -EINVAL;
WARN_ON(1); WARN_ON(1);
...@@ -4353,14 +4359,16 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, ...@@ -4353,14 +4359,16 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,
switch (event) { switch (event) {
case NETDEV_PRECHANGEUPPER: case NETDEV_PRECHANGEUPPER:
upper_dev = info->upper_dev; upper_dev = info->upper_dev;
if (!netif_is_bridge_master(upper_dev)) if (!netif_is_bridge_master(upper_dev) &&
!netif_is_l3_master(upper_dev))
return -EINVAL; return -EINVAL;
if (!info->linking) if (!info->linking)
break; break;
/* We can't have multiple VLAN interfaces configured on /* We can't have multiple VLAN interfaces configured on
* the same port and being members in the same bridge. * the same port and being members in the same bridge.
*/ */
if (!mlxsw_sp_port_master_bridge_check(mlxsw_sp_port, if (netif_is_bridge_master(upper_dev) &&
!mlxsw_sp_port_master_bridge_check(mlxsw_sp_port,
upper_dev)) upper_dev))
return -EINVAL; return -EINVAL;
break; break;
...@@ -4372,6 +4380,11 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, ...@@ -4372,6 +4380,11 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,
upper_dev); upper_dev);
else else
mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport); mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport);
} else if (netif_is_l3_master(upper_dev)) {
if (info->linking)
err = mlxsw_sp_vport_vrf_join(mlxsw_sp_vport);
else
mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
} else { } else {
err = -EINVAL; err = -EINVAL;
WARN_ON(1); WARN_ON(1);
......
...@@ -578,6 +578,10 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused, ...@@ -578,6 +578,10 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
unsigned long event, void *ptr); unsigned long event, void *ptr);
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *r); struct mlxsw_sp_rif *r);
int mlxsw_sp_vport_vrf_join(struct mlxsw_sp_port *mlxsw_sp_vport);
void mlxsw_sp_vport_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
int mlxsw_sp_port_vrf_join(struct mlxsw_sp_port *mlxsw_sp_port);
void mlxsw_sp_port_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count); int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count);
void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index); void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
......
...@@ -3226,6 +3226,47 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) ...@@ -3226,6 +3226,47 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
return err; return err;
} }
int mlxsw_sp_vport_vrf_join(struct mlxsw_sp_port *mlxsw_sp_vport)
{
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
struct net_device *dev = mlxsw_sp_vport->dev;
/* 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 (f && f->r)
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;
return mlxsw_sp_vport_vrf_join(mlxsw_sp_vport);
}
void mlxsw_sp_port_vrf_leave(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;
mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
}
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb) static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
{ {
struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb); struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
......
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