xref: /openbmc/linux/net/bridge/br_mst.c (revision 7caefa27)
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 
14 DEFINE_STATIC_KEY_FALSE(br_mst_used);
15 
br_mst_enabled(const struct net_device * dev)16 bool 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 }
23 EXPORT_SYMBOL_GPL(br_mst_enabled);
24 
br_mst_get_info(const struct net_device * dev,u16 msti,unsigned long * vids)25 int 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 }
49 EXPORT_SYMBOL_GPL(br_mst_get_info);
50 
br_mst_get_state(const struct net_device * dev,u16 msti,u8 * state)51 int 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 }
74 EXPORT_SYMBOL_GPL(br_mst_get_state);
75 
br_mst_vlan_set_state(struct net_bridge_vlan_group * vg,struct net_bridge_vlan * v,u8 state)76 static 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 
br_mst_set_state(struct net_bridge_port * p,u16 msti,u8 state,struct netlink_ext_ack * extack)89 int 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 
126 out:
127 	rcu_read_unlock();
128 	return err;
129 }
130 
br_mst_vlan_sync_state(struct net_bridge_vlan * pv,u16 msti)131 static 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 
br_mst_vlan_set_msti(struct net_bridge_vlan * mv,u16 msti)151 int 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 
br_mst_vlan_init_state(struct net_bridge_vlan * v)186 void 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 
br_mst_set_enabled(struct net_bridge * br,bool on,struct netlink_ext_ack * extack)197 int 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 
br_mst_info_size(const struct net_bridge_vlan_group * vg)236 size_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 
br_mst_fill_info(struct sk_buff * skb,const struct net_bridge_vlan_group * vg)262 int 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 
289 static 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 
br_mst_process_one(struct net_bridge_port * p,const struct nlattr * attr,struct netlink_ext_ack * extack)298 static 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 
br_mst_process(struct net_bridge_port * p,const struct nlattr * mst_attr,struct netlink_ext_ack * extack)328 int 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 }
361