1bca5859bSYevhen Orlov // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2bca5859bSYevhen Orlov /* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */ 3bca5859bSYevhen Orlov 4bca5859bSYevhen Orlov #include <linux/rhashtable.h> 5bca5859bSYevhen Orlov 6bca5859bSYevhen Orlov #include "prestera.h" 7bca5859bSYevhen Orlov #include "prestera_hw.h" 8bca5859bSYevhen Orlov #include "prestera_router_hw.h" 9bca5859bSYevhen Orlov #include "prestera_acl.h" 10bca5859bSYevhen Orlov 110a23ae23SYevhen Orlov /* Nexthop is pointed 120a23ae23SYevhen Orlov * to port (not rif) 130a23ae23SYevhen Orlov * +-------+ 140a23ae23SYevhen Orlov * +>|nexthop| 150a23ae23SYevhen Orlov * | +-------+ 160a23ae23SYevhen Orlov * | 170a23ae23SYevhen Orlov * +--+ +-----++ 180a23ae23SYevhen Orlov * +------->|vr|<-+ +>|nh_grp| 190a23ae23SYevhen Orlov * | +--+ | | +------+ 200a23ae23SYevhen Orlov * | | | 2116de3db1SYevhen Orlov * +-+-------+ +--+---+-+ 2216de3db1SYevhen Orlov * |rif_entry| |fib_node| 2316de3db1SYevhen Orlov * +---------+ +--------+ 2416de3db1SYevhen Orlov * Rif is Fib - is exit point 25bca5859bSYevhen Orlov * used as 26bca5859bSYevhen Orlov * entry point 27bca5859bSYevhen Orlov * for vr in hw 28bca5859bSYevhen Orlov */ 29bca5859bSYevhen Orlov 3016de3db1SYevhen Orlov #define PRESTERA_NHGR_UNUSED (0) 3116de3db1SYevhen Orlov #define PRESTERA_NHGR_DROP (0xFFFFFFFF) 320a23ae23SYevhen Orlov /* Need to merge it with router_manager */ 330a23ae23SYevhen Orlov #define PRESTERA_NH_ACTIVE_JIFFER_FILTER 3000 /* ms */ 3416de3db1SYevhen Orlov 3516de3db1SYevhen Orlov static const struct rhashtable_params __prestera_fib_ht_params = { 3616de3db1SYevhen Orlov .key_offset = offsetof(struct prestera_fib_node, key), 3716de3db1SYevhen Orlov .head_offset = offsetof(struct prestera_fib_node, ht_node), 3816de3db1SYevhen Orlov .key_len = sizeof(struct prestera_fib_key), 3916de3db1SYevhen Orlov .automatic_shrinking = true, 4016de3db1SYevhen Orlov }; 4116de3db1SYevhen Orlov 420a23ae23SYevhen Orlov static const struct rhashtable_params __prestera_nh_neigh_ht_params = { 430a23ae23SYevhen Orlov .key_offset = offsetof(struct prestera_nh_neigh, key), 440a23ae23SYevhen Orlov .key_len = sizeof(struct prestera_nh_neigh_key), 450a23ae23SYevhen Orlov .head_offset = offsetof(struct prestera_nh_neigh, ht_node), 460a23ae23SYevhen Orlov }; 470a23ae23SYevhen Orlov 480a23ae23SYevhen Orlov static const struct rhashtable_params __prestera_nexthop_group_ht_params = { 490a23ae23SYevhen Orlov .key_offset = offsetof(struct prestera_nexthop_group, key), 500a23ae23SYevhen Orlov .key_len = sizeof(struct prestera_nexthop_group_key), 510a23ae23SYevhen Orlov .head_offset = offsetof(struct prestera_nexthop_group, ht_node), 520a23ae23SYevhen Orlov }; 530a23ae23SYevhen Orlov 540a23ae23SYevhen Orlov static int prestera_nexthop_group_set(struct prestera_switch *sw, 550a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp); 560a23ae23SYevhen Orlov static bool 570a23ae23SYevhen Orlov prestera_nexthop_group_util_hw_state(struct prestera_switch *sw, 580a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp); 591e7313e8SYevhen Orlov static void prestera_fib_node_destroy_ht_cb(void *ptr, void *arg); 600a23ae23SYevhen Orlov 610a23ae23SYevhen Orlov /* TODO: move to router.h as macros */ 620a23ae23SYevhen Orlov static bool prestera_nh_neigh_key_is_valid(struct prestera_nh_neigh_key *key) 630a23ae23SYevhen Orlov { 640a23ae23SYevhen Orlov return memchr_inv(key, 0, sizeof(*key)) ? true : false; 650a23ae23SYevhen Orlov } 660a23ae23SYevhen Orlov 67bca5859bSYevhen Orlov int prestera_router_hw_init(struct prestera_switch *sw) 68bca5859bSYevhen Orlov { 6916de3db1SYevhen Orlov int err; 7016de3db1SYevhen Orlov 710a23ae23SYevhen Orlov err = rhashtable_init(&sw->router->nh_neigh_ht, 720a23ae23SYevhen Orlov &__prestera_nh_neigh_ht_params); 730a23ae23SYevhen Orlov if (err) 740a23ae23SYevhen Orlov goto err_nh_neigh_ht_init; 750a23ae23SYevhen Orlov 760a23ae23SYevhen Orlov err = rhashtable_init(&sw->router->nexthop_group_ht, 770a23ae23SYevhen Orlov &__prestera_nexthop_group_ht_params); 780a23ae23SYevhen Orlov if (err) 790a23ae23SYevhen Orlov goto err_nexthop_grp_ht_init; 800a23ae23SYevhen Orlov 8116de3db1SYevhen Orlov err = rhashtable_init(&sw->router->fib_ht, 8216de3db1SYevhen Orlov &__prestera_fib_ht_params); 8316de3db1SYevhen Orlov if (err) 8416de3db1SYevhen Orlov goto err_fib_ht_init; 8516de3db1SYevhen Orlov 86bca5859bSYevhen Orlov INIT_LIST_HEAD(&sw->router->vr_list); 87bca5859bSYevhen Orlov INIT_LIST_HEAD(&sw->router->rif_entry_list); 88bca5859bSYevhen Orlov 890a23ae23SYevhen Orlov return 0; 900a23ae23SYevhen Orlov 9116de3db1SYevhen Orlov err_fib_ht_init: 920a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nexthop_group_ht); 930a23ae23SYevhen Orlov err_nexthop_grp_ht_init: 940a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nh_neigh_ht); 950a23ae23SYevhen Orlov err_nh_neigh_ht_init: 96bca5859bSYevhen Orlov return 0; 97bca5859bSYevhen Orlov } 98bca5859bSYevhen Orlov 99e179f045SYevhen Orlov void prestera_router_hw_fini(struct prestera_switch *sw) 100e179f045SYevhen Orlov { 1011e7313e8SYevhen Orlov rhashtable_free_and_destroy(&sw->router->fib_ht, 1021e7313e8SYevhen Orlov prestera_fib_node_destroy_ht_cb, sw); 103e179f045SYevhen Orlov WARN_ON(!list_empty(&sw->router->vr_list)); 104e179f045SYevhen Orlov WARN_ON(!list_empty(&sw->router->rif_entry_list)); 10516de3db1SYevhen Orlov rhashtable_destroy(&sw->router->fib_ht); 1060a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nexthop_group_ht); 1070a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nh_neigh_ht); 108e179f045SYevhen Orlov } 109e179f045SYevhen Orlov 110bca5859bSYevhen Orlov static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw, 111bca5859bSYevhen Orlov u32 tb_id) 112bca5859bSYevhen Orlov { 113bca5859bSYevhen Orlov struct prestera_vr *vr; 114bca5859bSYevhen Orlov 115bca5859bSYevhen Orlov list_for_each_entry(vr, &sw->router->vr_list, router_node) { 116bca5859bSYevhen Orlov if (vr->tb_id == tb_id) 117bca5859bSYevhen Orlov return vr; 118bca5859bSYevhen Orlov } 119bca5859bSYevhen Orlov 120bca5859bSYevhen Orlov return NULL; 121bca5859bSYevhen Orlov } 122bca5859bSYevhen Orlov 123bca5859bSYevhen Orlov static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw, 124bca5859bSYevhen Orlov u32 tb_id, 125bca5859bSYevhen Orlov struct netlink_ext_ack *extack) 126bca5859bSYevhen Orlov { 127bca5859bSYevhen Orlov struct prestera_vr *vr; 128bca5859bSYevhen Orlov int err; 129bca5859bSYevhen Orlov 130bca5859bSYevhen Orlov vr = kzalloc(sizeof(*vr), GFP_KERNEL); 131bca5859bSYevhen Orlov if (!vr) { 132bca5859bSYevhen Orlov err = -ENOMEM; 133bca5859bSYevhen Orlov goto err_alloc_vr; 134bca5859bSYevhen Orlov } 135bca5859bSYevhen Orlov 136bca5859bSYevhen Orlov vr->tb_id = tb_id; 1376a1ba875SYevhen Orlov 1386a1ba875SYevhen Orlov err = prestera_hw_vr_create(sw, &vr->hw_vr_id); 1396a1ba875SYevhen Orlov if (err) 1406a1ba875SYevhen Orlov goto err_hw_create; 141bca5859bSYevhen Orlov 142bca5859bSYevhen Orlov list_add(&vr->router_node, &sw->router->vr_list); 143bca5859bSYevhen Orlov 144bca5859bSYevhen Orlov return vr; 145bca5859bSYevhen Orlov 1466a1ba875SYevhen Orlov err_hw_create: 147bca5859bSYevhen Orlov kfree(vr); 1486a1ba875SYevhen Orlov err_alloc_vr: 149bca5859bSYevhen Orlov return ERR_PTR(err); 150bca5859bSYevhen Orlov } 151bca5859bSYevhen Orlov 152bca5859bSYevhen Orlov static void __prestera_vr_destroy(struct prestera_switch *sw, 153bca5859bSYevhen Orlov struct prestera_vr *vr) 154bca5859bSYevhen Orlov { 155bca5859bSYevhen Orlov list_del(&vr->router_node); 1566a1ba875SYevhen Orlov prestera_hw_vr_delete(sw, vr->hw_vr_id); 157bca5859bSYevhen Orlov kfree(vr); 158bca5859bSYevhen Orlov } 159bca5859bSYevhen Orlov 160bca5859bSYevhen Orlov static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id, 161bca5859bSYevhen Orlov struct netlink_ext_ack *extack) 162bca5859bSYevhen Orlov { 163bca5859bSYevhen Orlov struct prestera_vr *vr; 164bca5859bSYevhen Orlov 165bca5859bSYevhen Orlov vr = __prestera_vr_find(sw, tb_id); 1666a1ba875SYevhen Orlov if (vr) { 1676a1ba875SYevhen Orlov refcount_inc(&vr->refcount); 1686a1ba875SYevhen Orlov } else { 169bca5859bSYevhen Orlov vr = __prestera_vr_create(sw, tb_id, extack); 170bca5859bSYevhen Orlov if (IS_ERR(vr)) 171bca5859bSYevhen Orlov return ERR_CAST(vr); 172bca5859bSYevhen Orlov 1736a1ba875SYevhen Orlov refcount_set(&vr->refcount, 1); 1746a1ba875SYevhen Orlov } 1756a1ba875SYevhen Orlov 176bca5859bSYevhen Orlov return vr; 177bca5859bSYevhen Orlov } 178bca5859bSYevhen Orlov 179bca5859bSYevhen Orlov static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr) 180bca5859bSYevhen Orlov { 1816a1ba875SYevhen Orlov if (refcount_dec_and_test(&vr->refcount)) 182bca5859bSYevhen Orlov __prestera_vr_destroy(sw, vr); 183bca5859bSYevhen Orlov } 184bca5859bSYevhen Orlov 185bca5859bSYevhen Orlov /* iface is overhead struct. vr_id also can be removed. */ 186bca5859bSYevhen Orlov static int 187bca5859bSYevhen Orlov __prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in, 188bca5859bSYevhen Orlov struct prestera_rif_entry_key *out) 189bca5859bSYevhen Orlov { 190bca5859bSYevhen Orlov memset(out, 0, sizeof(*out)); 191bca5859bSYevhen Orlov 192bca5859bSYevhen Orlov switch (in->iface.type) { 193bca5859bSYevhen Orlov case PRESTERA_IF_PORT_E: 194bca5859bSYevhen Orlov out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num; 195bca5859bSYevhen Orlov out->iface.dev_port.port_num = in->iface.dev_port.port_num; 196bca5859bSYevhen Orlov break; 197bca5859bSYevhen Orlov case PRESTERA_IF_LAG_E: 198bca5859bSYevhen Orlov out->iface.lag_id = in->iface.lag_id; 199bca5859bSYevhen Orlov break; 200bca5859bSYevhen Orlov case PRESTERA_IF_VID_E: 201bca5859bSYevhen Orlov out->iface.vlan_id = in->iface.vlan_id; 202bca5859bSYevhen Orlov break; 203bca5859bSYevhen Orlov default: 20432d098bbSYevhen Orlov WARN(1, "Unsupported iface type"); 205bca5859bSYevhen Orlov return -EINVAL; 206bca5859bSYevhen Orlov } 207bca5859bSYevhen Orlov 208bca5859bSYevhen Orlov out->iface.type = in->iface.type; 209bca5859bSYevhen Orlov return 0; 210bca5859bSYevhen Orlov } 211bca5859bSYevhen Orlov 212bca5859bSYevhen Orlov struct prestera_rif_entry * 213bca5859bSYevhen Orlov prestera_rif_entry_find(const struct prestera_switch *sw, 214bca5859bSYevhen Orlov const struct prestera_rif_entry_key *k) 215bca5859bSYevhen Orlov { 216bca5859bSYevhen Orlov struct prestera_rif_entry *rif_entry; 217bca5859bSYevhen Orlov struct prestera_rif_entry_key lk; /* lookup key */ 218bca5859bSYevhen Orlov 219bca5859bSYevhen Orlov if (__prestera_rif_entry_key_copy(k, &lk)) 220bca5859bSYevhen Orlov return NULL; 221bca5859bSYevhen Orlov 222bca5859bSYevhen Orlov list_for_each_entry(rif_entry, &sw->router->rif_entry_list, 223bca5859bSYevhen Orlov router_node) { 224bca5859bSYevhen Orlov if (!memcmp(k, &rif_entry->key, sizeof(*k))) 225bca5859bSYevhen Orlov return rif_entry; 226bca5859bSYevhen Orlov } 227bca5859bSYevhen Orlov 228bca5859bSYevhen Orlov return NULL; 229bca5859bSYevhen Orlov } 230bca5859bSYevhen Orlov 231bca5859bSYevhen Orlov void prestera_rif_entry_destroy(struct prestera_switch *sw, 232bca5859bSYevhen Orlov struct prestera_rif_entry *e) 233bca5859bSYevhen Orlov { 234bca5859bSYevhen Orlov struct prestera_iface iface; 235bca5859bSYevhen Orlov 236bca5859bSYevhen Orlov list_del(&e->router_node); 237bca5859bSYevhen Orlov 238bca5859bSYevhen Orlov memcpy(&iface, &e->key.iface, sizeof(iface)); 239bca5859bSYevhen Orlov iface.vr_id = e->vr->hw_vr_id; 240bca5859bSYevhen Orlov prestera_hw_rif_delete(sw, e->hw_id, &iface); 241bca5859bSYevhen Orlov 242bca5859bSYevhen Orlov prestera_vr_put(sw, e->vr); 243bca5859bSYevhen Orlov kfree(e); 244bca5859bSYevhen Orlov } 245bca5859bSYevhen Orlov 246bca5859bSYevhen Orlov struct prestera_rif_entry * 247bca5859bSYevhen Orlov prestera_rif_entry_create(struct prestera_switch *sw, 248bca5859bSYevhen Orlov struct prestera_rif_entry_key *k, 249bca5859bSYevhen Orlov u32 tb_id, const unsigned char *addr) 250bca5859bSYevhen Orlov { 251bca5859bSYevhen Orlov int err; 252bca5859bSYevhen Orlov struct prestera_rif_entry *e; 253bca5859bSYevhen Orlov struct prestera_iface iface; 254bca5859bSYevhen Orlov 255bca5859bSYevhen Orlov e = kzalloc(sizeof(*e), GFP_KERNEL); 256bca5859bSYevhen Orlov if (!e) 257bca5859bSYevhen Orlov goto err_kzalloc; 258bca5859bSYevhen Orlov 259bca5859bSYevhen Orlov if (__prestera_rif_entry_key_copy(k, &e->key)) 260bca5859bSYevhen Orlov goto err_key_copy; 261bca5859bSYevhen Orlov 262bca5859bSYevhen Orlov e->vr = prestera_vr_get(sw, tb_id, NULL); 263bca5859bSYevhen Orlov if (IS_ERR(e->vr)) 264bca5859bSYevhen Orlov goto err_vr_get; 265bca5859bSYevhen Orlov 266bca5859bSYevhen Orlov memcpy(&e->addr, addr, sizeof(e->addr)); 267bca5859bSYevhen Orlov 268bca5859bSYevhen Orlov /* HW */ 269bca5859bSYevhen Orlov memcpy(&iface, &e->key.iface, sizeof(iface)); 270bca5859bSYevhen Orlov iface.vr_id = e->vr->hw_vr_id; 271bca5859bSYevhen Orlov err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id); 272bca5859bSYevhen Orlov if (err) 273bca5859bSYevhen Orlov goto err_hw_create; 274bca5859bSYevhen Orlov 275bca5859bSYevhen Orlov list_add(&e->router_node, &sw->router->rif_entry_list); 276bca5859bSYevhen Orlov 277bca5859bSYevhen Orlov return e; 278bca5859bSYevhen Orlov 279bca5859bSYevhen Orlov err_hw_create: 280bca5859bSYevhen Orlov prestera_vr_put(sw, e->vr); 281bca5859bSYevhen Orlov err_vr_get: 282bca5859bSYevhen Orlov err_key_copy: 283bca5859bSYevhen Orlov kfree(e); 284bca5859bSYevhen Orlov err_kzalloc: 285bca5859bSYevhen Orlov return NULL; 286bca5859bSYevhen Orlov } 28716de3db1SYevhen Orlov 2880a23ae23SYevhen Orlov static void __prestera_nh_neigh_destroy(struct prestera_switch *sw, 2890a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh) 2900a23ae23SYevhen Orlov { 2910a23ae23SYevhen Orlov rhashtable_remove_fast(&sw->router->nh_neigh_ht, 2920a23ae23SYevhen Orlov &neigh->ht_node, 2930a23ae23SYevhen Orlov __prestera_nh_neigh_ht_params); 2940a23ae23SYevhen Orlov kfree(neigh); 2950a23ae23SYevhen Orlov } 2960a23ae23SYevhen Orlov 2970a23ae23SYevhen Orlov static struct prestera_nh_neigh * 2980a23ae23SYevhen Orlov __prestera_nh_neigh_create(struct prestera_switch *sw, 2990a23ae23SYevhen Orlov struct prestera_nh_neigh_key *key) 3000a23ae23SYevhen Orlov { 3010a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh; 3020a23ae23SYevhen Orlov int err; 3030a23ae23SYevhen Orlov 3040a23ae23SYevhen Orlov neigh = kzalloc(sizeof(*neigh), GFP_KERNEL); 3050a23ae23SYevhen Orlov if (!neigh) 3060a23ae23SYevhen Orlov goto err_kzalloc; 3070a23ae23SYevhen Orlov 3080a23ae23SYevhen Orlov memcpy(&neigh->key, key, sizeof(*key)); 3090a23ae23SYevhen Orlov neigh->info.connected = false; 3100a23ae23SYevhen Orlov INIT_LIST_HEAD(&neigh->nexthop_group_list); 3110a23ae23SYevhen Orlov err = rhashtable_insert_fast(&sw->router->nh_neigh_ht, 3120a23ae23SYevhen Orlov &neigh->ht_node, 3130a23ae23SYevhen Orlov __prestera_nh_neigh_ht_params); 3140a23ae23SYevhen Orlov if (err) 3150a23ae23SYevhen Orlov goto err_rhashtable_insert; 3160a23ae23SYevhen Orlov 3170a23ae23SYevhen Orlov return neigh; 3180a23ae23SYevhen Orlov 3190a23ae23SYevhen Orlov err_rhashtable_insert: 3200a23ae23SYevhen Orlov kfree(neigh); 3210a23ae23SYevhen Orlov err_kzalloc: 3220a23ae23SYevhen Orlov return NULL; 3230a23ae23SYevhen Orlov } 3240a23ae23SYevhen Orlov 3250a23ae23SYevhen Orlov struct prestera_nh_neigh * 3260a23ae23SYevhen Orlov prestera_nh_neigh_find(struct prestera_switch *sw, 3270a23ae23SYevhen Orlov struct prestera_nh_neigh_key *key) 3280a23ae23SYevhen Orlov { 3290a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh; 3300a23ae23SYevhen Orlov 3310a23ae23SYevhen Orlov nh_neigh = rhashtable_lookup_fast(&sw->router->nh_neigh_ht, 3320a23ae23SYevhen Orlov key, __prestera_nh_neigh_ht_params); 3330a23ae23SYevhen Orlov return IS_ERR(nh_neigh) ? NULL : nh_neigh; 3340a23ae23SYevhen Orlov } 3350a23ae23SYevhen Orlov 3360a23ae23SYevhen Orlov struct prestera_nh_neigh * 3370a23ae23SYevhen Orlov prestera_nh_neigh_get(struct prestera_switch *sw, 3380a23ae23SYevhen Orlov struct prestera_nh_neigh_key *key) 3390a23ae23SYevhen Orlov { 3400a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh; 3410a23ae23SYevhen Orlov 3420a23ae23SYevhen Orlov neigh = prestera_nh_neigh_find(sw, key); 3430a23ae23SYevhen Orlov if (!neigh) 3440a23ae23SYevhen Orlov return __prestera_nh_neigh_create(sw, key); 3450a23ae23SYevhen Orlov 3460a23ae23SYevhen Orlov return neigh; 3470a23ae23SYevhen Orlov } 3480a23ae23SYevhen Orlov 3490a23ae23SYevhen Orlov void prestera_nh_neigh_put(struct prestera_switch *sw, 3500a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh) 3510a23ae23SYevhen Orlov { 3520a23ae23SYevhen Orlov if (list_empty(&neigh->nexthop_group_list)) 3530a23ae23SYevhen Orlov __prestera_nh_neigh_destroy(sw, neigh); 3540a23ae23SYevhen Orlov } 3550a23ae23SYevhen Orlov 3560a23ae23SYevhen Orlov /* Updates new prestera_neigh_info */ 3570a23ae23SYevhen Orlov int prestera_nh_neigh_set(struct prestera_switch *sw, 3580a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh) 3590a23ae23SYevhen Orlov { 3600a23ae23SYevhen Orlov struct prestera_nh_neigh_head *nh_head; 3610a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 3620a23ae23SYevhen Orlov int err; 3630a23ae23SYevhen Orlov 3640a23ae23SYevhen Orlov list_for_each_entry(nh_head, &neigh->nexthop_group_list, head) { 3650a23ae23SYevhen Orlov nh_grp = nh_head->this; 3660a23ae23SYevhen Orlov err = prestera_nexthop_group_set(sw, nh_grp); 3670a23ae23SYevhen Orlov if (err) 3680a23ae23SYevhen Orlov return err; 3690a23ae23SYevhen Orlov } 3700a23ae23SYevhen Orlov 3710a23ae23SYevhen Orlov return 0; 3720a23ae23SYevhen Orlov } 3730a23ae23SYevhen Orlov 3740a23ae23SYevhen Orlov bool prestera_nh_neigh_util_hw_state(struct prestera_switch *sw, 3750a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh) 3760a23ae23SYevhen Orlov { 3770a23ae23SYevhen Orlov bool state; 3780a23ae23SYevhen Orlov struct prestera_nh_neigh_head *nh_head, *tmp; 3790a23ae23SYevhen Orlov 3800a23ae23SYevhen Orlov state = false; 3810a23ae23SYevhen Orlov list_for_each_entry_safe(nh_head, tmp, 3820a23ae23SYevhen Orlov &nh_neigh->nexthop_group_list, head) { 3830a23ae23SYevhen Orlov state = prestera_nexthop_group_util_hw_state(sw, nh_head->this); 3840a23ae23SYevhen Orlov if (state) 3850a23ae23SYevhen Orlov goto out; 3860a23ae23SYevhen Orlov } 3870a23ae23SYevhen Orlov 3880a23ae23SYevhen Orlov out: 3890a23ae23SYevhen Orlov return state; 3900a23ae23SYevhen Orlov } 3910a23ae23SYevhen Orlov 3920a23ae23SYevhen Orlov static struct prestera_nexthop_group * 3930a23ae23SYevhen Orlov __prestera_nexthop_group_create(struct prestera_switch *sw, 3940a23ae23SYevhen Orlov struct prestera_nexthop_group_key *key) 3950a23ae23SYevhen Orlov { 3960a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 3970a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh; 3980a23ae23SYevhen Orlov int nh_cnt, err, gid; 3990a23ae23SYevhen Orlov 4000a23ae23SYevhen Orlov nh_grp = kzalloc(sizeof(*nh_grp), GFP_KERNEL); 4010a23ae23SYevhen Orlov if (!nh_grp) 4020a23ae23SYevhen Orlov goto err_kzalloc; 4030a23ae23SYevhen Orlov 4040a23ae23SYevhen Orlov memcpy(&nh_grp->key, key, sizeof(*key)); 4050a23ae23SYevhen Orlov for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) { 4060a23ae23SYevhen Orlov if (!prestera_nh_neigh_key_is_valid(&nh_grp->key.neigh[nh_cnt])) 4070a23ae23SYevhen Orlov break; 4080a23ae23SYevhen Orlov 4090a23ae23SYevhen Orlov nh_neigh = prestera_nh_neigh_get(sw, 4100a23ae23SYevhen Orlov &nh_grp->key.neigh[nh_cnt]); 4110a23ae23SYevhen Orlov if (!nh_neigh) 4120a23ae23SYevhen Orlov goto err_nh_neigh_get; 4130a23ae23SYevhen Orlov 4140a23ae23SYevhen Orlov nh_grp->nh_neigh_head[nh_cnt].neigh = nh_neigh; 4150a23ae23SYevhen Orlov nh_grp->nh_neigh_head[nh_cnt].this = nh_grp; 4160a23ae23SYevhen Orlov list_add(&nh_grp->nh_neigh_head[nh_cnt].head, 4170a23ae23SYevhen Orlov &nh_neigh->nexthop_group_list); 4180a23ae23SYevhen Orlov } 4190a23ae23SYevhen Orlov 4200a23ae23SYevhen Orlov err = prestera_hw_nh_group_create(sw, nh_cnt, &nh_grp->grp_id); 4210a23ae23SYevhen Orlov if (err) 4220a23ae23SYevhen Orlov goto err_nh_group_create; 4230a23ae23SYevhen Orlov 4240a23ae23SYevhen Orlov err = prestera_nexthop_group_set(sw, nh_grp); 4250a23ae23SYevhen Orlov if (err) 4260a23ae23SYevhen Orlov goto err_nexthop_group_set; 4270a23ae23SYevhen Orlov 4280a23ae23SYevhen Orlov err = rhashtable_insert_fast(&sw->router->nexthop_group_ht, 4290a23ae23SYevhen Orlov &nh_grp->ht_node, 4300a23ae23SYevhen Orlov __prestera_nexthop_group_ht_params); 4310a23ae23SYevhen Orlov if (err) 4320a23ae23SYevhen Orlov goto err_ht_insert; 4330a23ae23SYevhen Orlov 4340a23ae23SYevhen Orlov /* reset cache for created group */ 4350a23ae23SYevhen Orlov gid = nh_grp->grp_id; 4360a23ae23SYevhen Orlov sw->router->nhgrp_hw_state_cache[gid / 8] &= ~BIT(gid % 8); 4370a23ae23SYevhen Orlov 4380a23ae23SYevhen Orlov return nh_grp; 4390a23ae23SYevhen Orlov 4400a23ae23SYevhen Orlov err_ht_insert: 4410a23ae23SYevhen Orlov err_nexthop_group_set: 4420a23ae23SYevhen Orlov prestera_hw_nh_group_delete(sw, nh_cnt, nh_grp->grp_id); 4430a23ae23SYevhen Orlov err_nh_group_create: 4440a23ae23SYevhen Orlov err_nh_neigh_get: 4450a23ae23SYevhen Orlov for (nh_cnt--; nh_cnt >= 0; nh_cnt--) { 4460a23ae23SYevhen Orlov list_del(&nh_grp->nh_neigh_head[nh_cnt].head); 4470a23ae23SYevhen Orlov prestera_nh_neigh_put(sw, nh_grp->nh_neigh_head[nh_cnt].neigh); 4480a23ae23SYevhen Orlov } 4490a23ae23SYevhen Orlov 4500a23ae23SYevhen Orlov kfree(nh_grp); 4510a23ae23SYevhen Orlov err_kzalloc: 4520a23ae23SYevhen Orlov return NULL; 4530a23ae23SYevhen Orlov } 4540a23ae23SYevhen Orlov 4550a23ae23SYevhen Orlov static void 4560a23ae23SYevhen Orlov __prestera_nexthop_group_destroy(struct prestera_switch *sw, 4570a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 4580a23ae23SYevhen Orlov { 4590a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh; 4600a23ae23SYevhen Orlov int nh_cnt; 4610a23ae23SYevhen Orlov 4620a23ae23SYevhen Orlov rhashtable_remove_fast(&sw->router->nexthop_group_ht, 4630a23ae23SYevhen Orlov &nh_grp->ht_node, 4640a23ae23SYevhen Orlov __prestera_nexthop_group_ht_params); 4650a23ae23SYevhen Orlov 4660a23ae23SYevhen Orlov for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) { 4670a23ae23SYevhen Orlov nh_neigh = nh_grp->nh_neigh_head[nh_cnt].neigh; 4680a23ae23SYevhen Orlov if (!nh_neigh) 4690a23ae23SYevhen Orlov break; 4700a23ae23SYevhen Orlov 4710a23ae23SYevhen Orlov list_del(&nh_grp->nh_neigh_head[nh_cnt].head); 4720a23ae23SYevhen Orlov prestera_nh_neigh_put(sw, nh_neigh); 4730a23ae23SYevhen Orlov } 4740a23ae23SYevhen Orlov 4750a23ae23SYevhen Orlov prestera_hw_nh_group_delete(sw, nh_cnt, nh_grp->grp_id); 4760a23ae23SYevhen Orlov kfree(nh_grp); 4770a23ae23SYevhen Orlov } 4780a23ae23SYevhen Orlov 4790a23ae23SYevhen Orlov static struct prestera_nexthop_group * 4800a23ae23SYevhen Orlov __prestera_nexthop_group_find(struct prestera_switch *sw, 4810a23ae23SYevhen Orlov struct prestera_nexthop_group_key *key) 4820a23ae23SYevhen Orlov { 4830a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 4840a23ae23SYevhen Orlov 4850a23ae23SYevhen Orlov nh_grp = rhashtable_lookup_fast(&sw->router->nexthop_group_ht, 4860a23ae23SYevhen Orlov key, __prestera_nexthop_group_ht_params); 4870a23ae23SYevhen Orlov return IS_ERR(nh_grp) ? NULL : nh_grp; 4880a23ae23SYevhen Orlov } 4890a23ae23SYevhen Orlov 4900a23ae23SYevhen Orlov static struct prestera_nexthop_group * 4910a23ae23SYevhen Orlov prestera_nexthop_group_get(struct prestera_switch *sw, 4920a23ae23SYevhen Orlov struct prestera_nexthop_group_key *key) 4930a23ae23SYevhen Orlov { 4940a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 4950a23ae23SYevhen Orlov 4960a23ae23SYevhen Orlov nh_grp = __prestera_nexthop_group_find(sw, key); 4970a23ae23SYevhen Orlov if (nh_grp) { 4980a23ae23SYevhen Orlov refcount_inc(&nh_grp->refcount); 4990a23ae23SYevhen Orlov } else { 5000a23ae23SYevhen Orlov nh_grp = __prestera_nexthop_group_create(sw, key); 501*30e9672aSDan Carpenter if (!nh_grp) 502*30e9672aSDan Carpenter return ERR_PTR(-ENOMEM); 5030a23ae23SYevhen Orlov 5040a23ae23SYevhen Orlov refcount_set(&nh_grp->refcount, 1); 5050a23ae23SYevhen Orlov } 5060a23ae23SYevhen Orlov 5070a23ae23SYevhen Orlov return nh_grp; 5080a23ae23SYevhen Orlov } 5090a23ae23SYevhen Orlov 5100a23ae23SYevhen Orlov static void prestera_nexthop_group_put(struct prestera_switch *sw, 5110a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 5120a23ae23SYevhen Orlov { 5130a23ae23SYevhen Orlov if (refcount_dec_and_test(&nh_grp->refcount)) 5140a23ae23SYevhen Orlov __prestera_nexthop_group_destroy(sw, nh_grp); 5150a23ae23SYevhen Orlov } 5160a23ae23SYevhen Orlov 5170a23ae23SYevhen Orlov /* Updates with new nh_neigh's info */ 5180a23ae23SYevhen Orlov static int prestera_nexthop_group_set(struct prestera_switch *sw, 5190a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 5200a23ae23SYevhen Orlov { 5210a23ae23SYevhen Orlov struct prestera_neigh_info info[PRESTERA_NHGR_SIZE_MAX]; 5220a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh; 5230a23ae23SYevhen Orlov int nh_cnt; 5240a23ae23SYevhen Orlov 5250a23ae23SYevhen Orlov memset(&info[0], 0, sizeof(info)); 5260a23ae23SYevhen Orlov for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) { 5270a23ae23SYevhen Orlov neigh = nh_grp->nh_neigh_head[nh_cnt].neigh; 5280a23ae23SYevhen Orlov if (!neigh) 5290a23ae23SYevhen Orlov break; 5300a23ae23SYevhen Orlov 5310a23ae23SYevhen Orlov memcpy(&info[nh_cnt], &neigh->info, sizeof(neigh->info)); 5320a23ae23SYevhen Orlov } 5330a23ae23SYevhen Orlov 5340a23ae23SYevhen Orlov return prestera_hw_nh_entries_set(sw, nh_cnt, &info[0], nh_grp->grp_id); 5350a23ae23SYevhen Orlov } 5360a23ae23SYevhen Orlov 5370a23ae23SYevhen Orlov static bool 5380a23ae23SYevhen Orlov prestera_nexthop_group_util_hw_state(struct prestera_switch *sw, 5390a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 5400a23ae23SYevhen Orlov { 5410a23ae23SYevhen Orlov int err; 5420a23ae23SYevhen Orlov u32 buf_size = sw->size_tbl_router_nexthop / 8 + 1; 5430a23ae23SYevhen Orlov u32 gid = nh_grp->grp_id; 5440a23ae23SYevhen Orlov u8 *cache = sw->router->nhgrp_hw_state_cache; 5450a23ae23SYevhen Orlov 5460a23ae23SYevhen Orlov /* Antijitter 5470a23ae23SYevhen Orlov * Prevent situation, when we read state of nh_grp twice in short time, 5480a23ae23SYevhen Orlov * and state bit is still cleared on second call. So just stuck active 5490a23ae23SYevhen Orlov * state for PRESTERA_NH_ACTIVE_JIFFER_FILTER, after last occurred. 5500a23ae23SYevhen Orlov */ 5510a23ae23SYevhen Orlov if (!time_before(jiffies, sw->router->nhgrp_hw_cache_kick + 5520a23ae23SYevhen Orlov msecs_to_jiffies(PRESTERA_NH_ACTIVE_JIFFER_FILTER))) { 5530a23ae23SYevhen Orlov err = prestera_hw_nhgrp_blk_get(sw, cache, buf_size); 5540a23ae23SYevhen Orlov if (err) { 5550a23ae23SYevhen Orlov pr_err("Failed to get hw state nh_grp's"); 5560a23ae23SYevhen Orlov return false; 5570a23ae23SYevhen Orlov } 5580a23ae23SYevhen Orlov 5590a23ae23SYevhen Orlov sw->router->nhgrp_hw_cache_kick = jiffies; 5600a23ae23SYevhen Orlov } 5610a23ae23SYevhen Orlov 5620a23ae23SYevhen Orlov if (cache[gid / 8] & BIT(gid % 8)) 5630a23ae23SYevhen Orlov return true; 5640a23ae23SYevhen Orlov 5650a23ae23SYevhen Orlov return false; 5660a23ae23SYevhen Orlov } 5670a23ae23SYevhen Orlov 56816de3db1SYevhen Orlov struct prestera_fib_node * 56916de3db1SYevhen Orlov prestera_fib_node_find(struct prestera_switch *sw, struct prestera_fib_key *key) 57016de3db1SYevhen Orlov { 57116de3db1SYevhen Orlov struct prestera_fib_node *fib_node; 57216de3db1SYevhen Orlov 57316de3db1SYevhen Orlov fib_node = rhashtable_lookup_fast(&sw->router->fib_ht, key, 57416de3db1SYevhen Orlov __prestera_fib_ht_params); 575d434ee9dSYang Yingliang return fib_node; 57616de3db1SYevhen Orlov } 57716de3db1SYevhen Orlov 57816de3db1SYevhen Orlov static void __prestera_fib_node_destruct(struct prestera_switch *sw, 57916de3db1SYevhen Orlov struct prestera_fib_node *fib_node) 58016de3db1SYevhen Orlov { 58116de3db1SYevhen Orlov struct prestera_vr *vr; 58216de3db1SYevhen Orlov 58316de3db1SYevhen Orlov vr = fib_node->info.vr; 58416de3db1SYevhen Orlov prestera_hw_lpm_del(sw, vr->hw_vr_id, fib_node->key.addr.u.ipv4, 58516de3db1SYevhen Orlov fib_node->key.prefix_len); 58616de3db1SYevhen Orlov switch (fib_node->info.type) { 5870a23ae23SYevhen Orlov case PRESTERA_FIB_TYPE_UC_NH: 5880a23ae23SYevhen Orlov prestera_nexthop_group_put(sw, fib_node->info.nh_grp); 5890a23ae23SYevhen Orlov break; 59016de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_TRAP: 59116de3db1SYevhen Orlov break; 59216de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_DROP: 59316de3db1SYevhen Orlov break; 59416de3db1SYevhen Orlov default: 59516de3db1SYevhen Orlov pr_err("Unknown fib_node->info.type = %d", 59616de3db1SYevhen Orlov fib_node->info.type); 59716de3db1SYevhen Orlov } 59816de3db1SYevhen Orlov 59916de3db1SYevhen Orlov prestera_vr_put(sw, vr); 60016de3db1SYevhen Orlov } 60116de3db1SYevhen Orlov 60216de3db1SYevhen Orlov void prestera_fib_node_destroy(struct prestera_switch *sw, 60316de3db1SYevhen Orlov struct prestera_fib_node *fib_node) 60416de3db1SYevhen Orlov { 60516de3db1SYevhen Orlov __prestera_fib_node_destruct(sw, fib_node); 60616de3db1SYevhen Orlov rhashtable_remove_fast(&sw->router->fib_ht, &fib_node->ht_node, 60716de3db1SYevhen Orlov __prestera_fib_ht_params); 60816de3db1SYevhen Orlov kfree(fib_node); 60916de3db1SYevhen Orlov } 61016de3db1SYevhen Orlov 6111e7313e8SYevhen Orlov static void prestera_fib_node_destroy_ht_cb(void *ptr, void *arg) 6121e7313e8SYevhen Orlov { 6131e7313e8SYevhen Orlov struct prestera_fib_node *node = ptr; 6141e7313e8SYevhen Orlov struct prestera_switch *sw = arg; 6151e7313e8SYevhen Orlov 6161e7313e8SYevhen Orlov __prestera_fib_node_destruct(sw, node); 6171e7313e8SYevhen Orlov kfree(node); 6181e7313e8SYevhen Orlov } 6191e7313e8SYevhen Orlov 62016de3db1SYevhen Orlov struct prestera_fib_node * 62116de3db1SYevhen Orlov prestera_fib_node_create(struct prestera_switch *sw, 62216de3db1SYevhen Orlov struct prestera_fib_key *key, 6230a23ae23SYevhen Orlov enum prestera_fib_type fib_type, 6240a23ae23SYevhen Orlov struct prestera_nexthop_group_key *nh_grp_key) 62516de3db1SYevhen Orlov { 62616de3db1SYevhen Orlov struct prestera_fib_node *fib_node; 62716de3db1SYevhen Orlov u32 grp_id; 62816de3db1SYevhen Orlov struct prestera_vr *vr; 62916de3db1SYevhen Orlov int err; 63016de3db1SYevhen Orlov 63116de3db1SYevhen Orlov fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL); 63216de3db1SYevhen Orlov if (!fib_node) 63316de3db1SYevhen Orlov goto err_kzalloc; 63416de3db1SYevhen Orlov 63516de3db1SYevhen Orlov memcpy(&fib_node->key, key, sizeof(*key)); 63616de3db1SYevhen Orlov fib_node->info.type = fib_type; 63716de3db1SYevhen Orlov 63816de3db1SYevhen Orlov vr = prestera_vr_get(sw, key->tb_id, NULL); 63916de3db1SYevhen Orlov if (IS_ERR(vr)) 64016de3db1SYevhen Orlov goto err_vr_get; 64116de3db1SYevhen Orlov 64216de3db1SYevhen Orlov fib_node->info.vr = vr; 64316de3db1SYevhen Orlov 64416de3db1SYevhen Orlov switch (fib_type) { 64516de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_TRAP: 64616de3db1SYevhen Orlov grp_id = PRESTERA_NHGR_UNUSED; 64716de3db1SYevhen Orlov break; 64816de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_DROP: 64916de3db1SYevhen Orlov grp_id = PRESTERA_NHGR_DROP; 65016de3db1SYevhen Orlov break; 6510a23ae23SYevhen Orlov case PRESTERA_FIB_TYPE_UC_NH: 6520a23ae23SYevhen Orlov fib_node->info.nh_grp = prestera_nexthop_group_get(sw, 6530a23ae23SYevhen Orlov nh_grp_key); 654*30e9672aSDan Carpenter if (IS_ERR(fib_node->info.nh_grp)) 6550a23ae23SYevhen Orlov goto err_nh_grp_get; 6560a23ae23SYevhen Orlov 6570a23ae23SYevhen Orlov grp_id = fib_node->info.nh_grp->grp_id; 6580a23ae23SYevhen Orlov break; 65916de3db1SYevhen Orlov default: 66016de3db1SYevhen Orlov pr_err("Unsupported fib_type %d", fib_type); 66116de3db1SYevhen Orlov goto err_nh_grp_get; 66216de3db1SYevhen Orlov } 66316de3db1SYevhen Orlov 66416de3db1SYevhen Orlov err = prestera_hw_lpm_add(sw, vr->hw_vr_id, key->addr.u.ipv4, 66516de3db1SYevhen Orlov key->prefix_len, grp_id); 66616de3db1SYevhen Orlov if (err) 66716de3db1SYevhen Orlov goto err_lpm_add; 66816de3db1SYevhen Orlov 66916de3db1SYevhen Orlov err = rhashtable_insert_fast(&sw->router->fib_ht, &fib_node->ht_node, 67016de3db1SYevhen Orlov __prestera_fib_ht_params); 67116de3db1SYevhen Orlov if (err) 67216de3db1SYevhen Orlov goto err_ht_insert; 67316de3db1SYevhen Orlov 67416de3db1SYevhen Orlov return fib_node; 67516de3db1SYevhen Orlov 67616de3db1SYevhen Orlov err_ht_insert: 67716de3db1SYevhen Orlov prestera_hw_lpm_del(sw, vr->hw_vr_id, key->addr.u.ipv4, 67816de3db1SYevhen Orlov key->prefix_len); 67916de3db1SYevhen Orlov err_lpm_add: 6800a23ae23SYevhen Orlov if (fib_type == PRESTERA_FIB_TYPE_UC_NH) 6810a23ae23SYevhen Orlov prestera_nexthop_group_put(sw, fib_node->info.nh_grp); 68216de3db1SYevhen Orlov err_nh_grp_get: 68316de3db1SYevhen Orlov prestera_vr_put(sw, vr); 68416de3db1SYevhen Orlov err_vr_get: 68516de3db1SYevhen Orlov kfree(fib_node); 68616de3db1SYevhen Orlov err_kzalloc: 68716de3db1SYevhen Orlov return NULL; 68816de3db1SYevhen Orlov } 689