Merge tag 'nfs-for-5.18-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[platform/kernel/linux-starfive.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               <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
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_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
90 int 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
128 static 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
148 int 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
183 void 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
194 int 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
233 size_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
259 int 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
286 static 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
295 static 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
325 int 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 }