Skip to content

Commit

Permalink
mlxsw: spectrum: Enable VxLAN enslavement to VLAN-aware bridges
Browse files Browse the repository at this point in the history
Commit 1c30d18 ("mlxsw: spectrum: Enable VxLAN enslavement to
bridges") enabled the enslavement of VxLAN devices to bridges that have
mlxsw ports (or their upper) as slaves. This patch extends mlxsw to also
support VLAN-aware bridges.

The patch is similar in nature to mentioned commit, but there is one
major difference. With VLAN-aware bridges, the VxLAN device's VNI is
mapped to the VLAN that is configured as PVID and egress untagged on the
bridge port.

Therefore, the driver is extended to listen to VLAN configuration on
VxLAN devices of interest and enable / disable NVE encapsulation on the
corresponding 802.1Q FIDs.

To prevent ambiguity, the driver makes sure that a given VLAN is not
configured as PVID and egress untagged on multiple VxLAN devices. This
sanitization takes place both when a port is enslaved to a bridge with
existing VxLAN devices and when a VLAN is added to / removed from a
VxLAN device of interest.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Petr Machata <petrm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ido Schimmel authored and David S. Miller committed Dec 1, 2018
1 parent 48fde46 commit d70e42b
Show file tree
Hide file tree
Showing 3 changed files with 404 additions and 14 deletions.
45 changes: 41 additions & 4 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,9 +5197,20 @@ 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, 0, extack);
} else {
/* 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;
Expand Down
21 changes: 21 additions & 0 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
Loading

0 comments on commit d70e42b

Please sign in to comment.