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: 7179eb5acd
("mlxsw: spectrum_router: Add support for VRFs")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
cedf90c0cc
commit
b1e455260c
|
@ -4106,7 +4106,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *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) &&
|
|
||||||
!netif_is_ovs_master(upper_dev))
|
!netif_is_ovs_master(upper_dev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!info->linking)
|
if (!info->linking)
|
||||||
|
@ -4151,11 +4150,6 @@ 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 if (netif_is_ovs_master(upper_dev)) {
|
} else if (netif_is_ovs_master(upper_dev)) {
|
||||||
if (info->linking)
|
if (info->linking)
|
||||||
err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);
|
err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);
|
||||||
|
@ -4275,7 +4269,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_PRECHANGEUPPER:
|
case NETDEV_PRECHANGEUPPER:
|
||||||
upper_dev = info->upper_dev;
|
upper_dev = info->upper_dev;
|
||||||
if (!is_vlan_dev(upper_dev) && !netif_is_l3_master(upper_dev))
|
if (!is_vlan_dev(upper_dev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (is_vlan_dev(upper_dev) &&
|
if (is_vlan_dev(upper_dev) &&
|
||||||
br_dev != mlxsw_sp->master_bridge.dev)
|
br_dev != mlxsw_sp->master_bridge.dev)
|
||||||
|
@ -4290,12 +4284,6 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
|
||||||
else
|
else
|
||||||
mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp,
|
mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp,
|
||||||
upper_dev);
|
upper_dev);
|
||||||
} else if (netif_is_l3_master(upper_dev)) {
|
|
||||||
if (info->linking)
|
|
||||||
err = mlxsw_sp_bridge_vrf_join(mlxsw_sp,
|
|
||||||
br_dev);
|
|
||||||
else
|
|
||||||
mlxsw_sp_bridge_vrf_leave(mlxsw_sp, br_dev);
|
|
||||||
} else {
|
} else {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
@ -4529,8 +4517,7 @@ 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;
|
||||||
|
@ -4550,11 +4537,6 @@ 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);
|
||||||
|
@ -4585,47 +4567,6 @@ static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
|
|
||||||
unsigned long event, void *ptr)
|
|
||||||
{
|
|
||||||
struct netdev_notifier_changeupper_info *info;
|
|
||||||
struct mlxsw_sp *mlxsw_sp;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
|
|
||||||
if (!mlxsw_sp)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
info = ptr;
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case NETDEV_PRECHANGEUPPER:
|
|
||||||
/* VLAN devices are only allowed on top of the
|
|
||||||
* VLAN-aware bridge.
|
|
||||||
*/
|
|
||||||
if (WARN_ON(vlan_dev_real_dev(vlan_dev) !=
|
|
||||||
mlxsw_sp->master_bridge.dev))
|
|
||||||
return -EINVAL;
|
|
||||||
if (!netif_is_l3_master(info->upper_dev))
|
|
||||||
return -EINVAL;
|
|
||||||
break;
|
|
||||||
case NETDEV_CHANGEUPPER:
|
|
||||||
if (netif_is_l3_master(info->upper_dev)) {
|
|
||||||
if (info->linking)
|
|
||||||
err = mlxsw_sp_bridge_vrf_join(mlxsw_sp,
|
|
||||||
vlan_dev);
|
|
||||||
else
|
|
||||||
mlxsw_sp_bridge_vrf_leave(mlxsw_sp, vlan_dev);
|
|
||||||
} else {
|
|
||||||
err = -EINVAL;
|
|
||||||
WARN_ON(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
|
static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
|
||||||
unsigned long event, void *ptr)
|
unsigned long event, void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -4638,13 +4579,19 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
|
||||||
else if (netif_is_lag_master(real_dev))
|
else if (netif_is_lag_master(real_dev))
|
||||||
return mlxsw_sp_netdevice_lag_vport_event(real_dev, event, ptr,
|
return mlxsw_sp_netdevice_lag_vport_event(real_dev, event, ptr,
|
||||||
vid);
|
vid);
|
||||||
else if (netif_is_bridge_master(real_dev))
|
|
||||||
return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, event,
|
|
||||||
ptr);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
|
||||||
|
{
|
||||||
|
struct netdev_notifier_changeupper_info *info = ptr;
|
||||||
|
|
||||||
|
if (event != NETDEV_PRECHANGEUPPER && event != NETDEV_CHANGEUPPER)
|
||||||
|
return false;
|
||||||
|
return netif_is_l3_master(info->upper_dev);
|
||||||
|
}
|
||||||
|
|
||||||
static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
|
static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
|
||||||
unsigned long event, void *ptr)
|
unsigned long event, void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -4653,6 +4600,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
|
||||||
|
|
||||||
if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
|
if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
|
||||||
err = mlxsw_sp_netdevice_router_port_event(dev);
|
err = mlxsw_sp_netdevice_router_port_event(dev);
|
||||||
|
else if (mlxsw_sp_is_vrf_event(event, ptr))
|
||||||
|
err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
|
||||||
else if (mlxsw_sp_port_dev_check(dev))
|
else if (mlxsw_sp_port_dev_check(dev))
|
||||||
err = mlxsw_sp_netdevice_port_event(dev, event, ptr);
|
err = mlxsw_sp_netdevice_port_event(dev, event, ptr);
|
||||||
else if (netif_is_lag_master(dev))
|
else if (netif_is_lag_master(dev))
|
||||||
|
|
|
@ -576,14 +576,8 @@ 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 *rif);
|
struct mlxsw_sp_rif *rif);
|
||||||
int mlxsw_sp_vport_vrf_join(struct mlxsw_sp_port *mlxsw_sp_vport);
|
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
||||||
void mlxsw_sp_vport_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
|
struct netdev_notifier_changeupper_info *info);
|
||||||
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_bridge_vrf_join(struct mlxsw_sp *mlxsw_sp,
|
|
||||||
struct net_device *l3_dev);
|
|
||||||
void mlxsw_sp_bridge_vrf_leave(struct mlxsw_sp *mlxsw_sp,
|
|
||||||
struct net_device *l3_dev);
|
|
||||||
|
|
||||||
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,
|
||||||
u32 *p_entry_index);
|
u32 *p_entry_index);
|
||||||
|
|
|
@ -3345,6 +3345,21 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
|
||||||
return 0;
|
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,
|
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
|
||||||
unsigned long event, void *ptr)
|
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))
|
if (!mlxsw_sp_rif_should_config(rif, ifa->ifa_dev, event))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (mlxsw_sp_port_dev_check(dev))
|
err = __mlxsw_sp_inetaddr_event(dev, event);
|
||||||
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);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return notifier_from_errno(err);
|
return notifier_from_errno(err);
|
||||||
}
|
}
|
||||||
|
@ -3433,71 +3440,53 @@ 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)
|
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 mlxsw_sp_rif *rif;
|
||||||
struct net_device *dev = mlxsw_sp_vport->dev;
|
|
||||||
|
|
||||||
/* In case vPort already has a RIF, then we need to drop it.
|
/* If netdev is already associated with a RIF, then we need to
|
||||||
* A new one will be created using the VRF's VR.
|
* destroy it and create a new one with the new virtual router ID.
|
||||||
*/
|
*/
|
||||||
if (f && f->rif)
|
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
|
||||||
mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport);
|
if (rif)
|
||||||
|
__mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN);
|
||||||
|
|
||||||
return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, dev);
|
return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mlxsw_sp_vport_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
|
static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
struct net_device *l3_dev)
|
||||||
{
|
{
|
||||||
mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport);
|
struct mlxsw_sp_rif *rif;
|
||||||
}
|
|
||||||
|
|
||||||
int mlxsw_sp_port_vrf_join(struct mlxsw_sp_port *mlxsw_sp_port)
|
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
|
||||||
{
|
if (!rif)
|
||||||
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;
|
return;
|
||||||
|
__mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN);
|
||||||
mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mlxsw_sp_bridge_vrf_join(struct mlxsw_sp *mlxsw_sp,
|
int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
||||||
struct net_device *l3_dev)
|
struct netdev_notifier_changeupper_info *info)
|
||||||
{
|
{
|
||||||
struct mlxsw_sp_fid *f;
|
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
|
if (!mlxsw_sp)
|
||||||
if (WARN_ON(!f))
|
return 0;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (f->rif)
|
switch (event) {
|
||||||
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
void mlxsw_sp_bridge_vrf_leave(struct mlxsw_sp *mlxsw_sp,
|
|
||||||
struct net_device *l3_dev)
|
|
||||||
{
|
|
||||||
struct mlxsw_sp_fid *f;
|
|
||||||
|
|
||||||
f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
|
|
||||||
if (WARN_ON(!f))
|
|
||||||
return;
|
|
||||||
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
|
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
|
||||||
|
|
Loading…
Reference in New Issue