net: bridge: mst: Notify switchdev drivers of VLAN MSTI migrations
authorTobias Waldekranz <tobias@waldekranz.com>
Wed, 16 Mar 2022 15:08:47 +0000 (16:08 +0100)
committerJakub Kicinski <kuba@kernel.org>
Thu, 17 Mar 2022 23:49:58 +0000 (16:49 -0700)
Whenever a VLAN moves to a new MSTI, send a switchdev notification so
that switchdevs can track a bridge's VID to MSTI mappings.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/switchdev.h
net/bridge/br_mst.c
net/bridge/br_switchdev.c

index 85dd004..53dfa0f 100644 (file)
@@ -29,6 +29,7 @@ enum switchdev_attr_id {
        SWITCHDEV_ATTR_ID_BRIDGE_MROUTER,
        SWITCHDEV_ATTR_ID_BRIDGE_MST,
        SWITCHDEV_ATTR_ID_MRP_PORT_ROLE,
+       SWITCHDEV_ATTR_ID_VLAN_MSTI,
 };
 
 struct switchdev_brport_flags {
@@ -36,6 +37,11 @@ struct switchdev_brport_flags {
        unsigned long mask;
 };
 
+struct switchdev_vlan_msti {
+       u16 vid;
+       u16 msti;
+};
+
 struct switchdev_attr {
        struct net_device *orig_dev;
        enum switchdev_attr_id id;
@@ -52,6 +58,7 @@ struct switchdev_attr {
                bool mst;                               /* BRIDGE_MST */
                bool mc_disabled;                       /* MC_DISABLED */
                u8 mrp_port_role;                       /* MRP_PORT_ROLE */
+               struct switchdev_vlan_msti vlan_msti;   /* VLAN_MSTI */
        } u;
 };
 
index 43ca6b9..2926617 100644 (file)
@@ -69,13 +69,26 @@ static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
 
 int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti)
 {
+       struct switchdev_attr attr = {
+               .id = SWITCHDEV_ATTR_ID_VLAN_MSTI,
+               .orig_dev = mv->br->dev,
+               .u.vlan_msti = {
+                       .vid = mv->vid,
+                       .msti = msti,
+               },
+       };
        struct net_bridge_vlan_group *vg;
        struct net_bridge_vlan *pv;
        struct net_bridge_port *p;
+       int err;
 
        if (mv->msti == msti)
                return 0;
 
+       err = switchdev_port_attr_set(mv->br->dev, &attr, NULL);
+       if (err && err != -EOPNOTSUPP)
+               return err;
+
        mv->msti = msti;
 
        list_for_each_entry(p, &mv->br->port_list, list) {
index 6f6a701..8cc44c3 100644 (file)
@@ -331,6 +331,46 @@ br_switchdev_fdb_replay(const struct net_device *br_dev, const void *ctx,
        return err;
 }
 
+static int br_switchdev_vlan_attr_replay(struct net_device *br_dev,
+                                        const void *ctx,
+                                        struct notifier_block *nb,
+                                        struct netlink_ext_ack *extack)
+{
+       struct switchdev_notifier_port_attr_info attr_info = {
+               .info = {
+                       .dev = br_dev,
+                       .extack = extack,
+                       .ctx = ctx,
+               },
+       };
+       struct net_bridge *br = netdev_priv(br_dev);
+       struct net_bridge_vlan_group *vg;
+       struct switchdev_attr attr;
+       struct net_bridge_vlan *v;
+       int err;
+
+       attr_info.attr = &attr;
+       attr.orig_dev = br_dev;
+
+       vg = br_vlan_group(br);
+
+       list_for_each_entry(v, &vg->vlan_list, vlist) {
+               if (v->msti) {
+                       attr.id = SWITCHDEV_ATTR_ID_VLAN_MSTI;
+                       attr.u.vlan_msti.vid = v->vid;
+                       attr.u.vlan_msti.msti = v->msti;
+
+                       err = nb->notifier_call(nb, SWITCHDEV_PORT_ATTR_SET,
+                                               &attr_info);
+                       err = notifier_to_errno(err);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
 static int
 br_switchdev_vlan_replay_one(struct notifier_block *nb,
                             struct net_device *dev,
@@ -425,6 +465,12 @@ static int br_switchdev_vlan_replay(struct net_device *br_dev,
                        return err;
        }
 
+       if (adding) {
+               err = br_switchdev_vlan_attr_replay(br_dev, ctx, nb, extack);
+               if (err)
+                       return err;
+       }
+
        return 0;
 }