1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Bridge Multiple Spanning Tree Support
6 * Tobias Waldekranz <tobias@waldekranz.com>
9 #include <linux/kernel.h>
10 #include <net/switchdev.h>
12 #include "br_private.h"
14 DEFINE_STATIC_KEY_FALSE(br_mst_used
);
16 bool br_mst_enabled(const struct net_device
*dev
)
18 if (!netif_is_bridge_master(dev
))
21 return br_opt_get(netdev_priv(dev
), BROPT_MST_ENABLED
);
23 EXPORT_SYMBOL_GPL(br_mst_enabled
);
25 int br_mst_get_info(const struct net_device
*dev
, u16 msti
, unsigned long *vids
)
27 const struct net_bridge_vlan_group
*vg
;
28 const struct net_bridge_vlan
*v
;
29 const struct net_bridge
*br
;
33 if (!netif_is_bridge_master(dev
))
36 br
= netdev_priv(dev
);
37 if (!br_opt_get(br
, BROPT_MST_ENABLED
))
40 vg
= br_vlan_group(br
);
42 list_for_each_entry(v
, &vg
->vlan_list
, vlist
) {
44 __set_bit(v
->vid
, vids
);
49 EXPORT_SYMBOL_GPL(br_mst_get_info
);
51 int br_mst_get_state(const struct net_device
*dev
, u16 msti
, u8
*state
)
53 const struct net_bridge_port
*p
= NULL
;
54 const struct net_bridge_vlan_group
*vg
;
55 const struct net_bridge_vlan
*v
;
59 p
= br_port_get_check_rtnl(dev
);
60 if (!p
|| !br_opt_get(p
->br
, BROPT_MST_ENABLED
))
63 vg
= nbp_vlan_group(p
);
65 list_for_each_entry(v
, &vg
->vlan_list
, vlist
) {
66 if (v
->brvlan
->msti
== msti
) {
74 EXPORT_SYMBOL_GPL(br_mst_get_state
);
76 static void br_mst_vlan_set_state(struct net_bridge_vlan_group
*vg
,
77 struct net_bridge_vlan
*v
,
80 if (br_vlan_get_state(v
) == state
)
83 br_vlan_set_state(v
, state
);
85 if (v
->vid
== vg
->pvid
)
86 br_vlan_set_pvid_state(vg
, state
);
89 int br_mst_set_state(struct net_bridge_port
*p
, u16 msti
, u8 state
,
90 struct netlink_ext_ack
*extack
)
92 struct switchdev_attr attr
= {
93 .id
= SWITCHDEV_ATTR_ID_PORT_MST_STATE
,
100 struct net_bridge_vlan_group
*vg
;
101 struct net_bridge_vlan
*v
;
105 vg
= nbp_vlan_group_rcu(p
);
109 /* MSTI 0 (CST) state changes are notified via the regular
110 * SWITCHDEV_ATTR_ID_PORT_STP_STATE.
113 err
= switchdev_port_attr_set(p
->dev
, &attr
, extack
);
114 if (err
&& err
!= -EOPNOTSUPP
)
119 list_for_each_entry_rcu(v
, &vg
->vlan_list
, vlist
) {
120 if (v
->brvlan
->msti
!= msti
)
123 br_mst_vlan_set_state(vg
, v
, state
);
131 static void br_mst_vlan_sync_state(struct net_bridge_vlan
*pv
, u16 msti
)
133 struct net_bridge_vlan_group
*vg
= nbp_vlan_group(pv
->port
);
134 struct net_bridge_vlan
*v
;
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
141 if (v
!= pv
&& v
->brvlan
->msti
== msti
) {
142 br_mst_vlan_set_state(vg
, pv
, v
->state
);
147 /* Otherwise, start out in a new MSTI with all ports disabled. */
148 return br_mst_vlan_set_state(vg
, pv
, BR_STATE_DISABLED
);
151 int br_mst_vlan_set_msti(struct net_bridge_vlan
*mv
, u16 msti
)
153 struct switchdev_attr attr
= {
154 .id
= SWITCHDEV_ATTR_ID_VLAN_MSTI
,
155 .orig_dev
= mv
->br
->dev
,
161 struct net_bridge_vlan_group
*vg
;
162 struct net_bridge_vlan
*pv
;
163 struct net_bridge_port
*p
;
166 if (mv
->msti
== msti
)
169 err
= switchdev_port_attr_set(mv
->br
->dev
, &attr
, NULL
);
170 if (err
&& err
!= -EOPNOTSUPP
)
175 list_for_each_entry(p
, &mv
->br
->port_list
, list
) {
176 vg
= nbp_vlan_group(p
);
178 pv
= br_vlan_find(vg
, mv
->vid
);
180 br_mst_vlan_sync_state(pv
, msti
);
186 void br_mst_vlan_init_state(struct net_bridge_vlan
*v
)
188 /* VLANs always start out in MSTI 0 (CST) */
191 if (br_vlan_is_master(v
))
192 v
->state
= BR_STATE_FORWARDING
;
194 v
->state
= v
->port
->state
;
197 int br_mst_set_enabled(struct net_bridge
*br
, bool on
,
198 struct netlink_ext_ack
*extack
)
200 struct switchdev_attr attr
= {
201 .id
= SWITCHDEV_ATTR_ID_BRIDGE_MST
,
205 struct net_bridge_vlan_group
*vg
;
206 struct net_bridge_port
*p
;
209 list_for_each_entry(p
, &br
->port_list
, list
) {
210 vg
= nbp_vlan_group(p
);
215 NL_SET_ERR_MSG(extack
,
216 "MST mode can't be changed while VLANs exist");
220 if (br_opt_get(br
, BROPT_MST_ENABLED
) == on
)
223 err
= switchdev_port_attr_set(br
->dev
, &attr
, extack
);
224 if (err
&& err
!= -EOPNOTSUPP
)
228 static_branch_enable(&br_mst_used
);
230 static_branch_disable(&br_mst_used
);
232 br_opt_toggle(br
, BROPT_MST_ENABLED
, on
);
236 size_t br_mst_info_size(const struct net_bridge_vlan_group
*vg
)
238 DECLARE_BITMAP(seen
, VLAN_N_VID
) = { 0 };
239 const struct net_bridge_vlan
*v
;
242 /* IFLA_BRIDGE_MST */
243 sz
= nla_total_size(0);
245 list_for_each_entry_rcu(v
, &vg
->vlan_list
, vlist
) {
246 if (test_bit(v
->brvlan
->msti
, seen
))
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
));
256 __set_bit(v
->brvlan
->msti
, seen
);
262 int br_mst_fill_info(struct sk_buff
*skb
,
263 const struct net_bridge_vlan_group
*vg
)
265 DECLARE_BITMAP(seen
, VLAN_N_VID
) = { 0 };
266 const struct net_bridge_vlan
*v
;
270 list_for_each_entry(v
, &vg
->vlan_list
, vlist
) {
271 if (test_bit(v
->brvlan
->msti
, seen
))
274 nest
= nla_nest_start_noflag(skb
, IFLA_BRIDGE_MST_ENTRY
);
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
)) {
281 nla_nest_end(skb
, nest
);
283 __set_bit(v
->brvlan
->msti
, seen
);
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 */
293 [IFLA_BRIDGE_MST_ENTRY_STATE
] = NLA_POLICY_RANGE(NLA_U8
,
298 static int br_mst_process_one(struct net_bridge_port
*p
,
299 const struct nlattr
*attr
,
300 struct netlink_ext_ack
*extack
)
302 struct nlattr
*tb
[IFLA_BRIDGE_MST_ENTRY_MAX
+ 1];
307 err
= nla_parse_nested(tb
, IFLA_BRIDGE_MST_ENTRY_MAX
, attr
,
308 br_mst_nl_policy
, extack
);
312 if (!tb
[IFLA_BRIDGE_MST_ENTRY_MSTI
]) {
313 NL_SET_ERR_MSG_MOD(extack
, "MSTI not specified");
317 if (!tb
[IFLA_BRIDGE_MST_ENTRY_STATE
]) {
318 NL_SET_ERR_MSG_MOD(extack
, "State not specified");
322 msti
= nla_get_u16(tb
[IFLA_BRIDGE_MST_ENTRY_MSTI
]);
323 state
= nla_get_u8(tb
[IFLA_BRIDGE_MST_ENTRY_STATE
]);
325 return br_mst_set_state(p
, msti
, state
, extack
);
328 int br_mst_process(struct net_bridge_port
*p
, const struct nlattr
*mst_attr
,
329 struct netlink_ext_ack
*extack
)
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");
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
);
355 NL_SET_ERR_MSG_MOD(extack
, "Found no MST entries to process");