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_port *p, struct net_bridge_vlan *v,
79 struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
81 if (v->state == state)
84 br_vlan_set_state(v, state);
86 if (v->vid == vg->pvid)
87 br_vlan_set_pvid_state(vg, state);
90 int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
91 struct netlink_ext_ack *extack)
93 struct switchdev_attr attr = {
94 .id = SWITCHDEV_ATTR_ID_PORT_MST_STATE,
101 struct net_bridge_vlan_group *vg;
102 struct net_bridge_vlan *v;
105 vg = nbp_vlan_group(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)
118 list_for_each_entry(v, &vg->vlan_list, vlist) {
119 if (v->brvlan->msti != msti)
122 br_mst_vlan_set_state(p, v, state);
128 static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
130 struct net_bridge_vlan_group *vg = nbp_vlan_group(pv->port);
131 struct net_bridge_vlan *v;
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
138 if (v != pv && v->brvlan->msti == msti) {
139 br_mst_vlan_set_state(pv->port, pv, v->state);
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);
148 int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti)
150 struct switchdev_attr attr = {
151 .id = SWITCHDEV_ATTR_ID_VLAN_MSTI,
152 .orig_dev = mv->br->dev,
158 struct net_bridge_vlan_group *vg;
159 struct net_bridge_vlan *pv;
160 struct net_bridge_port *p;
163 if (mv->msti == msti)
166 err = switchdev_port_attr_set(mv->br->dev, &attr, NULL);
167 if (err && err != -EOPNOTSUPP)
172 list_for_each_entry(p, &mv->br->port_list, list) {
173 vg = nbp_vlan_group(p);
175 pv = br_vlan_find(vg, mv->vid);
177 br_mst_vlan_sync_state(pv, msti);
183 void br_mst_vlan_init_state(struct net_bridge_vlan *v)
185 /* VLANs always start out in MSTI 0 (CST) */
188 if (br_vlan_is_master(v))
189 v->state = BR_STATE_FORWARDING;
191 v->state = v->port->state;
194 int br_mst_set_enabled(struct net_bridge *br, bool on,
195 struct netlink_ext_ack *extack)
197 struct switchdev_attr attr = {
198 .id = SWITCHDEV_ATTR_ID_BRIDGE_MST,
202 struct net_bridge_vlan_group *vg;
203 struct net_bridge_port *p;
206 list_for_each_entry(p, &br->port_list, list) {
207 vg = nbp_vlan_group(p);
212 NL_SET_ERR_MSG(extack,
213 "MST mode can't be changed while VLANs exist");
217 if (br_opt_get(br, BROPT_MST_ENABLED) == on)
220 err = switchdev_port_attr_set(br->dev, &attr, extack);
221 if (err && err != -EOPNOTSUPP)
225 static_branch_enable(&br_mst_used);
227 static_branch_disable(&br_mst_used);
229 br_opt_toggle(br, BROPT_MST_ENABLED, on);
233 size_t br_mst_info_size(const struct net_bridge_vlan_group *vg)
235 DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
236 const struct net_bridge_vlan *v;
239 /* IFLA_BRIDGE_MST */
240 sz = nla_total_size(0);
242 list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
243 if (test_bit(v->brvlan->msti, seen))
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));
253 __set_bit(v->brvlan->msti, seen);
259 int br_mst_fill_info(struct sk_buff *skb,
260 const struct net_bridge_vlan_group *vg)
262 DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
263 const struct net_bridge_vlan *v;
267 list_for_each_entry(v, &vg->vlan_list, vlist) {
268 if (test_bit(v->brvlan->msti, seen))
271 nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
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)) {
278 nla_nest_end(skb, nest);
280 __set_bit(v->brvlan->msti, seen);
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 */
290 [IFLA_BRIDGE_MST_ENTRY_STATE] = NLA_POLICY_RANGE(NLA_U8,
295 static int br_mst_process_one(struct net_bridge_port *p,
296 const struct nlattr *attr,
297 struct netlink_ext_ack *extack)
299 struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
304 err = nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
305 br_mst_nl_policy, extack);
309 if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI]) {
310 NL_SET_ERR_MSG_MOD(extack, "MSTI not specified");
314 if (!tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
315 NL_SET_ERR_MSG_MOD(extack, "State not specified");
319 msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
320 state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
322 return br_mst_set_state(p, msti, state, extack);
325 int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
326 struct netlink_ext_ack *extack)
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");
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);
352 NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process");