net: bridge: mst: Multiple Spanning Tree (MST) mode
Allow the user to switch from the current per-VLAN STP mode to an MST
mode.
Up to this point, per-VLAN STP states where always isolated from each
other. This is in contrast to the MSTP standard (802.1Q-2018, Clause
13.5), where VLANs are grouped into MST instances (MSTIs), and the
state is managed on a per-MSTI level, rather that at the per-VLAN
level.
Perhaps due to the prevalence of the standard, many switching ASICs
are built after the same model. Therefore, add a corresponding MST
mode to the bridge, which we can later add offloading support for in a
straight-forward way.
For now, all VLANs are fixed to MSTI 0, also called the Common
Spanning Tree (CST). That is, all VLANs will follow the port-global
state.
Upcoming changes will make this actually useful by allowing VLANs to
be mapped to arbitrary MSTIs and allow individual MSTI states to be
changed.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-03-16 16:08:43 +01:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Bridge Multiple Spanning Tree Support
*
* Authors :
* Tobias Waldekranz < tobias @ waldekranz . com >
*/
# include <linux/kernel.h>
# include "br_private.h"
DEFINE_STATIC_KEY_FALSE ( br_mst_used ) ;
static void br_mst_vlan_set_state ( struct net_bridge_port * p , struct net_bridge_vlan * v ,
u8 state )
{
struct net_bridge_vlan_group * vg = nbp_vlan_group ( p ) ;
if ( v - > state = = state )
return ;
br_vlan_set_state ( v , state ) ;
if ( v - > vid = = vg - > pvid )
br_vlan_set_pvid_state ( vg , state ) ;
}
int br_mst_set_state ( struct net_bridge_port * p , u16 msti , u8 state ,
struct netlink_ext_ack * extack )
{
struct net_bridge_vlan_group * vg ;
struct net_bridge_vlan * v ;
vg = nbp_vlan_group ( p ) ;
if ( ! vg )
return 0 ;
list_for_each_entry ( v , & vg - > vlan_list , vlist ) {
if ( v - > brvlan - > msti ! = msti )
continue ;
br_mst_vlan_set_state ( p , v , state ) ;
}
return 0 ;
}
2022-03-16 16:08:44 +01:00
static void br_mst_vlan_sync_state ( struct net_bridge_vlan * pv , u16 msti )
{
struct net_bridge_vlan_group * vg = nbp_vlan_group ( pv - > port ) ;
struct net_bridge_vlan * v ;
list_for_each_entry ( v , & vg - > vlan_list , vlist ) {
/* If this port already has a defined state in this
* MSTI ( through some other VLAN membership ) , inherit
* it .
*/
if ( v ! = pv & & v - > brvlan - > msti = = msti ) {
br_mst_vlan_set_state ( pv - > port , pv , v - > state ) ;
return ;
}
}
/* Otherwise, start out in a new MSTI with all ports disabled. */
return br_mst_vlan_set_state ( pv - > port , pv , BR_STATE_DISABLED ) ;
}
int br_mst_vlan_set_msti ( struct net_bridge_vlan * mv , u16 msti )
{
struct net_bridge_vlan_group * vg ;
struct net_bridge_vlan * pv ;
struct net_bridge_port * p ;
if ( mv - > msti = = msti )
return 0 ;
mv - > msti = msti ;
list_for_each_entry ( p , & mv - > br - > port_list , list ) {
vg = nbp_vlan_group ( p ) ;
pv = br_vlan_find ( vg , mv - > vid ) ;
if ( pv )
br_mst_vlan_sync_state ( pv , msti ) ;
}
return 0 ;
}
net: bridge: mst: Multiple Spanning Tree (MST) mode
Allow the user to switch from the current per-VLAN STP mode to an MST
mode.
Up to this point, per-VLAN STP states where always isolated from each
other. This is in contrast to the MSTP standard (802.1Q-2018, Clause
13.5), where VLANs are grouped into MST instances (MSTIs), and the
state is managed on a per-MSTI level, rather that at the per-VLAN
level.
Perhaps due to the prevalence of the standard, many switching ASICs
are built after the same model. Therefore, add a corresponding MST
mode to the bridge, which we can later add offloading support for in a
straight-forward way.
For now, all VLANs are fixed to MSTI 0, also called the Common
Spanning Tree (CST). That is, all VLANs will follow the port-global
state.
Upcoming changes will make this actually useful by allowing VLANs to
be mapped to arbitrary MSTIs and allow individual MSTI states to be
changed.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-03-16 16:08:43 +01:00
void br_mst_vlan_init_state ( struct net_bridge_vlan * v )
{
/* VLANs always start out in MSTI 0 (CST) */
v - > msti = 0 ;
if ( br_vlan_is_master ( v ) )
v - > state = BR_STATE_FORWARDING ;
else
v - > state = v - > port - > state ;
}
int br_mst_set_enabled ( struct net_bridge * br , bool on ,
struct netlink_ext_ack * extack )
{
struct net_bridge_vlan_group * vg ;
struct net_bridge_port * p ;
list_for_each_entry ( p , & br - > port_list , list ) {
vg = nbp_vlan_group ( p ) ;
if ( ! vg - > num_vlans )
continue ;
NL_SET_ERR_MSG ( extack ,
" MST mode can't be changed while VLANs exist " ) ;
return - EBUSY ;
}
if ( br_opt_get ( br , BROPT_MST_ENABLED ) = = on )
return 0 ;
if ( on )
static_branch_enable ( & br_mst_used ) ;
else
static_branch_disable ( & br_mst_used ) ;
br_opt_toggle ( br , BROPT_MST_ENABLED , on ) ;
return 0 ;
}