Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Bridge Multiple Spanning Tree Support
0004  *
0005  *  Authors:
0006  *  Tobias Waldekranz       <tobias@waldekranz.com>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <net/switchdev.h>
0011 
0012 #include "br_private.h"
0013 
0014 DEFINE_STATIC_KEY_FALSE(br_mst_used);
0015 
0016 bool br_mst_enabled(const struct net_device *dev)
0017 {
0018     if (!netif_is_bridge_master(dev))
0019         return false;
0020 
0021     return br_opt_get(netdev_priv(dev), BROPT_MST_ENABLED);
0022 }
0023 EXPORT_SYMBOL_GPL(br_mst_enabled);
0024 
0025 int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids)
0026 {
0027     const struct net_bridge_vlan_group *vg;
0028     const struct net_bridge_vlan *v;
0029     const struct net_bridge *br;
0030 
0031     ASSERT_RTNL();
0032 
0033     if (!netif_is_bridge_master(dev))
0034         return -EINVAL;
0035 
0036     br = netdev_priv(dev);
0037     if (!br_opt_get(br, BROPT_MST_ENABLED))
0038         return -EINVAL;
0039 
0040     vg = br_vlan_group(br);
0041 
0042     list_for_each_entry(v, &vg->vlan_list, vlist) {
0043         if (v->msti == msti)
0044             __set_bit(v->vid, vids);
0045     }
0046 
0047     return 0;
0048 }
0049 EXPORT_SYMBOL_GPL(br_mst_get_info);
0050 
0051 int br_mst_get_state(const struct net_device *dev, u16 msti, u8 *state)
0052 {
0053     const struct net_bridge_port *p = NULL;
0054     const struct net_bridge_vlan_group *vg;
0055     const struct net_bridge_vlan *v;
0056 
0057     ASSERT_RTNL();
0058 
0059     p = br_port_get_check_rtnl(dev);
0060     if (!p || !br_opt_get(p->br, BROPT_MST_ENABLED))
0061         return -EINVAL;
0062 
0063     vg = nbp_vlan_group(p);
0064 
0065     list_for_each_entry(v, &vg->vlan_list, vlist) {
0066         if (v->brvlan->msti == msti) {
0067             *state = v->state;
0068             return 0;
0069         }
0070     }
0071 
0072     return -ENOENT;
0073 }
0074 EXPORT_SYMBOL_GPL(br_mst_get_state);
0075 
0076 static void br_mst_vlan_set_state(struct net_bridge_port *p, struct net_bridge_vlan *v,
0077                   u8 state)
0078 {
0079     struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
0080 
0081     if (v->state == state)
0082         return;
0083 
0084     br_vlan_set_state(v, state);
0085 
0086     if (v->vid == vg->pvid)
0087         br_vlan_set_pvid_state(vg, state);
0088 }
0089 
0090 int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
0091              struct netlink_ext_ack *extack)
0092 {
0093     struct switchdev_attr attr = {
0094         .id = SWITCHDEV_ATTR_ID_PORT_MST_STATE,
0095         .orig_dev = p->dev,
0096         .u.mst_state = {
0097             .msti = msti,
0098             .state = state,
0099         },
0100     };
0101     struct net_bridge_vlan_group *vg;
0102     struct net_bridge_vlan *v;
0103     int err;
0104 
0105     vg = nbp_vlan_group(p);
0106     if (!vg)
0107         return 0;
0108 
0109     /* MSTI 0 (CST) state changes are notified via the regular
0110      * SWITCHDEV_ATTR_ID_PORT_STP_STATE.
0111      */
0112     if (msti) {
0113         err = switchdev_port_attr_set(p->dev, &attr, extack);
0114         if (err && err != -EOPNOTSUPP)
0115             return err;
0116     }
0117 
0118     list_for_each_entry(v, &vg->vlan_list, vlist) {
0119         if (v->brvlan->msti != msti)
0120             continue;
0121 
0122         br_mst_vlan_set_state(p, v, state);
0123     }
0124 
0125     return 0;
0126 }
0127 
0128 static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
0129 {
0130     struct net_bridge_vlan_group *vg = nbp_vlan_group(pv->port);
0131     struct net_bridge_vlan *v;
0132 
0133     list_for_each_entry(v, &vg->vlan_list, vlist) {
0134         /* If this port already has a defined state in this
0135          * MSTI (through some other VLAN membership), inherit
0136          * it.
0137          */
0138         if (v != pv && v->brvlan->msti == msti) {
0139             br_mst_vlan_set_state(pv->port, pv, v->state);
0140             return;
0141         }
0142     }
0143 
0144     /* Otherwise, start out in a new MSTI with all ports disabled. */
0145     return br_mst_vlan_set_state(pv->port, pv, BR_STATE_DISABLED);
0146 }
0147 
0148 int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti)
0149 {
0150     struct switchdev_attr attr = {
0151         .id = SWITCHDEV_ATTR_ID_VLAN_MSTI,
0152         .orig_dev = mv->br->dev,
0153         .u.vlan_msti = {
0154             .vid = mv->vid,
0155             .msti = msti,
0156         },
0157     };
0158     struct net_bridge_vlan_group *vg;
0159     struct net_bridge_vlan *pv;
0160     struct net_bridge_port *p;
0161     int err;
0162 
0163     if (mv->msti == msti)
0164         return 0;
0165 
0166     err = switchdev_port_attr_set(mv->br->dev, &attr, NULL);
0167     if (err && err != -EOPNOTSUPP)
0168         return err;
0169 
0170     mv->msti = msti;
0171 
0172     list_for_each_entry(p, &mv->br->port_list, list) {
0173         vg = nbp_vlan_group(p);
0174 
0175         pv = br_vlan_find(vg, mv->vid);
0176         if (pv)
0177             br_mst_vlan_sync_state(pv, msti);
0178     }
0179 
0180     return 0;
0181 }
0182 
0183 void br_mst_vlan_init_state(struct net_bridge_vlan *v)
0184 {
0185     /* VLANs always start out in MSTI 0 (CST) */
0186     v->msti = 0;
0187 
0188     if (br_vlan_is_master(v))
0189         v->state = BR_STATE_FORWARDING;
0190     else
0191         v->state = v->port->state;
0192 }
0193 
0194 int br_mst_set_enabled(struct net_bridge *br, bool on,
0195                struct netlink_ext_ack *extack)
0196 {
0197     struct switchdev_attr attr = {
0198         .id = SWITCHDEV_ATTR_ID_BRIDGE_MST,
0199         .orig_dev = br->dev,
0200         .u.mst = on,
0201     };
0202     struct net_bridge_vlan_group *vg;
0203     struct net_bridge_port *p;
0204     int err;
0205 
0206     list_for_each_entry(p, &br->port_list, list) {
0207         vg = nbp_vlan_group(p);
0208 
0209         if (!vg->num_vlans)
0210             continue;
0211 
0212         NL_SET_ERR_MSG(extack,
0213                    "MST mode can't be changed while VLANs exist");
0214         return -EBUSY;
0215     }
0216 
0217     if (br_opt_get(br, BROPT_MST_ENABLED) == on)
0218         return 0;
0219 
0220     err = switchdev_port_attr_set(br->dev, &attr, extack);
0221     if (err && err != -EOPNOTSUPP)
0222         return err;
0223 
0224     if (on)
0225         static_branch_enable(&br_mst_used);
0226     else
0227         static_branch_disable(&br_mst_used);
0228 
0229     br_opt_toggle(br, BROPT_MST_ENABLED, on);
0230     return 0;
0231 }
0232 
0233 size_t br_mst_info_size(const struct net_bridge_vlan_group *vg)
0234 {
0235     DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
0236     const struct net_bridge_vlan *v;
0237     size_t sz;
0238 
0239     /* IFLA_BRIDGE_MST */
0240     sz = nla_total_size(0);
0241 
0242     list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
0243         if (test_bit(v->brvlan->msti, seen))
0244             continue;
0245 
0246         /* IFLA_BRIDGE_MST_ENTRY */
0247         sz += nla_total_size(0) +
0248             /* IFLA_BRIDGE_MST_ENTRY_MSTI */
0249             nla_total_size(sizeof(u16)) +
0250             /* IFLA_BRIDGE_MST_ENTRY_STATE */
0251             nla_total_size(sizeof(u8));
0252 
0253         __set_bit(v->brvlan->msti, seen);
0254     }
0255 
0256     return sz;
0257 }
0258 
0259 int br_mst_fill_info(struct sk_buff *skb,
0260              const struct net_bridge_vlan_group *vg)
0261 {
0262     DECLARE_BITMAP(seen, VLAN_N_VID) = { 0 };
0263     const struct net_bridge_vlan *v;
0264     struct nlattr *nest;
0265     int err = 0;
0266 
0267     list_for_each_entry(v, &vg->vlan_list, vlist) {
0268         if (test_bit(v->brvlan->msti, seen))
0269             continue;
0270 
0271         nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
0272         if (!nest ||
0273             nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) ||
0274             nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
0275             err = -EMSGSIZE;
0276             break;
0277         }
0278         nla_nest_end(skb, nest);
0279 
0280         __set_bit(v->brvlan->msti, seen);
0281     }
0282 
0283     return err;
0284 }
0285 
0286 static const struct nla_policy br_mst_nl_policy[IFLA_BRIDGE_MST_ENTRY_MAX + 1] = {
0287     [IFLA_BRIDGE_MST_ENTRY_MSTI] = NLA_POLICY_RANGE(NLA_U16,
0288                            1, /* 0 reserved for CST */
0289                            VLAN_N_VID - 1),
0290     [IFLA_BRIDGE_MST_ENTRY_STATE] = NLA_POLICY_RANGE(NLA_U8,
0291                             BR_STATE_DISABLED,
0292                             BR_STATE_BLOCKING),
0293 };
0294 
0295 static int br_mst_process_one(struct net_bridge_port *p,
0296                   const struct nlattr *attr,
0297                   struct netlink_ext_ack *extack)
0298 {
0299     struct nlattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
0300     u16 msti;
0301     u8 state;
0302     int err;
0303 
0304     err = nla_parse_nested(tb, IFLA_BRIDGE_MST_ENTRY_MAX, attr,
0305                    br_mst_nl_policy, extack);
0306     if (err)
0307         return err;
0308 
0309     if (!tb[IFLA_BRIDGE_MST_ENTRY_MSTI]) {
0310         NL_SET_ERR_MSG_MOD(extack, "MSTI not specified");
0311         return -EINVAL;
0312     }
0313 
0314     if (!tb[IFLA_BRIDGE_MST_ENTRY_STATE]) {
0315         NL_SET_ERR_MSG_MOD(extack, "State not specified");
0316         return -EINVAL;
0317     }
0318 
0319     msti = nla_get_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
0320     state = nla_get_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
0321 
0322     return br_mst_set_state(p, msti, state, extack);
0323 }
0324 
0325 int br_mst_process(struct net_bridge_port *p, const struct nlattr *mst_attr,
0326            struct netlink_ext_ack *extack)
0327 {
0328     struct nlattr *attr;
0329     int err, msts = 0;
0330     int rem;
0331 
0332     if (!br_opt_get(p->br, BROPT_MST_ENABLED)) {
0333         NL_SET_ERR_MSG_MOD(extack, "Can't modify MST state when MST is disabled");
0334         return -EBUSY;
0335     }
0336 
0337     nla_for_each_nested(attr, mst_attr, rem) {
0338         switch (nla_type(attr)) {
0339         case IFLA_BRIDGE_MST_ENTRY:
0340             err = br_mst_process_one(p, attr, extack);
0341             break;
0342         default:
0343             continue;
0344         }
0345 
0346         msts++;
0347         if (err)
0348             break;
0349     }
0350 
0351     if (!msts) {
0352         NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process");
0353         err = -EINVAL;
0354     }
0355 
0356     return err;
0357 }