cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}