diff mbox series

[v2,net-next,02/10] net: bridge: mst: Allow changing a VLAN's MSTI

Message ID 20220301100321.951175-3-tobias@waldekranz.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: bridge: Multiple Spanning Trees | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 18 this patch: 18
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang success Errors and warnings before: 21 this patch: 21
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 23 this patch: 23
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 114 lines checked
netdev/kdoc success Errors and warnings before: 3 this patch: 3
netdev/source_inline success Was 0 now: 0

Commit Message

Tobias Waldekranz March 1, 2022, 10:03 a.m. UTC
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: Tobias Waldekranz <tobias@waldekranz.com>
---
 include/uapi/linux/if_bridge.h |  1 +
 net/bridge/br_mst.c            | 39 ++++++++++++++++++++++++++++++++++
 net/bridge/br_private.h        |  1 +
 net/bridge/br_vlan_options.c   | 19 +++++++++++++++--
 4 files changed, 58 insertions(+), 2 deletions(-)

Comments

Vladimir Oltean March 3, 2022, 10:27 p.m. UTC | #1
On Tue, Mar 01, 2022 at 11:03:13AM +0100, Tobias Waldekranz wrote:
> 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: Tobias Waldekranz <tobias@waldekranz.com>
> ---

> +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;

No attempt to detect non-changes to the MSTI, and exit early? In a later
patch you will also notify switchdev uselessly because of this.

> +
> +	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;
> +}
Tobias Waldekranz March 7, 2022, 2:54 p.m. UTC | #2
On Fri, Mar 04, 2022 at 00:27, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Tue, Mar 01, 2022 at 11:03:13AM +0100, Tobias Waldekranz wrote:
>> 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: Tobias Waldekranz <tobias@waldekranz.com>
>> ---
>
>> +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;
>
> No attempt to detect non-changes to the MSTI, and exit early? In a later
> patch you will also notify switchdev uselessly because of this.

Yeah you're right. Will fix in v3. Thanks
diff mbox series

Patch

diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 2711c3522010..b68016f625b7 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -564,6 +564,7 @@  enum {
 	BRIDGE_VLANDB_GOPTS_MCAST_QUERIER,
 	BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS,
 	BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE,
+	BRIDGE_VLANDB_GOPTS_MSTI,
 	__BRIDGE_VLANDB_GOPTS_MAX
 };
 #define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1)
diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c
index ad6e91670fa8..f3b8e279b85c 100644
--- a/net/bridge/br_mst.c
+++ b/net/bridge/br_mst.c
@@ -43,6 +43,45 @@  void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state)
 	}
 }
 
+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;
+
+	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)
 {
 	/* VLANs always start out in MSTI 0 (CST) */
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index af50ad036b06..63601043abca 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -1779,6 +1779,7 @@  static inline bool br_mst_is_enabled(struct net_bridge *br)
 }
 
 void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state);
+int br_mst_vlan_set_msti(struct net_bridge_vlan *v, u16 msti);
 void br_mst_vlan_init_state(struct net_bridge_vlan *v);
 int br_mst_set_enabled(struct net_bridge *br, unsigned long val);
 #else
diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c
index 09112b56e79c..87a9c80d26d3 100644
--- a/net/bridge/br_vlan_options.c
+++ b/net/bridge/br_vlan_options.c
@@ -44,8 +44,8 @@  bool br_vlan_opts_eq_range(const struct net_bridge_vlan *v_curr,
 	u8 curr_mc_rtr = br_vlan_multicast_router(v_curr);
 
 	return v_curr->state == range_end->state &&
-	       __vlan_tun_can_enter_range(v_curr, range_end) &&
-	       curr_mc_rtr == range_mc_rtr;
+		__vlan_tun_can_enter_range(v_curr, range_end) &&
+		curr_mc_rtr == range_mc_rtr;
 }
 
 bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v)
@@ -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)
 {
 	return v_curr->vid - r_end->vid == 1 &&
+		v_curr->msti == r_end->msti &&
 	       ((v_curr->priv_flags ^ r_end->priv_flags) &
 		BR_VLFLAG_GLOBAL_MCAST_ENABLED) == 0 &&
 		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,
 #endif
 #endif
 
+	if (nla_put_u16(skb, BRIDGE_VLANDB_GOPTS_MSTI, v_opts->msti))
+		goto out_err;
+
 	nla_nest_end(skb, nest);
 
 	return true;
@@ -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 */
 		+ br_rports_size(&v->br_mcast_ctx) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */
 #endif
+		+ nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_GOPTS_MSTI */
 		+ 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,
 	}
 #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;
 }
@@ -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_STARTUP_QUERY_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,