br_mst.c (7760B)
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 (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 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; 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 128static 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 148int 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 183void 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 194int 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 233size_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 259int 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 286static 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 295static 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 325int 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}