Loading...
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}
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}