Commit 6284c723 authored by Tobias Waldekranz's avatar Tobias Waldekranz Committed by Jakub Kicinski
Browse files

net: bridge: mst: Notify switchdev drivers of VLAN MSTI migrations



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: default avatarTobias Waldekranz <tobias@waldekranz.com>
Acked-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 87c167bb
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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;
};

+13 −0
Original line number Diff line number Diff line
@@ -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) {
+46 −0
Original line number Diff line number Diff line
@@ -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;
}