Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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_vlan_group *vg,
 77				  struct net_bridge_vlan *v,
 78				  u8 state)
 79{
 80	if (br_vlan_get_state(v) == state)
 81		return;
 82
 83	br_vlan_set_state(v, state);
 84
 85	if (v->vid == vg->pvid)
 86		br_vlan_set_pvid_state(vg, state);
 87}
 88
 89int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
 90		     struct netlink_ext_ack *extack)
 91{
 92	struct switchdev_attr attr = {
 93		.id = SWITCHDEV_ATTR_ID_PORT_MST_STATE,
 94		.orig_dev = p->dev,
 95		.u.mst_state = {
 96			.msti = msti,
 97			.state = state,
 98		},
 99	};
100	struct net_bridge_vlan_group *vg;
101	struct net_bridge_vlan *v;
102	int err = 0;
103
104	rcu_read_lock();
105	vg = nbp_vlan_group_rcu(p);
106	if (!vg)
107		goto out;
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			goto out;
116	}
117
118	err = 0;
119	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
120		if (v->brvlan->msti != msti)
121			continue;
122
123		br_mst_vlan_set_state(vg, v, state);
124	}
125
126out:
127	rcu_read_unlock();
128	return err;
129}
130
131static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
132{
133	struct net_bridge_vlan_group *vg = nbp_vlan_group(pv->port);
134	struct net_bridge_vlan *v;
135
136	list_for_each_entry(v, &vg->vlan_list, vlist) {
137		/* If this port already has a defined state in this
138		 * MSTI (through some other VLAN membership), inherit
139		 * it.
140		 */
141		if (v != pv && v->brvlan->msti == msti) {
142			br_mst_vlan_set_state(vg, pv, v->state);
143			return;
144		}
145	}
146
147	/* Otherwise, start out in a new MSTI with all ports disabled. */
148	return br_mst_vlan_set_state(vg, pv, BR_STATE_DISABLED);
149}
150
151int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti)
152{
153	struct switchdev_attr attr = {
154		.id = SWITCHDEV_ATTR_ID_VLAN_MSTI,
155		.orig_dev = mv->br->dev,
156		.u.vlan_msti = {
157			.vid = mv->vid,
158			.msti = msti,
159		},
160	};
161	struct net_bridge_vlan_group *vg;
162	struct net_bridge_vlan *pv;
163	struct net_bridge_port *p;
164	int err;
165
166	if (mv->msti == msti)
167		return 0;
168
169	err = switchdev_port_attr_set(mv->br->dev, &attr, NULL);
170	if (err && err != -EOPNOTSUPP)
171		return err;
172
173	mv->msti = msti;
174
175	list_for_each_entry(p, &mv->br->port_list, list) {
176		vg = nbp_vlan_group(p);
177
178		pv = br_vlan_find(vg, mv->vid);
179		if (pv)
180			br_mst_vlan_sync_state(pv, msti);
181	}
182
183	return 0;
184}
185
186void br_mst_vlan_init_state(struct net_bridge_vlan *v)
187{
188	/* VLANs always start out in MSTI 0 (CST) */
189	v->msti = 0;
190
191	if (br_vlan_is_master(v))
192		v->state = BR_STATE_FORWARDING;
193	else
194		v->state = v->port->state;
195}
196
197int br_mst_set_enabled(struct net_bridge *br, bool on,
198		       struct netlink_ext_ack *extack)
199{
200	struct switchdev_attr attr = {
201		.id = SWITCHDEV_ATTR_ID_BRIDGE_MST,
202		.orig_dev = br->dev,
203		.u.mst = on,
204	};
205	struct net_bridge_vlan_group *vg;
206	struct net_bridge_port *p;
207	int err;
208
209	list_for_each_entry(p, &br->port_list, list) {
210		vg = nbp_vlan_group(p);
211
212		if (!vg->num_vlans)
213			continue;
214
215		NL_SET_ERR_MSG(extack,
216			       "MST mode can't be changed while VLANs exist");
217		return -EBUSY;
218	}
219
220	if (br_opt_get(br, BROPT_MST_ENABLED) == on)
221		return 0;
222
223	err = switchdev_port_attr_set(br->dev, &attr, extack);
224	if (err && err != -EOPNOTSUPP)
225		return err;
226
227	if (on)
228		static_branch_enable(&br_mst_used);
229	else
230		static_branch_disable(&br_mst_used);
231
232	br_opt_toggle(br, BROPT_MST_ENABLED, on);
233	return 0;
234}
235
236size_t br_mst_info_size(const struct net_bridge_vlan_group *vg)
237{
238	DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
239	const struct net_bridge_vlan *v;
240	size_t sz;
241
242	/* IFLA_BRIDGE_MST */
243	sz = nla_total_size(0);
244
245	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
246		if (test_bit(v->brvlan->msti, seen))
247			continue;
248
249		/* IFLA_BRIDGE_MST_ENTRY */
250		sz += nla_total_size(0) +
251			/* IFLA_BRIDGE_MST_ENTRY_MSTI */
252			nla_total_size(sizeof(u16)) +
253			/* IFLA_BRIDGE_MST_ENTRY_STATE */
254			nla_total_size(sizeof(u8));
255
256		__set_bit(v->brvlan->msti, seen);
257	}
258
259	return sz;
260}
261
262int br_mst_fill_info(struct sk_buff *skb,
263		     const struct net_bridge_vlan_group *vg)
264{
265	DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
266	const struct net_bridge_vlan *v;
267	struct nlattr *nest;
268	int err = 0;
269
270	list_for_each_entry(v, &vg->vlan_list, vlist) {
271		if (test_bit(v->brvlan->msti, seen))
272			continue;
273
274		nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
275		if (!nest ||
276		    nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) ||
277		    nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
278			err = -EMSGSIZE;
279			break;
280		}
281		nla_nest_end(skb, nest);
282
283		__set_bit(v->brvlan->msti, seen);
284	}
285
286	return err;
287}
288
289static const struct nla_policy br_mst_nl_policy[IFLA_BRIDGE_MST_ENTRY_MAX + 1] = {
290	[IFLA_BRIDGE_MST_ENTRY_MSTI] = NLA_POLICY_RANGE(NLA_U16,
291						   1, /* 0 reserved for CST */
292						   VLAN_N_VID - 1),
293	[IFLA_BRIDGE_MST_ENTRY_STATE] = NLA_POLICY_RANGE(NLA_U8,
294						    BR_STATE_DISABLED,
295						    BR_STATE_BLOCKING),
296};
297
298static int br_mst_process_one(struct net_bridge_port *p,
299			      const struct nlattr *attr,
300			      struct netlink_ext_ack *extack)
301{
302	struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
303	u16 msti;
304	u8 state;
305	int err;
306
307	err = nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
308			       br_mst_nl_policy, extack);
309	if (err)
310		return err;
311
312	if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI]) {
313		NL_SET_ERR_MSG_MOD(extack, "MSTI not specified");
314		return -EINVAL;
315	}
316
317	if (!tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
318		NL_SET_ERR_MSG_MOD(extack, "State not specified");
319		return -EINVAL;
320	}
321
322	msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
323	state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
324
325	return br_mst_set_state(p, msti, state, extack);
326}
327
328int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
329		   struct netlink_ext_ack *extack)
330{
331	struct nlattr *attr;
332	int err, msts = 0;
333	int rem;
334
335	if (!br_opt_get(p->br, BROPT_MST_ENABLED)) {
336		NL_SET_ERR_MSG_MOD(extack, "Can't modify MST state when MST is disabled");
337		return -EBUSY;
338	}
339
340	nla_for_each_nested(attr, mst_attr, rem) {
341		switch (nla_type(attr)) {
342		case IFLA_BRIDGE_MST_ENTRY:
343			err = br_mst_process_one(p, attr, extack);
344			break;
345		default:
346			continue;
347		}
348
349		msts++;
350		if (err)
351			break;
352	}
353
354	if (!msts) {
355		NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process");
356		err = -EINVAL;
357	}
358
359	return err;
360}