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

lan966x_mdb.c (14965B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3#include <net/switchdev.h>
      4
      5#include "lan966x_main.h"
      6
      7struct lan966x_pgid_entry {
      8	struct list_head list;
      9	int index;
     10	refcount_t refcount;
     11	u16 ports;
     12};
     13
     14struct lan966x_mdb_entry {
     15	struct list_head list;
     16	unsigned char mac[ETH_ALEN];
     17	u16 vid;
     18	u16 ports;
     19	struct lan966x_pgid_entry *pgid;
     20	u8 cpu_copy;
     21};
     22
     23void lan966x_mdb_init(struct lan966x *lan966x)
     24{
     25	INIT_LIST_HEAD(&lan966x->mdb_entries);
     26	INIT_LIST_HEAD(&lan966x->pgid_entries);
     27}
     28
     29static void lan966x_mdb_purge_mdb_entries(struct lan966x *lan966x)
     30{
     31	struct lan966x_mdb_entry *mdb_entry, *tmp;
     32
     33	list_for_each_entry_safe(mdb_entry, tmp, &lan966x->mdb_entries, list) {
     34		list_del(&mdb_entry->list);
     35		kfree(mdb_entry);
     36	}
     37}
     38
     39static void lan966x_mdb_purge_pgid_entries(struct lan966x *lan966x)
     40{
     41	struct lan966x_pgid_entry *pgid_entry, *tmp;
     42
     43	list_for_each_entry_safe(pgid_entry, tmp, &lan966x->pgid_entries, list) {
     44		list_del(&pgid_entry->list);
     45		kfree(pgid_entry);
     46	}
     47}
     48
     49void lan966x_mdb_deinit(struct lan966x *lan966x)
     50{
     51	lan966x_mdb_purge_mdb_entries(lan966x);
     52	lan966x_mdb_purge_pgid_entries(lan966x);
     53}
     54
     55static struct lan966x_mdb_entry *
     56lan966x_mdb_entry_get(struct lan966x *lan966x,
     57		      const unsigned char *mac,
     58		      u16 vid)
     59{
     60	struct lan966x_mdb_entry *mdb_entry;
     61
     62	list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
     63		if (ether_addr_equal(mdb_entry->mac, mac) &&
     64		    mdb_entry->vid == vid)
     65			return mdb_entry;
     66	}
     67
     68	return NULL;
     69}
     70
     71static struct lan966x_mdb_entry *
     72lan966x_mdb_entry_add(struct lan966x *lan966x,
     73		      const struct switchdev_obj_port_mdb *mdb)
     74{
     75	struct lan966x_mdb_entry *mdb_entry;
     76
     77	mdb_entry = kzalloc(sizeof(*mdb_entry), GFP_KERNEL);
     78	if (!mdb_entry)
     79		return ERR_PTR(-ENOMEM);
     80
     81	ether_addr_copy(mdb_entry->mac, mdb->addr);
     82	mdb_entry->vid = mdb->vid;
     83
     84	list_add_tail(&mdb_entry->list, &lan966x->mdb_entries);
     85
     86	return mdb_entry;
     87}
     88
     89static void lan966x_mdb_encode_mac(unsigned char *mac,
     90				   struct lan966x_mdb_entry *mdb_entry,
     91				   enum macaccess_entry_type type)
     92{
     93	ether_addr_copy(mac, mdb_entry->mac);
     94
     95	if (type == ENTRYTYPE_MACV4) {
     96		mac[0] = 0;
     97		mac[1] = mdb_entry->ports >> 8;
     98		mac[2] = mdb_entry->ports & 0xff;
     99	} else if (type == ENTRYTYPE_MACV6) {
    100		mac[0] = mdb_entry->ports >> 8;
    101		mac[1] = mdb_entry->ports & 0xff;
    102	}
    103}
    104
    105static int lan966x_mdb_ip_add(struct lan966x_port *port,
    106			      const struct switchdev_obj_port_mdb *mdb,
    107			      enum macaccess_entry_type type)
    108{
    109	bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
    110	struct lan966x *lan966x = port->lan966x;
    111	struct lan966x_mdb_entry *mdb_entry;
    112	unsigned char mac[ETH_ALEN];
    113	bool cpu_copy = false;
    114
    115	mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
    116	if (!mdb_entry) {
    117		mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
    118		if (IS_ERR(mdb_entry))
    119			return PTR_ERR(mdb_entry);
    120	} else {
    121		lan966x_mdb_encode_mac(mac, mdb_entry, type);
    122		lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    123	}
    124
    125	if (cpu_port)
    126		mdb_entry->cpu_copy++;
    127	else
    128		mdb_entry->ports |= BIT(port->chip_port);
    129
    130	/* Copy the frame to CPU only if the CPU is in the VLAN */
    131	if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
    132	    mdb_entry->cpu_copy)
    133		cpu_copy = true;
    134
    135	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    136	return lan966x_mac_ip_learn(lan966x, cpu_copy,
    137				    mac, mdb_entry->vid, type);
    138}
    139
    140static int lan966x_mdb_ip_del(struct lan966x_port *port,
    141			      const struct switchdev_obj_port_mdb *mdb,
    142			      enum macaccess_entry_type type)
    143{
    144	bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
    145	struct lan966x *lan966x = port->lan966x;
    146	struct lan966x_mdb_entry *mdb_entry;
    147	unsigned char mac[ETH_ALEN];
    148	u16 ports;
    149
    150	mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
    151	if (!mdb_entry)
    152		return -ENOENT;
    153
    154	ports = mdb_entry->ports;
    155	if (cpu_port) {
    156		/* If there are still other references to the CPU port then
    157		 * there is no point to delete and add again the same entry
    158		 */
    159		mdb_entry->cpu_copy--;
    160		if (mdb_entry->cpu_copy)
    161			return 0;
    162	} else {
    163		ports &= ~BIT(port->chip_port);
    164	}
    165
    166	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    167	lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    168
    169	mdb_entry->ports = ports;
    170
    171	if (!mdb_entry->ports && !mdb_entry->cpu_copy) {
    172		list_del(&mdb_entry->list);
    173		kfree(mdb_entry);
    174		return 0;
    175	}
    176
    177	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    178	return lan966x_mac_ip_learn(lan966x, mdb_entry->cpu_copy,
    179				    mac, mdb_entry->vid, type);
    180}
    181
    182static struct lan966x_pgid_entry *
    183lan966x_pgid_entry_add(struct lan966x *lan966x, int index, u16 ports)
    184{
    185	struct lan966x_pgid_entry *pgid_entry;
    186
    187	pgid_entry = kzalloc(sizeof(*pgid_entry), GFP_KERNEL);
    188	if (!pgid_entry)
    189		return ERR_PTR(-ENOMEM);
    190
    191	pgid_entry->ports = ports;
    192	pgid_entry->index = index;
    193	refcount_set(&pgid_entry->refcount, 1);
    194
    195	list_add_tail(&pgid_entry->list, &lan966x->pgid_entries);
    196
    197	return pgid_entry;
    198}
    199
    200static struct lan966x_pgid_entry *
    201lan966x_pgid_entry_get(struct lan966x *lan966x,
    202		       struct lan966x_mdb_entry *mdb_entry)
    203{
    204	struct lan966x_pgid_entry *pgid_entry;
    205	int index;
    206
    207	/* Try to find an existing pgid that uses the same ports as the
    208	 * mdb_entry
    209	 */
    210	list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
    211		if (pgid_entry->ports == mdb_entry->ports) {
    212			refcount_inc(&pgid_entry->refcount);
    213			return pgid_entry;
    214		}
    215	}
    216
    217	/* Try to find an empty pgid entry and allocate one in case it finds it,
    218	 * otherwise it means that there are no more resources
    219	 */
    220	for (index = PGID_GP_START; index < PGID_GP_END; index++) {
    221		bool used = false;
    222
    223		list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
    224			if (pgid_entry->index == index) {
    225				used = true;
    226				break;
    227			}
    228		}
    229
    230		if (!used)
    231			return lan966x_pgid_entry_add(lan966x, index,
    232						      mdb_entry->ports);
    233	}
    234
    235	return ERR_PTR(-ENOSPC);
    236}
    237
    238static void lan966x_pgid_entry_del(struct lan966x *lan966x,
    239				   struct lan966x_pgid_entry *pgid_entry)
    240{
    241	if (!refcount_dec_and_test(&pgid_entry->refcount))
    242		return;
    243
    244	list_del(&pgid_entry->list);
    245	kfree(pgid_entry);
    246}
    247
    248static int lan966x_mdb_l2_add(struct lan966x_port *port,
    249			      const struct switchdev_obj_port_mdb *mdb,
    250			      enum macaccess_entry_type type)
    251{
    252	bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
    253	struct lan966x *lan966x = port->lan966x;
    254	struct lan966x_pgid_entry *pgid_entry;
    255	struct lan966x_mdb_entry *mdb_entry;
    256	unsigned char mac[ETH_ALEN];
    257
    258	mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
    259	if (!mdb_entry) {
    260		mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
    261		if (IS_ERR(mdb_entry))
    262			return PTR_ERR(mdb_entry);
    263	} else {
    264		lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
    265		lan966x_mdb_encode_mac(mac, mdb_entry, type);
    266		lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    267	}
    268
    269	if (cpu_port) {
    270		mdb_entry->ports |= BIT(CPU_PORT);
    271		mdb_entry->cpu_copy++;
    272	} else {
    273		mdb_entry->ports |= BIT(port->chip_port);
    274	}
    275
    276	pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
    277	if (IS_ERR(pgid_entry)) {
    278		list_del(&mdb_entry->list);
    279		kfree(mdb_entry);
    280		return PTR_ERR(pgid_entry);
    281	}
    282	mdb_entry->pgid = pgid_entry;
    283
    284	/* Copy the frame to CPU only if the CPU is in the VLAN */
    285	if (!lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
    286	    mdb_entry->cpu_copy)
    287		mdb_entry->ports &= BIT(CPU_PORT);
    288
    289	lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
    290		ANA_PGID_PGID,
    291		lan966x, ANA_PGID(pgid_entry->index));
    292
    293	return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
    294				 mdb_entry->vid, type);
    295}
    296
    297static int lan966x_mdb_l2_del(struct lan966x_port *port,
    298			      const struct switchdev_obj_port_mdb *mdb,
    299			      enum macaccess_entry_type type)
    300{
    301	bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
    302	struct lan966x *lan966x = port->lan966x;
    303	struct lan966x_pgid_entry *pgid_entry;
    304	struct lan966x_mdb_entry *mdb_entry;
    305	unsigned char mac[ETH_ALEN];
    306	u16 ports;
    307
    308	mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
    309	if (!mdb_entry)
    310		return -ENOENT;
    311
    312	ports = mdb_entry->ports;
    313	if (cpu_port) {
    314		/* If there are still other references to the CPU port then
    315		 * there is no point to delete and add again the same entry
    316		 */
    317		mdb_entry->cpu_copy--;
    318		if (mdb_entry->cpu_copy)
    319			return 0;
    320
    321		ports &= ~BIT(CPU_PORT);
    322	} else {
    323		ports &= ~BIT(port->chip_port);
    324	}
    325
    326	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    327	lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    328	lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
    329
    330	mdb_entry->ports = ports;
    331
    332	if (!mdb_entry->ports) {
    333		list_del(&mdb_entry->list);
    334		kfree(mdb_entry);
    335		return 0;
    336	}
    337
    338	pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
    339	if (IS_ERR(pgid_entry)) {
    340		list_del(&mdb_entry->list);
    341		kfree(mdb_entry);
    342		return PTR_ERR(pgid_entry);
    343	}
    344	mdb_entry->pgid = pgid_entry;
    345
    346	lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
    347		ANA_PGID_PGID,
    348		lan966x, ANA_PGID(pgid_entry->index));
    349
    350	return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
    351				 mdb_entry->vid, type);
    352}
    353
    354static enum macaccess_entry_type
    355lan966x_mdb_classify(const unsigned char *mac)
    356{
    357	if (mac[0] == 0x01 && mac[1] == 0x00 && mac[2] == 0x5e)
    358		return ENTRYTYPE_MACV4;
    359	if (mac[0] == 0x33 && mac[1] == 0x33)
    360		return ENTRYTYPE_MACV6;
    361	return ENTRYTYPE_LOCKED;
    362}
    363
    364int lan966x_handle_port_mdb_add(struct lan966x_port *port,
    365				const struct switchdev_obj *obj)
    366{
    367	const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
    368	enum macaccess_entry_type type;
    369
    370	/* Split the way the entries are added for ipv4/ipv6 and for l2. The
    371	 * reason is that for ipv4/ipv6 it doesn't require to use any pgid
    372	 * entry, while for l2 is required to use pgid entries
    373	 */
    374	type = lan966x_mdb_classify(mdb->addr);
    375	if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
    376		return lan966x_mdb_ip_add(port, mdb, type);
    377
    378	return lan966x_mdb_l2_add(port, mdb, type);
    379}
    380
    381int lan966x_handle_port_mdb_del(struct lan966x_port *port,
    382				const struct switchdev_obj *obj)
    383{
    384	const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
    385	enum macaccess_entry_type type;
    386
    387	/* Split the way the entries are removed for ipv4/ipv6 and for l2. The
    388	 * reason is that for ipv4/ipv6 it doesn't require to use any pgid
    389	 * entry, while for l2 is required to use pgid entries
    390	 */
    391	type = lan966x_mdb_classify(mdb->addr);
    392	if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
    393		return lan966x_mdb_ip_del(port, mdb, type);
    394
    395	return lan966x_mdb_l2_del(port, mdb, type);
    396}
    397
    398static void lan966x_mdb_ip_cpu_copy(struct lan966x *lan966x,
    399				    struct lan966x_mdb_entry *mdb_entry,
    400				    enum macaccess_entry_type type)
    401{
    402	unsigned char mac[ETH_ALEN];
    403
    404	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    405	lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    406	lan966x_mac_ip_learn(lan966x, true, mac, mdb_entry->vid, type);
    407}
    408
    409static void lan966x_mdb_l2_cpu_copy(struct lan966x *lan966x,
    410				    struct lan966x_mdb_entry *mdb_entry,
    411				    enum macaccess_entry_type type)
    412{
    413	struct lan966x_pgid_entry *pgid_entry;
    414	unsigned char mac[ETH_ALEN];
    415
    416	lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
    417	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    418	lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    419
    420	mdb_entry->ports |= BIT(CPU_PORT);
    421
    422	pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
    423	if (IS_ERR(pgid_entry))
    424		return;
    425
    426	mdb_entry->pgid = pgid_entry;
    427
    428	lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
    429		ANA_PGID_PGID,
    430		lan966x, ANA_PGID(pgid_entry->index));
    431
    432	lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
    433			  mdb_entry->vid, type);
    434}
    435
    436void lan966x_mdb_write_entries(struct lan966x *lan966x, u16 vid)
    437{
    438	struct lan966x_mdb_entry *mdb_entry;
    439	enum macaccess_entry_type type;
    440
    441	list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
    442		if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
    443			continue;
    444
    445		type = lan966x_mdb_classify(mdb_entry->mac);
    446		if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
    447			lan966x_mdb_ip_cpu_copy(lan966x, mdb_entry, type);
    448		else
    449			lan966x_mdb_l2_cpu_copy(lan966x, mdb_entry, type);
    450	}
    451}
    452
    453static void lan966x_mdb_ip_cpu_remove(struct lan966x *lan966x,
    454				      struct lan966x_mdb_entry *mdb_entry,
    455				      enum macaccess_entry_type type)
    456{
    457	unsigned char mac[ETH_ALEN];
    458
    459	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    460	lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    461	lan966x_mac_ip_learn(lan966x, false, mac, mdb_entry->vid, type);
    462}
    463
    464static void lan966x_mdb_l2_cpu_remove(struct lan966x *lan966x,
    465				      struct lan966x_mdb_entry *mdb_entry,
    466				      enum macaccess_entry_type type)
    467{
    468	struct lan966x_pgid_entry *pgid_entry;
    469	unsigned char mac[ETH_ALEN];
    470
    471	lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
    472	lan966x_mdb_encode_mac(mac, mdb_entry, type);
    473	lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    474
    475	mdb_entry->ports &= ~BIT(CPU_PORT);
    476
    477	pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
    478	if (IS_ERR(pgid_entry))
    479		return;
    480
    481	mdb_entry->pgid = pgid_entry;
    482
    483	lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
    484		ANA_PGID_PGID,
    485		lan966x, ANA_PGID(pgid_entry->index));
    486
    487	lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
    488			  mdb_entry->vid, type);
    489}
    490
    491void lan966x_mdb_erase_entries(struct lan966x *lan966x, u16 vid)
    492{
    493	struct lan966x_mdb_entry *mdb_entry;
    494	enum macaccess_entry_type type;
    495
    496	list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
    497		if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
    498			continue;
    499
    500		type = lan966x_mdb_classify(mdb_entry->mac);
    501		if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
    502			lan966x_mdb_ip_cpu_remove(lan966x, mdb_entry, type);
    503		else
    504			lan966x_mdb_l2_cpu_remove(lan966x, mdb_entry, type);
    505	}
    506}
    507
    508void lan966x_mdb_clear_entries(struct lan966x *lan966x)
    509{
    510	struct lan966x_mdb_entry *mdb_entry;
    511	enum macaccess_entry_type type;
    512	unsigned char mac[ETH_ALEN];
    513
    514	list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
    515		type = lan966x_mdb_classify(mdb_entry->mac);
    516
    517		lan966x_mdb_encode_mac(mac, mdb_entry, type);
    518		/* Remove just the MAC entry, still keep the PGID in case of L2
    519		 * entries because this can be restored at later point
    520		 */
    521		lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
    522	}
    523}
    524
    525void lan966x_mdb_restore_entries(struct lan966x *lan966x)
    526{
    527	struct lan966x_mdb_entry *mdb_entry;
    528	enum macaccess_entry_type type;
    529	unsigned char mac[ETH_ALEN];
    530	bool cpu_copy = false;
    531
    532	list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
    533		type = lan966x_mdb_classify(mdb_entry->mac);
    534
    535		lan966x_mdb_encode_mac(mac, mdb_entry, type);
    536		if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6) {
    537			/* Copy the frame to CPU only if the CPU is in the VLAN */
    538			if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x,
    539								  mdb_entry->vid) &&
    540			    mdb_entry->cpu_copy)
    541				cpu_copy = true;
    542
    543			lan966x_mac_ip_learn(lan966x, cpu_copy, mac,
    544					     mdb_entry->vid, type);
    545		} else {
    546			lan966x_mac_learn(lan966x, mdb_entry->pgid->index,
    547					  mdb_entry->mac,
    548					  mdb_entry->vid, type);
    549		}
    550	}
    551}