Skip to content

Commit

Permalink
Merge branch 'mlxsw-Support-bridge-router-interfaces-with-non-default…
Browse files Browse the repository at this point in the history
…-VLAN'

Ido Schimmel says:

====================
mlxsw: Support bridge router interfaces with non-default VLAN

Petr says:

When traffic is inserted on a router interface associated with an 802.1q
bridge, the VLAN that the traffic appears on is determined by PVID of
the bridge device itself. However currently mlxsw always configures such
traffic to be forwarded to VLAN 1, regardless of the bridge PVID.

Fix the problem by modifying the FID-handling code to assign such
traffic not to FID that corresponds to VLAN 1, but to a FID that
corresponds to the configured PVID. Bail out if there is no PVID. This
is implemented in patches #1 and #2.

From that point on, also forbid any changes to bridge device PVID,
because such changes would not be reflected. This is implemented in
patches #3, #4 and #5.

Finally in patch #6, introduce tests that use bridge as a routed
interface, and test mlxsw in both the currently-supported scenario of
using PVID 1, and the newly-supported one of using a custom PVID.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 26, 2018
2 parents fb22350 + 5b1e7f9 commit 651b451
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 14 deletions.
42 changes: 30 additions & 12 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ struct mlxsw_sp_rif_ops {
const struct mlxsw_sp_rif_params *params);
int (*configure)(struct mlxsw_sp_rif *rif);
void (*deconfigure)(struct mlxsw_sp_rif *rif);
struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif);
struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
struct netlink_ext_ack *extack);
};

static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
Expand Down Expand Up @@ -342,10 +343,6 @@ static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif)
mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
}

static struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev);

#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE + 1)

struct mlxsw_sp_prefix_usage {
Expand Down Expand Up @@ -5967,7 +5964,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
return NOTIFY_DONE;
}

static struct mlxsw_sp_rif *
struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev)
{
Expand Down Expand Up @@ -6125,6 +6122,11 @@ const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif)
return rif->dev;
}

struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif)
{
return rif->fid;
}

static struct mlxsw_sp_rif *
mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_rif_params *params,
Expand Down Expand Up @@ -6162,7 +6164,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
rif->ops = ops;

if (ops->fid_get) {
fid = ops->fid_get(rif);
fid = ops->fid_get(rif, extack);
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
goto err_fid_get;
Expand Down Expand Up @@ -6267,7 +6269,7 @@ mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
}

/* FID was already created, just take a reference */
fid = rif->ops->fid_get(rif);
fid = rif->ops->fid_get(rif, extack);
err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
if (err)
goto err_fid_port_vid_map;
Expand Down Expand Up @@ -6775,7 +6777,8 @@ static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
}

static struct mlxsw_sp_fid *
mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif)
mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif,
struct netlink_ext_ack *extack)
{
return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
}
Expand Down Expand Up @@ -6865,9 +6868,23 @@ static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
}

static struct mlxsw_sp_fid *
mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif)
mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif,
struct netlink_ext_ack *extack)
{
u16 vid = is_vlan_dev(rif->dev) ? vlan_dev_vlan_id(rif->dev) : 1;
u16 vid;
int err;

if (is_vlan_dev(rif->dev)) {
vid = vlan_dev_vlan_id(rif->dev);
} else {
err = br_vlan_get_pvid(rif->dev, &vid);
if (!vid)
err = -EINVAL;
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID");
return ERR_PTR(err);
}
}

return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
}
Expand Down Expand Up @@ -6937,7 +6954,8 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
}

static struct mlxsw_sp_fid *
mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif)
mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif,
struct netlink_ext_ack *extack)
{
return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex);
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ struct mlxsw_sp_neigh_entry;
struct mlxsw_sp_nexthop;
struct mlxsw_sp_ipip_entry;

struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev);
struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
u16 rif_index);
u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
Expand All @@ -75,6 +77,7 @@ u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev);
int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif);
u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp);
const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif);
struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif);
int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif,
enum mlxsw_sp_rif_counter_dir dir,
Expand Down
47 changes: 45 additions & 2 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,39 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}

static int
mlxsw_sp_br_ban_rif_pvid_change(struct mlxsw_sp *mlxsw_sp,
const struct net_device *br_dev,
const struct switchdev_obj_port_vlan *vlan)
{
struct mlxsw_sp_rif *rif;
struct mlxsw_sp_fid *fid;
u16 pvid;
u16 vid;

rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev);
if (!rif)
return 0;
fid = mlxsw_sp_rif_fid(rif);
pvid = mlxsw_sp_fid_8021q_vid(fid);

for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
if (vlan->flags & BRIDGE_VLAN_INFO_PVID) {
if (vid != pvid) {
netdev_err(br_dev, "Can't change PVID, it's used by router interface\n");
return -EBUSY;
}
} else {
if (vid == pvid) {
netdev_err(br_dev, "Can't remove PVID, it's used by router interface\n");
return -EBUSY;
}
}
}

return 0;
}

static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
Expand All @@ -1146,8 +1179,18 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_bridge_port *bridge_port;
u16 vid;

if (netif_is_bridge_master(orig_dev))
return -EOPNOTSUPP;
if (netif_is_bridge_master(orig_dev)) {
int err = 0;

if ((vlan->flags & BRIDGE_VLAN_INFO_BRENTRY) &&
br_vlan_enabled(orig_dev) &&
switchdev_trans_ph_prepare(trans))
err = mlxsw_sp_br_ban_rif_pvid_change(mlxsw_sp,
orig_dev, vlan);
if (!err)
err = -EOPNOTSUPP;
return err;
}

if (switchdev_trans_ph_prepare(trans))
return 0;
Expand Down
113 changes: 113 additions & 0 deletions tools/testing/selftests/net/forwarding/router_bridge.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

ALL_TESTS="
ping_ipv4
ping_ipv6
"
NUM_NETIFS=4
source lib.sh

h1_create()
{
simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2
ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
}

h1_destroy()
{
ip -6 route del 2001:db8:2::/64 vrf v$h1
ip -4 route del 192.0.2.128/28 vrf v$h1
simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
}

h2_create()
{
simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64
ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129
ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
}

h2_destroy()
{
ip -6 route del 2001:db8:1::/64 vrf v$h2
ip -4 route del 192.0.2.0/28 vrf v$h2
simple_if_fini $h2 192.0.2.130/28 2001:db8:2::2/64
}

router_create()
{
ip link add name br1 type bridge vlan_filtering 1
ip link set dev br1 up

ip link set dev $swp1 master br1
ip link set dev $swp1 up
__addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64

ip link set dev $swp2 up
__addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
}

router_destroy()
{
__addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
ip link set dev $swp2 down

__addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64
ip link set dev $swp1 down
ip link set dev $swp1 nomaster

ip link del dev br1
}

setup_prepare()
{
h1=${NETIFS[p1]}
swp1=${NETIFS[p2]}

swp2=${NETIFS[p3]}
h2=${NETIFS[p4]}

vrf_prepare

h1_create
h2_create

router_create

forwarding_enable
}

cleanup()
{
pre_cleanup

forwarding_restore

router_destroy

h2_destroy
h1_destroy

vrf_cleanup
}

ping_ipv4()
{
ping_test $h1 192.0.2.130
}

ping_ipv6()
{
ping6_test $h1 2001:db8:2::2
}

trap cleanup EXIT

setup_prepare
setup_wait

tests_run

exit $EXIT_STATUS
Loading

0 comments on commit 651b451

Please sign in to comment.