Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Feb 10-13, 2025
Register
Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *	Bridge Multiple Spanning Tree Support
  4 *
  5 *	Authors:
  6 *	Tobias Waldekranz		<tobias@waldekranz.com>
  7 */
  8
  9#include <linux/kernel.h>
 10#include <net/switchdev.h>
 11
 12#include "br_private.h"
 13
 14DEFINE_STATIC_KEY_FALSE(br_mst_used);
 15
 16bool br_mst_enabled(const struct net_device *dev)
 17{
 18	if (!netif_is_bridge_master(dev))
 19		return false;
 20
 21	return br_opt_get(netdev_priv(dev), BROPT_MST_ENABLED);
 22}
 23EXPORT_SYMBOL_GPL(br_mst_enabled);
 24
 25int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids)
 26{
 27	const struct net_bridge_vlan_group *vg;
 28	const struct net_bridge_vlan *v;
 29	const struct net_bridge *br;
 30
 31	ASSERT_RTNL();
 32
 33	if (!netif_is_bridge_master(dev))
 34		return -EINVAL;
 35
 36	br = netdev_priv(dev);
 37	if (!br_opt_get(br, BROPT_MST_ENABLED))
 38		return -EINVAL;
 39
 40	vg = br_vlan_group(br);
 41
 42	list_for_each_entry(v, &vg->vlan_list, vlist) {
 43		if (v->msti == msti)
 44			__set_bit(v->vid, vids);
 45	}
 46
 47	return 0;
 48}
 49EXPORT_SYMBOL_GPL(br_mst_get_info);
 50
 51int br_mst_get_state(const struct net_device *dev, u16 msti, u8 *state)
 52{
 53	const struct net_bridge_port *p = NULL;
 54	const struct net_bridge_vlan_group *vg;
 55	const struct net_bridge_vlan *v;
 56
 57	ASSERT_RTNL();
 58
 59	p = br_port_get_check_rtnl(dev);
 60	if (!p || !br_opt_get(p->br, BROPT_MST_ENABLED))
 61		return -EINVAL;
 62
 63	vg = nbp_vlan_group(p);
 64
 65	list_for_each_entry(v, &vg->vlan_list, vlist) {
 66		if (v->brvlan->msti == msti) {
 67			*state = v->state;
 68			return 0;
 69		}
 70	}
 71
 72	return -ENOENT;
 73}
 74EXPORT_SYMBOL_GPL(br_mst_get_state);
 75
 76static void br_mst_vlan_set_state(struct net_bridge_port *p, struct net_bridge_vlan *v,
 77				  u8 state)
 78{
 79	struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
 80
 81	if (v->state == state)
 82		return;
 83
 84	br_vlan_set_state(v, state);
 85
 86	if (v->vid == vg->pvid)
 87		br_vlan_set_pvid_state(vg, state);
 88}
 89
 90int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
 91		     struct netlink_ext_ack *extack)
 92{
 93	struct switchdev_attr attr = {
 94		.id = SWITCHDEV_ATTR_ID_PORT_MST_STATE,
 95		.orig_dev = p->dev,
 96		.u.mst_state = {
 97			.msti = msti,
 98			.state = state,
 99		},
100	};
101	struct net_bridge_vlan_group *vg;
102	struct net_bridge_vlan *v;
103	int err;
104
 
105	vg = nbp_vlan_group(p);
106	if (!vg)
107		return 0;
108
109	/* MSTI 0 (CST) state changes are notified via the regular
110	 * SWITCHDEV_ATTR_ID_PORT_STP_STATE.
111	 */
112	if (msti) {
113		err = switchdev_port_attr_set(p->dev, &attr, extack);
114		if (err && err != -EOPNOTSUPP)
115			return err;
116	}
117
118	list_for_each_entry(v, &vg->vlan_list, vlist) {
 
119		if (v->brvlan->msti != msti)
120			continue;
121
122		br_mst_vlan_set_state(p, v, state);
123	}
124
125	return 0;
 
 
126}
127
128static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
129{
130	struct net_bridge_vlan_group *vg = nbp_vlan_group(pv->port);
131	struct net_bridge_vlan *v;
132
133	list_for_each_entry(v, &vg->vlan_list, vlist) {
134		/* If this port already has a defined state in this
135		 * MSTI (through some other VLAN membership), inherit
136		 * it.
137		 */
138		if (v != pv && v->brvlan->msti == msti) {
139			br_mst_vlan_set_state(pv->port, pv, v->state);
140			return;
141		}
142	}
143
144	/* Otherwise, start out in a new MSTI with all ports disabled. */
145	return br_mst_vlan_set_state(pv->port, pv, BR_STATE_DISABLED);
146}
147
148int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti)
149{
150	struct switchdev_attr attr = {
151		.id = SWITCHDEV_ATTR_ID_VLAN_MSTI,
152		.orig_dev = mv->br->dev,
153		.u.vlan_msti = {
154			.vid = mv->vid,
155			.msti = msti,
156		},
157	};
158	struct net_bridge_vlan_group *vg;
159	struct net_bridge_vlan *pv;
160	struct net_bridge_port *p;
161	int err;
162
163	if (mv->msti == msti)
164		return 0;
165
166	err = switchdev_port_attr_set(mv->br->dev, &attr, NULL);
167	if (err && err != -EOPNOTSUPP)
168		return err;
169
170	mv->msti = msti;
171
172	list_for_each_entry(p, &mv->br->port_list, list) {
173		vg = nbp_vlan_group(p);
174
175		pv = br_vlan_find(vg, mv->vid);
176		if (pv)
177			br_mst_vlan_sync_state(pv, msti);
178	}
179
180	return 0;
181}
182
183void br_mst_vlan_init_state(struct net_bridge_vlan *v)
184{
185	/* VLANs always start out in MSTI 0 (CST) */
186	v->msti = 0;
187
188	if (br_vlan_is_master(v))
189		v->state = BR_STATE_FORWARDING;
190	else
191		v->state = v->port->state;
192}
193
194int br_mst_set_enabled(struct net_bridge *br, bool on,
195		       struct netlink_ext_ack *extack)
196{
197	struct switchdev_attr attr = {
198		.id = SWITCHDEV_ATTR_ID_BRIDGE_MST,
199		.orig_dev = br->dev,
200		.u.mst = on,
201	};
202	struct net_bridge_vlan_group *vg;
203	struct net_bridge_port *p;
204	int err;
205
206	list_for_each_entry(p, &br->port_list, list) {
207		vg = nbp_vlan_group(p);
208
209		if (!vg->num_vlans)
210			continue;
211
212		NL_SET_ERR_MSG(extack,
213			       "MST mode can't be changed while VLANs exist");
214		return -EBUSY;
215	}
216
217	if (br_opt_get(br, BROPT_MST_ENABLED) == on)
218		return 0;
219
220	err = switchdev_port_attr_set(br->dev, &attr, extack);
221	if (err && err != -EOPNOTSUPP)
222		return err;
223
224	if (on)
225		static_branch_enable(&br_mst_used);
226	else
227		static_branch_disable(&br_mst_used);
228
229	br_opt_toggle(br, BROPT_MST_ENABLED, on);
230	return 0;
231}
232
233size_t br_mst_info_size(const struct net_bridge_vlan_group *vg)
234{
235	DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
236	const struct net_bridge_vlan *v;
237	size_t sz;
238
239	/* IFLA_BRIDGE_MST */
240	sz = nla_total_size(0);
241
242	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
243		if (test_bit(v->brvlan->msti, seen))
244			continue;
245
246		/* IFLA_BRIDGE_MST_ENTRY */
247		sz += nla_total_size(0) +
248			/* IFLA_BRIDGE_MST_ENTRY_MSTI */
249			nla_total_size(sizeof(u16)) +
250			/* IFLA_BRIDGE_MST_ENTRY_STATE */
251			nla_total_size(sizeof(u8));
252
253		__set_bit(v->brvlan->msti, seen);
254	}
255
256	return sz;
257}
258
259int br_mst_fill_info(struct sk_buff *skb,
260		     const struct net_bridge_vlan_group *vg)
261{
262	DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
263	const struct net_bridge_vlan *v;
264	struct nlattr *nest;
265	int err = 0;
266
267	list_for_each_entry(v, &vg->vlan_list, vlist) {
268		if (test_bit(v->brvlan->msti, seen))
269			continue;
270
271		nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
272		if (!nest ||
273		    nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) ||
274		    nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
275			err = -EMSGSIZE;
276			break;
277		}
278		nla_nest_end(skb, nest);
279
280		__set_bit(v->brvlan->msti, seen);
281	}
282
283	return err;
284}
285
286static const struct nla_policy br_mst_nl_policy[IFLA_BRIDGE_MST_ENTRY_MAX + 1] = {
287	[IFLA_BRIDGE_MST_ENTRY_MSTI] = NLA_POLICY_RANGE(NLA_U16,
288						   1, /* 0 reserved for CST */
289						   VLAN_N_VID - 1),
290	[IFLA_BRIDGE_MST_ENTRY_STATE] = NLA_POLICY_RANGE(NLA_U8,
291						    BR_STATE_DISABLED,
292						    BR_STATE_BLOCKING),
293};
294
295static int br_mst_process_one(struct net_bridge_port *p,
296			      const struct nlattr *attr,
297			      struct netlink_ext_ack *extack)
298{
299	struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
300	u16 msti;
301	u8 state;
302	int err;
303
304	err = nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
305			       br_mst_nl_policy, extack);
306	if (err)
307		return err;
308
309	if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI]) {
310		NL_SET_ERR_MSG_MOD(extack, "MSTI not specified");
311		return -EINVAL;
312	}
313
314	if (!tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
315		NL_SET_ERR_MSG_MOD(extack, "State not specified");
316		return -EINVAL;
317	}
318
319	msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
320	state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
321
322	return br_mst_set_state(p, msti, state, extack);
323}
324
325int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
326		   struct netlink_ext_ack *extack)
327{
328	struct nlattr *attr;
329	int err, msts = 0;
330	int rem;
331
332	if (!br_opt_get(p->br, BROPT_MST_ENABLED)) {
333		NL_SET_ERR_MSG_MOD(extack, "Can't modify MST state when MST is disabled");
334		return -EBUSY;
335	}
336
337	nla_for_each_nested(attr, mst_attr, rem) {
338		switch (nla_type(attr)) {
339		case IFLA_BRIDGE_MST_ENTRY:
340			err = br_mst_process_one(p, attr, extack);
341			break;
342		default:
343			continue;
344		}
345
346		msts++;
347		if (err)
348			break;
349	}
350
351	if (!msts) {
352		NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process");
353		err = -EINVAL;
354	}
355
356	return err;
357}
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *	Bridge Multiple Spanning Tree Support
  4 *
  5 *	Authors:
  6 *	Tobias Waldekranz		<tobias@waldekranz.com>
  7 */
  8
  9#include <linux/kernel.h>
 10#include <net/switchdev.h>
 11
 12#include "br_private.h"
 13
 14DEFINE_STATIC_KEY_FALSE(br_mst_used);
 15
 16bool br_mst_enabled(const struct net_device *dev)
 17{
 18	if (!netif_is_bridge_master(dev))
 19		return false;
 20
 21	return br_opt_get(netdev_priv(dev), BROPT_MST_ENABLED);
 22}
 23EXPORT_SYMBOL_GPL(br_mst_enabled);
 24
 25int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids)
 26{
 27	const struct net_bridge_vlan_group *vg;
 28	const struct net_bridge_vlan *v;
 29	const struct net_bridge *br;
 30
 31	ASSERT_RTNL();
 32
 33	if (!netif_is_bridge_master(dev))
 34		return -EINVAL;
 35
 36	br = netdev_priv(dev);
 37	if (!br_opt_get(br, BROPT_MST_ENABLED))
 38		return -EINVAL;
 39
 40	vg = br_vlan_group(br);
 41
 42	list_for_each_entry(v, &vg->vlan_list, vlist) {
 43		if (v->msti == msti)
 44			__set_bit(v->vid, vids);
 45	}
 46
 47	return 0;
 48}
 49EXPORT_SYMBOL_GPL(br_mst_get_info);
 50
 51int br_mst_get_state(const struct net_device *dev, u16 msti, u8 *state)
 52{
 53	const struct net_bridge_port *p = NULL;
 54	const struct net_bridge_vlan_group *vg;
 55	const struct net_bridge_vlan *v;
 56
 57	ASSERT_RTNL();
 58
 59	p = br_port_get_check_rtnl(dev);
 60	if (!p || !br_opt_get(p->br, BROPT_MST_ENABLED))
 61		return -EINVAL;
 62
 63	vg = nbp_vlan_group(p);
 64
 65	list_for_each_entry(v, &vg->vlan_list, vlist) {
 66		if (v->brvlan->msti == msti) {
 67			*state = v->state;
 68			return 0;
 69		}
 70	}
 71
 72	return -ENOENT;
 73}
 74EXPORT_SYMBOL_GPL(br_mst_get_state);
 75
 76static void br_mst_vlan_set_state(struct net_bridge_port *p, struct net_bridge_vlan *v,
 77				  u8 state)
 78{
 79	struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
 80
 81	if (br_vlan_get_state(v) == state)
 82		return;
 83
 84	br_vlan_set_state(v, state);
 85
 86	if (v->vid == vg->pvid)
 87		br_vlan_set_pvid_state(vg, state);
 88}
 89
 90int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
 91		     struct netlink_ext_ack *extack)
 92{
 93	struct switchdev_attr attr = {
 94		.id = SWITCHDEV_ATTR_ID_PORT_MST_STATE,
 95		.orig_dev = p->dev,
 96		.u.mst_state = {
 97			.msti = msti,
 98			.state = state,
 99		},
100	};
101	struct net_bridge_vlan_group *vg;
102	struct net_bridge_vlan *v;
103	int err = 0;
104
105	rcu_read_lock();
106	vg = nbp_vlan_group(p);
107	if (!vg)
108		goto out;
109
110	/* MSTI 0 (CST) state changes are notified via the regular
111	 * SWITCHDEV_ATTR_ID_PORT_STP_STATE.
112	 */
113	if (msti) {
114		err = switchdev_port_attr_set(p->dev, &attr, extack);
115		if (err && err != -EOPNOTSUPP)
116			goto out;
117	}
118
119	err = 0;
120	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
121		if (v->brvlan->msti != msti)
122			continue;
123
124		br_mst_vlan_set_state(p, v, state);
125	}
126
127out:
128	rcu_read_unlock();
129	return err;
130}
131
132static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
133{
134	struct net_bridge_vlan_group *vg = nbp_vlan_group(pv->port);
135	struct net_bridge_vlan *v;
136
137	list_for_each_entry(v, &vg->vlan_list, vlist) {
138		/* If this port already has a defined state in this
139		 * MSTI (through some other VLAN membership), inherit
140		 * it.
141		 */
142		if (v != pv && v->brvlan->msti == msti) {
143			br_mst_vlan_set_state(pv->port, pv, v->state);
144			return;
145		}
146	}
147
148	/* Otherwise, start out in a new MSTI with all ports disabled. */
149	return br_mst_vlan_set_state(pv->port, pv, BR_STATE_DISABLED);
150}
151
152int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti)
153{
154	struct switchdev_attr attr = {
155		.id = SWITCHDEV_ATTR_ID_VLAN_MSTI,
156		.orig_dev = mv->br->dev,
157		.u.vlan_msti = {
158			.vid = mv->vid,
159			.msti = msti,
160		},
161	};
162	struct net_bridge_vlan_group *vg;
163	struct net_bridge_vlan *pv;
164	struct net_bridge_port *p;
165	int err;
166
167	if (mv->msti == msti)
168		return 0;
169
170	err = switchdev_port_attr_set(mv->br->dev, &attr, NULL);
171	if (err && err != -EOPNOTSUPP)
172		return err;
173
174	mv->msti = msti;
175
176	list_for_each_entry(p, &mv->br->port_list, list) {
177		vg = nbp_vlan_group(p);
178
179		pv = br_vlan_find(vg, mv->vid);
180		if (pv)
181			br_mst_vlan_sync_state(pv, msti);
182	}
183
184	return 0;
185}
186
187void br_mst_vlan_init_state(struct net_bridge_vlan *v)
188{
189	/* VLANs always start out in MSTI 0 (CST) */
190	v->msti = 0;
191
192	if (br_vlan_is_master(v))
193		v->state = BR_STATE_FORWARDING;
194	else
195		v->state = v->port->state;
196}
197
198int br_mst_set_enabled(struct net_bridge *br, bool on,
199		       struct netlink_ext_ack *extack)
200{
201	struct switchdev_attr attr = {
202		.id = SWITCHDEV_ATTR_ID_BRIDGE_MST,
203		.orig_dev = br->dev,
204		.u.mst = on,
205	};
206	struct net_bridge_vlan_group *vg;
207	struct net_bridge_port *p;
208	int err;
209
210	list_for_each_entry(p, &br->port_list, list) {
211		vg = nbp_vlan_group(p);
212
213		if (!vg->num_vlans)
214			continue;
215
216		NL_SET_ERR_MSG(extack,
217			       "MST mode can't be changed while VLANs exist");
218		return -EBUSY;
219	}
220
221	if (br_opt_get(br, BROPT_MST_ENABLED) == on)
222		return 0;
223
224	err = switchdev_port_attr_set(br->dev, &attr, extack);
225	if (err && err != -EOPNOTSUPP)
226		return err;
227
228	if (on)
229		static_branch_enable(&br_mst_used);
230	else
231		static_branch_disable(&br_mst_used);
232
233	br_opt_toggle(br, BROPT_MST_ENABLED, on);
234	return 0;
235}
236
237size_t br_mst_info_size(const struct net_bridge_vlan_group *vg)
238{
239	DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
240	const struct net_bridge_vlan *v;
241	size_t sz;
242
243	/* IFLA_BRIDGE_MST */
244	sz = nla_total_size(0);
245
246	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
247		if (test_bit(v->brvlan->msti, seen))
248			continue;
249
250		/* IFLA_BRIDGE_MST_ENTRY */
251		sz += nla_total_size(0) +
252			/* IFLA_BRIDGE_MST_ENTRY_MSTI */
253			nla_total_size(sizeof(u16)) +
254			/* IFLA_BRIDGE_MST_ENTRY_STATE */
255			nla_total_size(sizeof(u8));
256
257		__set_bit(v->brvlan->msti, seen);
258	}
259
260	return sz;
261}
262
263int br_mst_fill_info(struct sk_buff *skb,
264		     const struct net_bridge_vlan_group *vg)
265{
266	DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
267	const struct net_bridge_vlan *v;
268	struct nlattr *nest;
269	int err = 0;
270
271	list_for_each_entry(v, &vg->vlan_list, vlist) {
272		if (test_bit(v->brvlan->msti, seen))
273			continue;
274
275		nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
276		if (!nest ||
277		    nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) ||
278		    nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
279			err = -EMSGSIZE;
280			break;
281		}
282		nla_nest_end(skb, nest);
283
284		__set_bit(v->brvlan->msti, seen);
285	}
286
287	return err;
288}
289
290static const struct nla_policy br_mst_nl_policy[IFLA_BRIDGE_MST_ENTRY_MAX + 1] = {
291	[IFLA_BRIDGE_MST_ENTRY_MSTI] = NLA_POLICY_RANGE(NLA_U16,
292						   1, /* 0 reserved for CST */
293						   VLAN_N_VID - 1),
294	[IFLA_BRIDGE_MST_ENTRY_STATE] = NLA_POLICY_RANGE(NLA_U8,
295						    BR_STATE_DISABLED,
296						    BR_STATE_BLOCKING),
297};
298
299static int br_mst_process_one(struct net_bridge_port *p,
300			      const struct nlattr *attr,
301			      struct netlink_ext_ack *extack)
302{
303	struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
304	u16 msti;
305	u8 state;
306	int err;
307
308	err = nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
309			       br_mst_nl_policy, extack);
310	if (err)
311		return err;
312
313	if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI]) {
314		NL_SET_ERR_MSG_MOD(extack, "MSTI not specified");
315		return -EINVAL;
316	}
317
318	if (!tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
319		NL_SET_ERR_MSG_MOD(extack, "State not specified");
320		return -EINVAL;
321	}
322
323	msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
324	state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
325
326	return br_mst_set_state(p, msti, state, extack);
327}
328
329int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
330		   struct netlink_ext_ack *extack)
331{
332	struct nlattr *attr;
333	int err, msts = 0;
334	int rem;
335
336	if (!br_opt_get(p->br, BROPT_MST_ENABLED)) {
337		NL_SET_ERR_MSG_MOD(extack, "Can't modify MST state when MST is disabled");
338		return -EBUSY;
339	}
340
341	nla_for_each_nested(attr, mst_attr, rem) {
342		switch (nla_type(attr)) {
343		case IFLA_BRIDGE_MST_ENTRY:
344			err = br_mst_process_one(p, attr, extack);
345			break;
346		default:
347			continue;
348		}
349
350		msts++;
351		if (err)
352			break;
353	}
354
355	if (!msts) {
356		NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process");
357		err = -EINVAL;
358	}
359
360	return err;
361}