mlxsw: spectrum_router: Add support for VRFs on top of bridges
authorIdo Schimmel <idosch@mellanox.com>
Thu, 16 Mar 2017 08:08:19 +0000 (09:08 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 16 Mar 2017 17:18:35 +0000 (10:18 -0700)
In a similar fashion to the previous patch, allow bridges and VLAN
devices on top of bridges to be enslaved to a VRF master device.

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>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

index 659df3225a2487805486ddba46c956c84db44cfe..28019f8b70f7a2da3d7dc130d2cb9ab042b18870 100644 (file)
@@ -4111,7 +4111,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
        switch (event) {
        case NETDEV_PRECHANGEUPPER:
                upper_dev = info->upper_dev;
-               if (!is_vlan_dev(upper_dev))
+               if (!is_vlan_dev(upper_dev) && !netif_is_l3_master(upper_dev))
                        return -EINVAL;
                if (is_vlan_dev(upper_dev) &&
                    br_dev != mlxsw_sp->master_bridge.dev)
@@ -4126,6 +4126,12 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_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);
@@ -4415,6 +4421,47 @@ static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev,
        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)
 {
@@ -4427,6 +4474,9 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
        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;
 }
index 60004d97e631563b256f6bd4bb92e52d666924cb..0e223f6983c5daf460d04f37fcf5e35205e16e02 100644 (file)
@@ -582,6 +582,10 @@ 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_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);
 void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
index e26268805fccfd0b790da83ae21a3f93dca40700..c89f4b4d70b10ce1ca498ffe2f16a22a2e7ec224 100644 (file)
@@ -3267,6 +3267,32 @@ void mlxsw_sp_port_vrf_leave(struct mlxsw_sp_port *mlxsw_sp_port)
        mlxsw_sp_vport_vrf_leave(mlxsw_sp_vport);
 }
 
+int mlxsw_sp_bridge_vrf_join(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 -EINVAL;
+
+       if (f->r)
+               mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->r);
+
+       return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
+}
+
+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->r);
+}
+
 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);