Commit 382d7dcf authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-rif-pvid'

Petr Machata says:

====================
mlxsw: Manage RIF across PVID changes

The mlxsw driver currently makes the assumption that the user applies
configuration in a bottom-up manner. Thus netdevices need to be added to
the bridge before IP addresses are configured on that bridge or SVI added
on top of it. Enslaving a netdevice to another netdevice that already has
uppers is in fact forbidden by mlxsw for this reason. Despite this safety,
it is rather easy to get into situations where the offloaded configuration
is just plain wrong.

As an example, take a front panel port, configure an IP address: it gets a
RIF. Now enslave the port to the bridge, and the RIF is gone. Remove the
port from the bridge again, but the RIF never comes back. There is a number
of similar situations, where changing the configuration there and back
utterly breaks the offload.

The situation is going to be made better by implementing a range of replays
and post-hoc offloads.

In this patch set, address the ordering issues related to creation of
bridge RIFs. Currently, mlxsw has several shortcomings with regards to RIF
handling due to PVID changes:

- In order to cause RIF for a bridge device to be created, the user is
  expected first to set PVID, then to add an IP address. The reverse
  ordering is disallowed, which is not very user-friendly.

- When such bridge gets a VLAN upper whose VID was the same as the existing
  PVID, and this VLAN netdevice gets an IP address, a RIF is created for
  this netdevice. The new RIF is then assigned to the 802.1Q FID for the
  given VID. This results in a working configuration. However, then, when
  the VLAN netdevice is removed again, the RIF for the bridge itself is
  never reassociated to the PVID.

- PVID cannot be changed once the bridge has uppers. Presumably this is
  because the driver does not manage RIFs properly in face of PVID changes.
  However, as the previous point shows, it is still possible to get into
  invalid configurations.

This patch set addresses these issues and relaxes some of the ordering
requirements that mlxsw had. The patch set proceeds as follows:

- In patch #1, pass extack to mlxsw_sp_br_ban_rif_pvid_change()

- To relax ordering between setting PVID and adding an IP address to a
  bridge, mlxsw must be able to request that a RIF is created with a given
  VLAN ID, instead of trying to deduce it from the current netdevice
  settings, which do not reflect the user-requested values yet. This is
  done in patches #2 and #3.

- Similarly, mlxsw_sp_inetaddr_bridge_event() will need to make decisions
  based on the user-requested value of PVID, not the current value. Thus in
  patches #4 and #5, add a new argument which carries the requested PVID
  value.

- Finally in patch #6 relax the ban on PVID changes when a bridge has
  uppers. Instead, add the logic necessary for creation of a RIF as a
  result of PVID change.

- Relevant selftests are presented afterwards. In patch #7 a preparatory
  helper is added to lib.sh. Patches #8, #9, #10 and #11 include selftests
  themselves.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f16276ad 9cbb3da4
