Loading...
Note: File does not exist in v5.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}