]> Git Repo - J-linux.git/blob - net/bridge/br_mst.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / net / bridge / br_mst.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *      Bridge Multiple Spanning Tree Support
4  *
5  *      Authors:
6  *      Tobias Waldekranz               <[email protected]>
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
This page took 0.045611 seconds and 4 git commands to generate.