Skip to content

Commit

Permalink
Merge branch 'mlxsw-Add-VxLAN-support-with-VLAN-aware-bridges'
Browse files Browse the repository at this point in the history
Ido Schimmel says:

====================
mlxsw: Add VxLAN support with VLAN-aware bridges

Commit 53e50a6 ("Merge branch 'mlxsw-Add-VxLAN-support'") added
mlxsw support for VxLAN when the VxLAN device was enslaved to
VLAN-unaware bridges. This patchset extends mlxsw to also support VxLAN
with VLAN-aware bridges.

With VLAN-aware bridges, the VxLAN device's VNI is mapped to the VLAN
that is configured as 'pvid untagged' on the corresponding bridge port.
To prevent ambiguity, mlxsw forbids configurations in which the same
VLAN is configured as 'pvid untagged' on multiple VxLAN devices.

Patches #1-#2 add the necessary APIs in mlxsw and the bridge driver.

Patches #3-#4 perform small refactoring in order to prepare mlxsw for
VLAN-aware support.

Patch #5 finally enables the enslavement of VxLAN devices to a
VLAN-aware bridge. Among other things, it extends mlxsw to handle
switchdev notifications about VLAN add / delete on a VxLAN device
enslaved to an offloaded VLAN-aware bridge.

Patches #6-#8 add selftests to test the new functionality.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 1, 2018
2 parents 734317d + b5166d7 commit f4bb495
Show file tree
Hide file tree
Showing 8 changed files with 1,441 additions and 63 deletions.
53 changes: 45 additions & 8 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -4782,6 +4782,30 @@ static bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev)
return num_vxlans > 1;
}

static bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev)
{
DECLARE_BITMAP(vlans, VLAN_N_VID) = {0};
struct net_device *dev;
struct list_head *iter;

netdev_for_each_lower_dev(br_dev, dev, iter) {
u16 pvid;
int err;

if (!netif_is_vxlan(dev))
continue;

err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid);
if (err || !pvid)
continue;

if (test_and_set_bit(pvid, vlans))
return false;
}

return true;
}

static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,
struct netlink_ext_ack *extack)
{
Expand All @@ -4790,13 +4814,15 @@ static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,
return false;
}

if (br_vlan_enabled(br_dev)) {
NL_SET_ERR_MSG_MOD(extack, "VLAN filtering can not be enabled on a bridge with a VxLAN device");
if (!br_vlan_enabled(br_dev) &&
mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) {
NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge");
return false;
}

if (mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) {
NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge");
if (br_vlan_enabled(br_dev) &&
!mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) {
NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged");
return false;
}

Expand Down Expand Up @@ -5171,10 +5197,21 @@ static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
if (cu_info->linking) {
if (!netif_running(dev))
return 0;
/* When the bridge is VLAN-aware, the VNI of the VxLAN
* device needs to be mapped to a VLAN, but at this
* point no VLANs are configured on the VxLAN device
*/
if (br_vlan_enabled(upper_dev))
return 0;
return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev,
dev, extack);
dev, 0, extack);
} else {
mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev);
/* VLANs were already flushed, which triggered the
* necessary cleanup
*/
if (br_vlan_enabled(upper_dev))
return 0;
mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);
}
break;
case NETDEV_PRE_UP:
Expand All @@ -5185,7 +5222,7 @@ static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
return 0;
if (!mlxsw_sp_lower_get(upper_dev))
return 0;
return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev,
return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0,
extack);
case NETDEV_DOWN:
upper_dev = netdev_master_upper_dev_get(dev);
Expand All @@ -5195,7 +5232,7 @@ static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
return 0;
if (!mlxsw_sp_lower_get(upper_dev))
return 0;
mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev);
mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);
break;
}

Expand Down
26 changes: 24 additions & 2 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include <linux/rhashtable.h>
#include <linux/bitops.h>
#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
#include <linux/list.h>
#include <linux/dcbnl.h>
Expand Down Expand Up @@ -261,6 +262,26 @@ static inline bool mlxsw_sp_bridge_has_vxlan(struct net_device *br_dev)
return !!mlxsw_sp_bridge_vxlan_dev_find(br_dev);
}

static inline int
mlxsw_sp_vxlan_mapped_vid(const struct net_device *vxlan_dev, u16 *p_vid)
{
struct bridge_vlan_info vinfo;
u16 vid = 0;
int err;

err = br_vlan_get_pvid(vxlan_dev, &vid);
if (err || !vid)
goto out;

err = br_vlan_get_info(vxlan_dev, vid, &vinfo);
if (err || !(vinfo.flags & BRIDGE_VLAN_INFO_UNTAGGED))
vid = 0;

out:
*p_vid = vid;
return err;
}

static inline bool
mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port)
{
Expand Down Expand Up @@ -358,10 +379,9 @@ bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *br_dev);
int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp,
const struct net_device *br_dev,
const struct net_device *vxlan_dev,
const struct net_device *vxlan_dev, u16 vid,
struct netlink_ext_ack *extack);
void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp,
const struct net_device *br_dev,
const struct net_device *vxlan_dev);

/* spectrum.c */
Expand Down Expand Up @@ -753,6 +773,8 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
int br_ifindex);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
u16 vid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
int br_ifindex);
struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,12 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
}

struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
u16 vid)
{
return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
}

struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
int br_ifindex)
{
Expand Down
Loading

0 comments on commit f4bb495

Please sign in to comment.