Skip to content

Commit

Permalink
mlxsw: spectrum_router: Add support for VRFs
Browse files Browse the repository at this point in the history
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: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ido Schimmel authored and David S. Miller committed Mar 16, 2017
1 parent 9db032b commit 7179eb5
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
19 changes: 16 additions & 3 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -3951,7 +3951,8 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
upper_dev = info->upper_dev;
if (!is_vlan_dev(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;
if (!info->linking)
break;
Expand Down Expand Up @@ -3991,6 +3992,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
else
mlxsw_sp_port_lag_leave(mlxsw_sp_port,
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 {
err = -EINVAL;
WARN_ON(1);
Expand Down Expand Up @@ -4353,14 +4359,16 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,
switch (event) {
case NETDEV_PRECHANGEUPPER:
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;
if (!info->linking)
break;
/* We can't have multiple VLAN interfaces configured on
* 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))
return -EINVAL;
break;
Expand All @@ -4372,6 +4380,11 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev,
upper_dev);
else
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 {
err = -EINVAL;
WARN_ON(1);
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,10 @@ int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
unsigned long event, void *ptr);
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
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);
void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
Expand Down
41 changes: 41 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
Original file line number Diff line number Diff line change
Expand Up @@ -3226,6 +3226,47 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
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)
{
struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
Expand Down

0 comments on commit 7179eb5

Please sign in to comment.