Commit 8c678d60 authored by Tobias Waldekranz's avatar Tobias Waldekranz Committed by Jakub Kicinski

net: bridge: mst: Allow changing a VLAN's MSTI

Allow a VLAN to move out of the CST (MSTI 0), to an independent tree.

The user manages the VID to MSTI mappings via a global VLAN
setting. The proposed iproute2 interface would be:

    bridge vlan global set dev br0 vid <VID> msti <MSTI>

Changing the state in non-zero MSTIs is still not supported, but will
be addressed in upcoming changes.
Signed-off-by: default avatarTobias Waldekranz <tobias@waldekranz.com>
Acked-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent ec7328b5
...@@ -564,6 +564,7 @@ enum { ...@@ -564,6 +564,7 @@ enum {
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER, BRIDGE_VLANDB_GOPTS_MCAST_QUERIER,
BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS, BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS,
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE, BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE,
BRIDGE_VLANDB_GOPTS_MSTI,
__BRIDGE_VLANDB_GOPTS_MAX __BRIDGE_VLANDB_GOPTS_MAX
}; };
#define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1) #define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1)
......
...@@ -46,6 +46,48 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, ...@@ -46,6 +46,48 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
return 0; return 0;
} }
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;
}
void br_mst_vlan_init_state(struct net_bridge_vlan *v) void br_mst_vlan_init_state(struct net_bridge_vlan *v)
{ {
/* VLANs always start out in MSTI 0 (CST) */ /* VLANs always start out in MSTI 0 (CST) */
......
...@@ -1780,6 +1780,7 @@ static inline bool br_mst_is_enabled(struct net_bridge *br) ...@@ -1780,6 +1780,7 @@ static inline bool br_mst_is_enabled(struct net_bridge *br)
int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int br_mst_vlan_set_msti(struct net_bridge_vlan *v, u16 msti);
void br_mst_vlan_init_state(struct net_bridge_vlan *v); void br_mst_vlan_init_state(struct net_bridge_vlan *v);
int br_mst_set_enabled(struct net_bridge *br, bool on, int br_mst_set_enabled(struct net_bridge *br, bool on,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
......
...@@ -296,6 +296,7 @@ bool br_vlan_global_opts_can_enter_range(const struct net_bridge_vlan *v_curr, ...@@ -296,6 +296,7 @@ bool br_vlan_global_opts_can_enter_range(const struct net_bridge_vlan *v_curr,
const struct net_bridge_vlan *r_end) const struct net_bridge_vlan *r_end)
{ {
return v_curr->vid - r_end->vid == 1 && return v_curr->vid - r_end->vid == 1 &&
v_curr->msti == r_end->msti &&
((v_curr->priv_flags ^ r_end->priv_flags) & ((v_curr->priv_flags ^ r_end->priv_flags) &
BR_VLFLAG_GLOBAL_MCAST_ENABLED) == 0 && BR_VLFLAG_GLOBAL_MCAST_ENABLED) == 0 &&
br_multicast_ctx_options_equal(&v_curr->br_mcast_ctx, br_multicast_ctx_options_equal(&v_curr->br_mcast_ctx,
...@@ -384,6 +385,9 @@ bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range, ...@@ -384,6 +385,9 @@ bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range,
#endif #endif
#endif #endif
if (nla_put_u16(skb, BRIDGE_VLANDB_GOPTS_MSTI, v_opts->msti))
goto out_err;
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
return true; return true;
...@@ -415,6 +419,7 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(const struct net_bridge_vlan *v) ...@@ -415,6 +419,7 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(const struct net_bridge_vlan *v)
+ nla_total_size(0) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */ + nla_total_size(0) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */
+ br_rports_size(&v->br_mcast_ctx) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */ + br_rports_size(&v->br_mcast_ctx) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */
#endif #endif
+ nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_GOPTS_MSTI */
+ nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */ + nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */
} }
...@@ -564,6 +569,15 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br, ...@@ -564,6 +569,15 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br,
} }
#endif #endif
#endif #endif
if (tb[BRIDGE_VLANDB_GOPTS_MSTI]) {
u16 msti;
msti = nla_get_u16(tb[BRIDGE_VLANDB_GOPTS_MSTI]);
err = br_mst_vlan_set_msti(v, msti);
if (err)
return err;
*changed = true;
}
return 0; return 0;
} }
...@@ -583,6 +597,7 @@ static const struct nla_policy br_vlan_db_gpol[BRIDGE_VLANDB_GOPTS_MAX + 1] = { ...@@ -583,6 +597,7 @@ static const struct nla_policy br_vlan_db_gpol[BRIDGE_VLANDB_GOPTS_MAX + 1] = {
[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL] = { .type = NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL] = { .type = NLA_U64 },
[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL] = { .type = NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL] = { .type = NLA_U64 },
[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL] = { .type = NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL] = { .type = NLA_U64 },
[BRIDGE_VLANDB_GOPTS_MSTI] = NLA_POLICY_MAX(NLA_U16, VLAN_N_VID - 1),
}; };
int br_vlan_rtm_process_global_options(struct net_device *dev, int br_vlan_rtm_process_global_options(struct net_device *dev,
......
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