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

prestera_router_hw.c (7456B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */
      3
      4#include <linux/rhashtable.h>
      5
      6#include "prestera.h"
      7#include "prestera_hw.h"
      8#include "prestera_router_hw.h"
      9#include "prestera_acl.h"
     10
     11/*            +--+
     12 *   +------->|vr|<-+
     13 *   |        +--+  |
     14 *   |              |
     15 * +-+-------+   +--+---+-+
     16 * |rif_entry|   |fib_node|
     17 * +---------+   +--------+
     18 *  Rif is        Fib - is exit point
     19 *  used as
     20 *  entry point
     21 *  for vr in hw
     22 */
     23
     24#define PRESTERA_NHGR_UNUSED (0)
     25#define PRESTERA_NHGR_DROP (0xFFFFFFFF)
     26
     27static const struct rhashtable_params __prestera_fib_ht_params = {
     28	.key_offset  = offsetof(struct prestera_fib_node, key),
     29	.head_offset = offsetof(struct prestera_fib_node, ht_node),
     30	.key_len     = sizeof(struct prestera_fib_key),
     31	.automatic_shrinking = true,
     32};
     33
     34int prestera_router_hw_init(struct prestera_switch *sw)
     35{
     36	int err;
     37
     38	err = rhashtable_init(&sw->router->fib_ht,
     39			      &__prestera_fib_ht_params);
     40	if (err)
     41		goto err_fib_ht_init;
     42
     43	INIT_LIST_HEAD(&sw->router->vr_list);
     44	INIT_LIST_HEAD(&sw->router->rif_entry_list);
     45
     46err_fib_ht_init:
     47	return 0;
     48}
     49
     50void prestera_router_hw_fini(struct prestera_switch *sw)
     51{
     52	WARN_ON(!list_empty(&sw->router->vr_list));
     53	WARN_ON(!list_empty(&sw->router->rif_entry_list));
     54	rhashtable_destroy(&sw->router->fib_ht);
     55}
     56
     57static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw,
     58					      u32 tb_id)
     59{
     60	struct prestera_vr *vr;
     61
     62	list_for_each_entry(vr, &sw->router->vr_list, router_node) {
     63		if (vr->tb_id == tb_id)
     64			return vr;
     65	}
     66
     67	return NULL;
     68}
     69
     70static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw,
     71						u32 tb_id,
     72						struct netlink_ext_ack *extack)
     73{
     74	struct prestera_vr *vr;
     75	int err;
     76
     77	vr = kzalloc(sizeof(*vr), GFP_KERNEL);
     78	if (!vr) {
     79		err = -ENOMEM;
     80		goto err_alloc_vr;
     81	}
     82
     83	vr->tb_id = tb_id;
     84
     85	err = prestera_hw_vr_create(sw, &vr->hw_vr_id);
     86	if (err)
     87		goto err_hw_create;
     88
     89	list_add(&vr->router_node, &sw->router->vr_list);
     90
     91	return vr;
     92
     93err_hw_create:
     94	kfree(vr);
     95err_alloc_vr:
     96	return ERR_PTR(err);
     97}
     98
     99static void __prestera_vr_destroy(struct prestera_switch *sw,
    100				  struct prestera_vr *vr)
    101{
    102	list_del(&vr->router_node);
    103	prestera_hw_vr_delete(sw, vr->hw_vr_id);
    104	kfree(vr);
    105}
    106
    107static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id,
    108					   struct netlink_ext_ack *extack)
    109{
    110	struct prestera_vr *vr;
    111
    112	vr = __prestera_vr_find(sw, tb_id);
    113	if (vr) {
    114		refcount_inc(&vr->refcount);
    115	} else {
    116		vr = __prestera_vr_create(sw, tb_id, extack);
    117		if (IS_ERR(vr))
    118			return ERR_CAST(vr);
    119
    120		refcount_set(&vr->refcount, 1);
    121	}
    122
    123	return vr;
    124}
    125
    126static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr)
    127{
    128	if (refcount_dec_and_test(&vr->refcount))
    129		__prestera_vr_destroy(sw, vr);
    130}
    131
    132/* iface is overhead struct. vr_id also can be removed. */
    133static int
    134__prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in,
    135			      struct prestera_rif_entry_key *out)
    136{
    137	memset(out, 0, sizeof(*out));
    138
    139	switch (in->iface.type) {
    140	case PRESTERA_IF_PORT_E:
    141		out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num;
    142		out->iface.dev_port.port_num = in->iface.dev_port.port_num;
    143		break;
    144	case PRESTERA_IF_LAG_E:
    145		out->iface.lag_id = in->iface.lag_id;
    146		break;
    147	case PRESTERA_IF_VID_E:
    148		out->iface.vlan_id = in->iface.vlan_id;
    149		break;
    150	default:
    151		WARN(1, "Unsupported iface type");
    152		return -EINVAL;
    153	}
    154
    155	out->iface.type = in->iface.type;
    156	return 0;
    157}
    158
    159struct prestera_rif_entry *
    160prestera_rif_entry_find(const struct prestera_switch *sw,
    161			const struct prestera_rif_entry_key *k)
    162{
    163	struct prestera_rif_entry *rif_entry;
    164	struct prestera_rif_entry_key lk; /* lookup key */
    165
    166	if (__prestera_rif_entry_key_copy(k, &lk))
    167		return NULL;
    168
    169	list_for_each_entry(rif_entry, &sw->router->rif_entry_list,
    170			    router_node) {
    171		if (!memcmp(k, &rif_entry->key, sizeof(*k)))
    172			return rif_entry;
    173	}
    174
    175	return NULL;
    176}
    177
    178void prestera_rif_entry_destroy(struct prestera_switch *sw,
    179				struct prestera_rif_entry *e)
    180{
    181	struct prestera_iface iface;
    182
    183	list_del(&e->router_node);
    184
    185	memcpy(&iface, &e->key.iface, sizeof(iface));
    186	iface.vr_id = e->vr->hw_vr_id;
    187	prestera_hw_rif_delete(sw, e->hw_id, &iface);
    188
    189	prestera_vr_put(sw, e->vr);
    190	kfree(e);
    191}
    192
    193struct prestera_rif_entry *
    194prestera_rif_entry_create(struct prestera_switch *sw,
    195			  struct prestera_rif_entry_key *k,
    196			  u32 tb_id, const unsigned char *addr)
    197{
    198	int err;
    199	struct prestera_rif_entry *e;
    200	struct prestera_iface iface;
    201
    202	e = kzalloc(sizeof(*e), GFP_KERNEL);
    203	if (!e)
    204		goto err_kzalloc;
    205
    206	if (__prestera_rif_entry_key_copy(k, &e->key))
    207		goto err_key_copy;
    208
    209	e->vr = prestera_vr_get(sw, tb_id, NULL);
    210	if (IS_ERR(e->vr))
    211		goto err_vr_get;
    212
    213	memcpy(&e->addr, addr, sizeof(e->addr));
    214
    215	/* HW */
    216	memcpy(&iface, &e->key.iface, sizeof(iface));
    217	iface.vr_id = e->vr->hw_vr_id;
    218	err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id);
    219	if (err)
    220		goto err_hw_create;
    221
    222	list_add(&e->router_node, &sw->router->rif_entry_list);
    223
    224	return e;
    225
    226err_hw_create:
    227	prestera_vr_put(sw, e->vr);
    228err_vr_get:
    229err_key_copy:
    230	kfree(e);
    231err_kzalloc:
    232	return NULL;
    233}
    234
    235struct prestera_fib_node *
    236prestera_fib_node_find(struct prestera_switch *sw, struct prestera_fib_key *key)
    237{
    238	struct prestera_fib_node *fib_node;
    239
    240	fib_node = rhashtable_lookup_fast(&sw->router->fib_ht, key,
    241					  __prestera_fib_ht_params);
    242	return fib_node;
    243}
    244
    245static void __prestera_fib_node_destruct(struct prestera_switch *sw,
    246					 struct prestera_fib_node *fib_node)
    247{
    248	struct prestera_vr *vr;
    249
    250	vr = fib_node->info.vr;
    251	prestera_hw_lpm_del(sw, vr->hw_vr_id, fib_node->key.addr.u.ipv4,
    252			    fib_node->key.prefix_len);
    253	switch (fib_node->info.type) {
    254	case PRESTERA_FIB_TYPE_TRAP:
    255		break;
    256	case PRESTERA_FIB_TYPE_DROP:
    257		break;
    258	default:
    259	      pr_err("Unknown fib_node->info.type = %d",
    260		     fib_node->info.type);
    261	}
    262
    263	prestera_vr_put(sw, vr);
    264}
    265
    266void prestera_fib_node_destroy(struct prestera_switch *sw,
    267			       struct prestera_fib_node *fib_node)
    268{
    269	__prestera_fib_node_destruct(sw, fib_node);
    270	rhashtable_remove_fast(&sw->router->fib_ht, &fib_node->ht_node,
    271			       __prestera_fib_ht_params);
    272	kfree(fib_node);
    273}
    274
    275struct prestera_fib_node *
    276prestera_fib_node_create(struct prestera_switch *sw,
    277			 struct prestera_fib_key *key,
    278			 enum prestera_fib_type fib_type)
    279{
    280	struct prestera_fib_node *fib_node;
    281	u32 grp_id;
    282	struct prestera_vr *vr;
    283	int err;
    284
    285	fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL);
    286	if (!fib_node)
    287		goto err_kzalloc;
    288
    289	memcpy(&fib_node->key, key, sizeof(*key));
    290	fib_node->info.type = fib_type;
    291
    292	vr = prestera_vr_get(sw, key->tb_id, NULL);
    293	if (IS_ERR(vr))
    294		goto err_vr_get;
    295
    296	fib_node->info.vr = vr;
    297
    298	switch (fib_type) {
    299	case PRESTERA_FIB_TYPE_TRAP:
    300		grp_id = PRESTERA_NHGR_UNUSED;
    301		break;
    302	case PRESTERA_FIB_TYPE_DROP:
    303		grp_id = PRESTERA_NHGR_DROP;
    304		break;
    305	default:
    306		pr_err("Unsupported fib_type %d", fib_type);
    307		goto err_nh_grp_get;
    308	}
    309
    310	err = prestera_hw_lpm_add(sw, vr->hw_vr_id, key->addr.u.ipv4,
    311				  key->prefix_len, grp_id);
    312	if (err)
    313		goto err_lpm_add;
    314
    315	err = rhashtable_insert_fast(&sw->router->fib_ht, &fib_node->ht_node,
    316				     __prestera_fib_ht_params);
    317	if (err)
    318		goto err_ht_insert;
    319
    320	return fib_node;
    321
    322err_ht_insert:
    323	prestera_hw_lpm_del(sw, vr->hw_vr_id, key->addr.u.ipv4,
    324			    key->prefix_len);
    325err_lpm_add:
    326err_nh_grp_get:
    327	prestera_vr_put(sw, vr);
    328err_vr_get:
    329	kfree(fib_node);
    330err_kzalloc:
    331	return NULL;
    332}