if (!is_vlan_dev(upper_dev) &&
!netif_is_lag_master(upper_dev) &&
!netif_is_bridge_master(upper_dev) &&
- !netif_is_l3_master(upper_dev) &&
!netif_is_ovs_master(upper_dev))
return -EINVAL;
if (!info->linking)
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 if (netif_is_ovs_master(upper_dev)) {
if (info->linking)
err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);
switch (event) {
case NETDEV_PRECHANGEUPPER:
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;
if (is_vlan_dev(upper_dev) &&
br_dev != mlxsw_sp->master_bridge.dev)
else
mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp,
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 {
err = -EINVAL;
WARN_ON(1);
switch (event) {
case NETDEV_PRECHANGEUPPER:
upper_dev = info->upper_dev;
- if (!netif_is_bridge_master(upper_dev) &&
- !netif_is_l3_master(upper_dev))
+ if (!netif_is_bridge_master(upper_dev))
return -EINVAL;
if (!info->linking)
break;
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);
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,
unsigned long event, void *ptr)
{
else if (netif_is_lag_master(real_dev))
return mlxsw_sp_netdevice_lag_vport_event(real_dev, event, ptr,
vid);
- else if (netif_is_bridge_master(real_dev))
- return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, event,
- ptr);
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,
unsigned long event, void *ptr)
{
if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
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))
err = mlxsw_sp_netdevice_port_event(dev, event, ptr);
else if (netif_is_lag_master(dev))
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,
unsigned long event, void *ptr)
{
if (!mlxsw_sp_rif_should_config(rif, ifa->ifa_dev, event))
goto out;
- if (mlxsw_sp_port_dev_check(dev))
- 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);
-
+ err = __mlxsw_sp_inetaddr_event(dev, event);
out:
return notifier_from_errno(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 net_device *dev = mlxsw_sp_vport->dev;
+ struct mlxsw_sp_rif *rif;
- /* 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 netdev is already associated with a RIF, then we need to
+ * destroy it and create a new one with the new virtual router ID.
*/
- if (f && f->rif)
- 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;
+ rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
+ if (rif)
+ __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN);
- return mlxsw_sp_vport_vrf_join(mlxsw_sp_vport);
+ return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP);
}
-void mlxsw_sp_port_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_port)
+static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *l3_dev)
{
- struct mlxsw_sp_port *mlxsw_sp_vport;
+ struct mlxsw_sp_rif *rif;
- mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1);
- if (WARN_ON(!mlxsw_sp_vport))
+ rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
+ if (!rif)
return;
-
- mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
+ __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN);
}
-int mlxsw_sp_bridge_vrf_join(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev)
+int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
+ struct netdev_notifier_changeupper_info *info)
{
- struct mlxsw_sp_fid *f;
-
- f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
- if (WARN_ON(!f))
- return -EINVAL;
-
- if (f->rif)
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
+ int err = 0;
- return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
-}
+ if (!mlxsw_sp)
+ return 0;
-void mlxsw_sp_bridge_vrf_leave(struct mlxsw_sp *mlxsw_sp,
- struct net_device *l3_dev)
-{
- struct mlxsw_sp_fid *f;
+ switch (event) {
+ 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;
+ }
- f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
- if (WARN_ON(!f))
- return;
- mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
+ return err;
}
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)