......@@ -139,6 +139,7 @@ struct mlxsw_sp_rif_ops {
struct netlink_ext_ack *extack);
void (*deconfigure)(struct mlxsw_sp_rif *rif);
struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack);
void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
};
......@@ -8300,7 +8301,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
rif->rif_entries = rif_entries;
if (ops->fid_get) {
fid = ops->fid_get(rif, extack);
fid = ops->fid_get(rif, params, extack);
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
goto err_fid_get;
......@@ -8410,6 +8411,110 @@ void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
mutex_unlock(&mlxsw_sp->router->lock);
}
static void mlxsw_sp_rif_destroy_vlan_upper(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev,
u16 vid)
{
struct net_device *upper_dev;
struct mlxsw_sp_crif *crif;
rcu_read_lock();
upper_dev = __vlan_find_dev_deep_rcu(br_dev, htons(ETH_P_8021Q), vid);
rcu_read_unlock();
if (!upper_dev)
return;
crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, upper_dev);
if (!crif || !crif->rif)
return;
mlxsw_sp_rif_destroy(crif->rif);
}
static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
struct net_device *l3_dev,
int lower_pvid,
unsigned long event,
struct netlink_ext_ack *extack);
int mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev,
u16 new_vid, bool is_pvid,
struct netlink_ext_ack *extack)
{
struct mlxsw_sp_rif *old_rif;
struct mlxsw_sp_rif *new_rif;
struct net_device *upper_dev;
u16 old_pvid = 0;
u16 new_pvid;
int err = 0;
mutex_lock(&mlxsw_sp->router->lock);
old_rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev);
if (old_rif) {
/* If the RIF on the bridge is not a VLAN RIF, we shouldn't have
* gotten a PVID notification.
*/
if (WARN_ON(old_rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN))
old_rif = NULL;
else
old_pvid = mlxsw_sp_fid_8021q_vid(old_rif->fid);
}
if (is_pvid)
new_pvid = new_vid;
else if (old_pvid == new_vid)
new_pvid = 0;
else
goto out;
if (old_pvid == new_pvid)
goto out;
if (new_pvid) {
struct mlxsw_sp_rif_params params = {
.dev = br_dev,
.vid = new_pvid,
};
/* If there is a VLAN upper with the same VID as the new PVID,
* kill its RIF, if there is one.
*/
mlxsw_sp_rif_destroy_vlan_upper(mlxsw_sp, br_dev, new_pvid);
if (mlxsw_sp_dev_addr_list_empty(br_dev))
goto out;
new_rif = mlxsw_sp_rif_create(mlxsw_sp, &params, extack);
if (IS_ERR(new_rif)) {
err = PTR_ERR(new_rif);
goto out;
}
if (old_pvid)
mlxsw_sp_rif_migrate_destroy(mlxsw_sp, old_rif, new_rif,
true);
} else {
mlxsw_sp_rif_destroy(old_rif);
}
if (old_pvid) {
rcu_read_lock();
upper_dev = __vlan_find_dev_deep_rcu(br_dev, htons(ETH_P_8021Q),
old_pvid);
rcu_read_unlock();
if (upper_dev)
err = mlxsw_sp_inetaddr_bridge_event(mlxsw_sp,
upper_dev,
new_pvid,
NETDEV_UP, extack);
}
out:
mutex_unlock(&mlxsw_sp->router->lock);
return err;
}
static void
mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
......@@ -8664,21 +8769,24 @@ __mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_rif_params params = {
.dev = l3_dev,
};
struct mlxsw_sp_rif_params params;
u16 vid = mlxsw_sp_port_vlan->vid;
struct mlxsw_sp_rif *rif;
struct mlxsw_sp_fid *fid;
int err;
params = (struct mlxsw_sp_rif_params) {
.dev = l3_dev,
.vid = vid,
};
mlxsw_sp_rif_subport_params_init(&params, mlxsw_sp_port_vlan);
rif = mlxsw_sp_rif_subport_get(mlxsw_sp, &params, extack);
if (IS_ERR(rif))
return PTR_ERR(rif);
/* FID was already created, just take a reference */
fid = rif->ops->fid_get(rif, extack);
fid = rif->ops->fid_get(rif, &params, extack);
err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
if (err)
goto err_fid_port_vid_map;
......@@ -8822,6 +8930,7 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
struct net_device *l3_dev,
int lower_pvid,
unsigned long event,
struct netlink_ext_ack *extack)
{
......@@ -8829,6 +8938,7 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
.dev = l3_dev,
};
struct mlxsw_sp_rif *rif;
int err;
switch (event) {
case NETDEV_UP:
......@@ -8840,7 +8950,21 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
NL_SET_ERR_MSG_MOD(extack, "Adding an IP address to 802.1ad bridge is not supported");
return -EOPNOTSUPP;
}
err = br_vlan_get_pvid(l3_dev, &params.vid);
if (err)
return err;
if (!params.vid)
return 0;
} else if (is_vlan_dev(l3_dev)) {
params.vid = vlan_dev_vlan_id(l3_dev);
/* If the VID matches PVID of the bridge below, the
* bridge owns the RIF for this VLAN. Don't do anything.
*/
if ((int)params.vid == lower_pvid)
return 0;
}
rif = mlxsw_sp_rif_create(mlxsw_sp, &params, extack);
if (IS_ERR(rif))
return PTR_ERR(rif);
......@@ -8861,19 +8985,27 @@ static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp,
{
struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
u16 vid = vlan_dev_vlan_id(vlan_dev);
u16 lower_pvid;
int err;
if (netif_is_bridge_port(vlan_dev))
return 0;
if (mlxsw_sp_port_dev_check(real_dev))
if (mlxsw_sp_port_dev_check(real_dev)) {
return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev,
event, vid, extack);
else if (netif_is_lag_master(real_dev))
} else if (netif_is_lag_master(real_dev)) {
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
vid, extack);
else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev, event,
} else if (netif_is_bridge_master(real_dev) &&
br_vlan_enabled(real_dev)) {
err = br_vlan_get_pvid(real_dev, &lower_pvid);
if (err)
return err;
return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev,
lower_pvid, event,
extack);
}
return 0;
}
......@@ -9008,7 +9140,7 @@ static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
else if (netif_is_lag_master(dev))
return mlxsw_sp_inetaddr_lag_event(dev, event, extack);
else if (netif_is_bridge_master(dev))
return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, event,
return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, -1, event,
extack);
else if (is_vlan_dev(dev))
return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event,
......@@ -9724,6 +9856,7 @@ 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,
const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack)
{
return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
......@@ -9836,6 +9969,7 @@ 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,
const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack)
{
int rif_ifindex = mlxsw_sp_rif_dev_ifindex(rif);
......@@ -9869,27 +10003,22 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
static struct mlxsw_sp_fid *
mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif,
const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack)
{
struct net_device *dev = mlxsw_sp_rif_dev(rif);
struct net_device *br_dev;
u16 vid;
int err;
if (WARN_ON(!params->vid))
return ERR_PTR(-EINVAL);
if (is_vlan_dev(dev)) {
vid = vlan_dev_vlan_id(dev);
br_dev = vlan_dev_real_dev(dev);
if (WARN_ON(!netif_is_bridge_master(br_dev)))
return ERR_PTR(-EINVAL);
} else {
err = br_vlan_get_pvid(dev, &vid);
if (err < 0 || !vid) {
NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID");
return ERR_PTR(-EINVAL);
}
}
return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, params->vid);
}
static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
......
......@@ -171,6 +171,10 @@ int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp);
struct net_device *
mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev);
int mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp *mlxsw_sp,
struct net_device *dev,
u16 new_vid, bool is_pvid,
struct netlink_ext_ack *extack);
int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev,
struct netlink_ext_ack *extack);
......
......@@ -1479,29 +1479,15 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
}
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)
mlxsw_sp_br_rif_pvid_change(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack)
{
u16 pvid;
pvid = mlxsw_sp_rif_vid(mlxsw_sp, br_dev);
if (!pvid)
return 0;
if (vlan->flags & BRIDGE_VLAN_INFO_PVID) {
if (vlan->vid != pvid) {
netdev_err(br_dev, "Can't change PVID, it's used by router interface\n");
return -EBUSY;
}
} else {
if (vlan->vid == pvid) {
netdev_err(br_dev, "Can't remove PVID, it's used by router interface\n");
return -EBUSY;
}
}
bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
return 0;
return mlxsw_sp_router_bridge_vlan_add(mlxsw_sp, br_dev, vlan->vid,
flag_pvid, extack);
}
static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
......@@ -1518,8 +1504,8 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
int err = 0;
if (br_vlan_enabled(orig_dev))
err = mlxsw_sp_br_ban_rif_pvid_change(mlxsw_sp,
orig_dev, vlan);
err = mlxsw_sp_br_rif_pvid_change(mlxsw_sp, orig_dev,
vlan, extack);
if (!err)
err = -EOPNOTSUPP;
return err;
......
......@@ -65,6 +65,8 @@ TEST_PROGS = bridge_igmp.sh \
q_in_vni.sh \
router_bridge.sh \
router_bridge_vlan.sh \
router_bridge_pvid_vlan_upper.sh \
router_bridge_vlan_upper_pvid.sh \
router_broadcast.sh \
router_mpath_nh_res.sh \
router_mpath_nh.sh \
......
......@@ -1215,6 +1215,15 @@ ping_test()
log_test "ping$3"
}
ping_test_fails()
{
RET=0
ping_do $1 $2
check_fail $?
log_test "ping fails$3"
}
ping6_do()
{
local if_name=$1
......@@ -1237,6 +1246,15 @@ ping6_test()
log_test "ping6$3"
}
ping6_test_fails()
{
RET=0
ping6_do $1 $2
check_fail $?
log_test "ping6 fails$3"
}
learning_test()
{
local bridge=$1
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# +------------------------+ +----------------------+
# | H1 (vrf) | | H2 (vrf) |
# | + $h1 | | + $h2 |
# | | 192.0.2.1/28 | | | 192.0.2.130/28 |
# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 |
# | | | | | |
# +----|-------------------+ +--|-------------------+
# | |
# +----|--------------------------------------------------|-------------------+
# | SW | | |
# | +--|-----------------------------+ + $swp2 |
# | | + $swp1 BR1 (802.1q) | 192.0.2.129/28 |
# | | 192.0.2.2/28 | 2001:db8:2::1/64 |
# | | 2001:db8:1::1/64 | |
# | | | |
# | +--------------------------------+ |
# +---------------------------------------------------------------------------+
ALL_TESTS="
ping_ipv4
ping_ipv6
config_remove_pvid
ping_ipv4_fails
ping_ipv6_fails
config_add_pvid
ping_ipv4
ping_ipv6
"
NUM_NETIFS=4
source lib.sh
......@@ -62,6 +86,22 @@ router_destroy()
ip link del dev br1
}
config_remove_pvid()
{
log_info "Remove PVID from the bridge"
bridge vlan add dev br1 vid 1 self
sleep 2
}
config_add_pvid()
{
log_info "Add PVID to the bridge"
bridge vlan add dev br1 vid 1 self pvid untagged
sleep 2
}
setup_prepare()
{
h1=${NETIFS[p1]}
......@@ -104,6 +144,16 @@ ping_ipv6()
ping6_test $h1 2001:db8:2::2
}
ping_ipv4_fails()
{
ping_test_fails $h1 192.0.2.130
}
ping_ipv6_fails()
{
ping6_test_fails $h1 2001:db8:2::2
}
trap cleanup EXIT
setup_prepare
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# +----------------------------+
# | H1 (vrf) |
# | + $h1.10 | +----------------------+
# | | 192.0.2.1/28 | | H2 (vrf) |
# | | 2001:db8:1::1/64 | | + $h2 |
# | | | | | 192.0.2.130/28 |
# | + $h1 | | | 2001:db8:2::2/64 |
# +---|------------------------+ +--|-------------------+
# | |
# +---|--------------------------------------------------|-------------------+
# | | router (main VRF) | |
# | +-|----------------------------------+ + $swp2 |
# | | + $swp1 BR1 (802.1q, pvid=10) | 192.0.2.129/28 |
# | | 192.0.2.2/28 | 2001:db8:2::1/64 |
# | | 2001:db8:1::2/64 | |
# | +------------------------------------+ |
# +--------------------------------------------------------------------------+
ALL_TESTS="
ping_ipv4
ping_ipv6
shuffle_pvid
ping_ipv4
ping_ipv6
"
NUM_NETIFS=4
source lib.sh
h1_create()
{
simple_if_init $h1
vlan_create $h1 10 v$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
vlan_destroy $h1 10
simple_if_fini $h1
}
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 address $(mac_get $swp1) \
type bridge vlan_filtering 1 vlan_default_pvid 0
ip link set dev br1 up
__addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64
ip link set dev $swp1 master br1
ip link set dev $swp1 up
ip link set dev $swp2 up
__addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
bridge vlan add dev br1 vid 10 pvid untagged self
bridge vlan add dev $swp1 vid 10
}
router_destroy()
{
bridge vlan del dev $swp1 vid 10
bridge vlan del dev br1 vid 10 self
__addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
ip link set dev $swp2 down
ip link set dev $swp1 down
ip link set dev $swp1 nomaster
__addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64
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
}
shuffle_pvid()
{
log_info "Add and remove VLAN upper for PVID VLAN"
# Adding and removing a VLAN upper for the PVID VLAN shouldn't change
# anything. The address is arbitrary, just to make sure it will be an L3
# netdevice.
vlan_create br1 10 "" 192.0.2.33/28
sleep 1
vlan_destroy br1 10
}
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
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# +------------------------+ +----------------------+
# +------------------------------------------------+ +----------------------+
# | H1 (vrf) | | H2 (vrf) |
# | + $h1.555 | | + $h2 |
# | | 192.0.2.1/28 | | | 192.0.2.130/28 |
# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 |
# | | | | | |
# | + $h1.555 + $h1.777 | | + $h2 |
# | | 192.0.2.1/28 | 192.0.2.17/28 | | | 192.0.2.130/28 |
# | | 2001:db8:1::1/64 | 2001:db8:3::1/64 | | | 192.0.2.146/28 |
# | | .-----------------' | | | 2001:db8:2::2/64 |
# | |/ | | | 2001:db8:4::2/64 |
# | + $h1 | | | |
# +----|-------------------+ +--|-------------------+
# +----|-------------------------------------------+ +--|-------------------+
# | |
# +----|--------------------------------------------------|-------------------+
# | SW | | |
# | +--|-------------------------------+ + $swp2 |
# | | + $swp1 | 192.0.2.129/28 |
# | | vid 555 | 2001:db8:2::1/64 |
# | | | |
# | | + BR1 (802.1q) | |
# | | vid 555 777 | 192.0.2.145/28 |
# | | | 2001:db8:2::1/64 |
# | | + BR1 (802.1q) | 2001:db8:4::1/64 |
# | | vid 555 pvid untagged | |
# | | 192.0.2.2/28 | |
# | | 192.0.2.18/28 | |
# | | 2001:db8:1::2/64 | |
# | | 2001:db8:3::2/64 | |
# | +----------------------------------+ |
# +---------------------------------------------------------------------------+
......@@ -27,6 +30,14 @@ ALL_TESTS="
ping_ipv4
ping_ipv6
vlan
config_777
ping_ipv4_fails
ping_ipv6_fails
ping_ipv4_777
ping_ipv6_777
config_555
ping_ipv4
ping_ipv6
"
NUM_NETIFS=4
source lib.sh
......@@ -34,31 +45,47 @@ source lib.sh
h1_create()
{
simple_if_init $h1
vlan_create $h1 555 v$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
vlan_create $h1 777 v$h1 192.0.2.17/28 2001:db8:3::1/64
ip -4 route add 192.0.2.144/28 vrf v$h1 nexthop via 192.0.2.18
ip -6 route add 2001:db8:4::/64 vrf v$h1 nexthop via 2001:db8:3::2
}
h1_destroy()
{
ip -6 route del 2001:db8:4::/64 vrf v$h1
ip -4 route del 192.0.2.144/28 vrf v$h1
vlan_destroy $h1 777
ip -6 route del 2001:db8:2::/64 vrf v$h1
ip -4 route del 192.0.2.128/28 vrf v$h1
vlan_destroy $h1 555
simple_if_fini $h1
}
h2_create()
{
simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64
simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64 \
192.0.2.146/28 2001:db8:4::2/64
ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129
ip -4 route add 192.0.2.16/28 vrf v$h2 nexthop via 192.0.2.145
ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
ip -6 route add 2001:db8:3::/64 vrf v$h2 nexthop via 2001:db8:4::1
}
h2_destroy()
{
ip -6 route del 2001:db8:3::/64 vrf v$h2
ip -6 route del 2001:db8:1::/64 vrf v$h2
ip -4 route del 192.0.2.16/28 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
simple_if_fini $h2 192.0.2.146/28 2001:db8:4::2/64 \
192.0.2.130/28 2001:db8:2::2/64
}
router_create()
......@@ -71,18 +98,23 @@ router_create()
bridge vlan add dev br1 vid 555 self pvid untagged
bridge vlan add dev $swp1 vid 555
bridge vlan add dev $swp1 vid 777
__addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64
__addr_add_del br1 add 192.0.2.18/28 2001:db8:3::2/64
ip link set dev $swp2 up
__addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
__addr_add_del $swp2 add 192.0.2.145/28 2001:db8:4::1/64
}
router_destroy()
{
__addr_add_del $swp2 del 192.0.2.145/28 2001:db8:4::1/64
__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.18/28 2001:db8:3::2/64
__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
......@@ -108,6 +140,24 @@ setup_prepare()
forwarding_enable
}
config_555()
{
log_info "Configure VLAN 555 as PVID"
bridge vlan add dev br1 vid 555 self pvid untagged
bridge vlan del dev br1 vid 777 self
sleep 2
}
config_777()
{
log_info "Configure VLAN 777 as PVID"
bridge vlan add dev br1 vid 777 self pvid untagged
bridge vlan del dev br1 vid 555 self
sleep 2
}
cleanup()
{
pre_cleanup
......@@ -136,12 +186,32 @@ vlan()
ping_ipv4()
{
ping_test $h1 192.0.2.130
ping_test $h1.555 192.0.2.130
}
ping_ipv6()
{
ping6_test $h1 2001:db8:2::2
ping6_test $h1.555 2001:db8:2::2
}
ping_ipv4_fails()
{
ping_test_fails $h1.555 192.0.2.130 ": via 555"
}
ping_ipv6_fails()
{
ping6_test_fails $h1.555 2001:db8:2::2 ": via 555"
}
ping_ipv4_777()
{
ping_test $h1.777 192.0.2.146 ": via 777"
}
ping_ipv6_777()
{
ping6_test $h1.777 2001:db8:4::2 ": via 777"
}
trap cleanup EXIT
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# +----------------------------+
# | H1 (vrf) |
# | + $h1.10 | +----------------------+
# | | 192.0.2.1/28 | | H2 (vrf) |
# | | 2001:db8:1::1/64 | | + $h2 |
# | | | | | 192.0.2.130/28 |
# | + $h1 | | | 2001:db8:2::2/64 |
# +---|------------------------+ +--|-------------------+
# | |
# +---|--------------------------------------------------|-------------------+
# | | router (main VRF) | |
# | +-|--------------------------+ + $swp2 |
# | | + $swp1 BR1 (802.1q) | 192.0.2.129/28 |
# | +-----+----------------------+ 2001:db8:2::1/64 |
# | | |
# | + br1.10 |
# | 192.0.2.2/28 |
# | 2001:db8:1::2/64 |
# +--------------------------------------------------------------------------+
ALL_TESTS="
ping_ipv4
ping_ipv6
pvid_set_unset
ping_ipv4
ping_ipv6
pvid_set_move
ping_ipv4
ping_ipv6
"
NUM_NETIFS=4
source lib.sh
h1_create()
{
simple_if_init $h1
vlan_create $h1 10 v$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
vlan_destroy $h1 10
simple_if_fini $h1
}
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 address $(mac_get $swp1) \
type bridge vlan_filtering 1 vlan_default_pvid 0
ip link set dev br1 up
ip link set dev $swp1 master br1
ip link set dev $swp1 up
ip link set dev $swp2 up
__addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
bridge vlan add dev br1 vid 10 self
bridge vlan add dev $swp1 vid 10
vlan_create br1 10 "" 192.0.2.2/28 2001:db8:1::2/64
}
router_destroy()
{
vlan_destroy br1 10
bridge vlan del dev $swp1 vid 10
bridge vlan del dev br1 vid 10 self
__addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
ip link set dev $swp2 down
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
}
pvid_set_unset()
{
log_info "Set and unset PVID on VLAN 10"
bridge vlan add dev br1 vid 10 pvid self
sleep 1
bridge vlan add dev br1 vid 10 self
}
pvid_set_move()
{
log_info "Set PVID on VLAN 10, then move it to VLAN 20"
bridge vlan add dev br1 vid 10 pvid self
sleep 1
bridge vlan add dev br1 vid 20 pvid self
}
shuffle_vlan()
{
log_info ""
}
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment