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 11*0a23ae23SYevhen Orlov /* Nexthop is pointed 12*0a23ae23SYevhen Orlov * to port (not rif) 13*0a23ae23SYevhen Orlov * +-------+ 14*0a23ae23SYevhen Orlov * +>|nexthop| 15*0a23ae23SYevhen Orlov * | +-------+ 16*0a23ae23SYevhen Orlov * | 17*0a23ae23SYevhen Orlov * +--+ +-----++ 18*0a23ae23SYevhen Orlov * +------->|vr|<-+ +>|nh_grp| 19*0a23ae23SYevhen Orlov * | +--+ | | +------+ 20*0a23ae23SYevhen 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) 32*0a23ae23SYevhen Orlov /* Need to merge it with router_manager */ 33*0a23ae23SYevhen 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 42*0a23ae23SYevhen Orlov static const struct rhashtable_params __prestera_nh_neigh_ht_params = { 43*0a23ae23SYevhen Orlov .key_offset = offsetof(struct prestera_nh_neigh, key), 44*0a23ae23SYevhen Orlov .key_len = sizeof(struct prestera_nh_neigh_key), 45*0a23ae23SYevhen Orlov .head_offset = offsetof(struct prestera_nh_neigh, ht_node), 46*0a23ae23SYevhen Orlov }; 47*0a23ae23SYevhen Orlov 48*0a23ae23SYevhen Orlov static const struct rhashtable_params __prestera_nexthop_group_ht_params = { 49*0a23ae23SYevhen Orlov .key_offset = offsetof(struct prestera_nexthop_group, key), 50*0a23ae23SYevhen Orlov .key_len = sizeof(struct prestera_nexthop_group_key), 51*0a23ae23SYevhen Orlov .head_offset = offsetof(struct prestera_nexthop_group, ht_node), 52*0a23ae23SYevhen Orlov }; 53*0a23ae23SYevhen Orlov 54*0a23ae23SYevhen Orlov static int prestera_nexthop_group_set(struct prestera_switch *sw, 55*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp); 56*0a23ae23SYevhen Orlov static bool 57*0a23ae23SYevhen Orlov prestera_nexthop_group_util_hw_state(struct prestera_switch *sw, 58*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp); 59*0a23ae23SYevhen Orlov 60*0a23ae23SYevhen Orlov /* TODO: move to router.h as macros */ 61*0a23ae23SYevhen Orlov static bool prestera_nh_neigh_key_is_valid(struct prestera_nh_neigh_key *key) 62*0a23ae23SYevhen Orlov { 63*0a23ae23SYevhen Orlov return memchr_inv(key, 0, sizeof(*key)) ? true : false; 64*0a23ae23SYevhen Orlov } 65*0a23ae23SYevhen Orlov 66bca5859bSYevhen Orlov int prestera_router_hw_init(struct prestera_switch *sw) 67bca5859bSYevhen Orlov { 6816de3db1SYevhen Orlov int err; 6916de3db1SYevhen Orlov 70*0a23ae23SYevhen Orlov err = rhashtable_init(&sw->router->nh_neigh_ht, 71*0a23ae23SYevhen Orlov &__prestera_nh_neigh_ht_params); 72*0a23ae23SYevhen Orlov if (err) 73*0a23ae23SYevhen Orlov goto err_nh_neigh_ht_init; 74*0a23ae23SYevhen Orlov 75*0a23ae23SYevhen Orlov err = rhashtable_init(&sw->router->nexthop_group_ht, 76*0a23ae23SYevhen Orlov &__prestera_nexthop_group_ht_params); 77*0a23ae23SYevhen Orlov if (err) 78*0a23ae23SYevhen Orlov goto err_nexthop_grp_ht_init; 79*0a23ae23SYevhen Orlov 8016de3db1SYevhen Orlov err = rhashtable_init(&sw->router->fib_ht, 8116de3db1SYevhen Orlov &__prestera_fib_ht_params); 8216de3db1SYevhen Orlov if (err) 8316de3db1SYevhen Orlov goto err_fib_ht_init; 8416de3db1SYevhen Orlov 85bca5859bSYevhen Orlov INIT_LIST_HEAD(&sw->router->vr_list); 86bca5859bSYevhen Orlov INIT_LIST_HEAD(&sw->router->rif_entry_list); 87bca5859bSYevhen Orlov 88*0a23ae23SYevhen Orlov return 0; 89*0a23ae23SYevhen Orlov 9016de3db1SYevhen Orlov err_fib_ht_init: 91*0a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nexthop_group_ht); 92*0a23ae23SYevhen Orlov err_nexthop_grp_ht_init: 93*0a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nh_neigh_ht); 94*0a23ae23SYevhen Orlov err_nh_neigh_ht_init: 95bca5859bSYevhen Orlov return 0; 96bca5859bSYevhen Orlov } 97bca5859bSYevhen Orlov 98e179f045SYevhen Orlov void prestera_router_hw_fini(struct prestera_switch *sw) 99e179f045SYevhen Orlov { 100e179f045SYevhen Orlov WARN_ON(!list_empty(&sw->router->vr_list)); 101e179f045SYevhen Orlov WARN_ON(!list_empty(&sw->router->rif_entry_list)); 10216de3db1SYevhen Orlov rhashtable_destroy(&sw->router->fib_ht); 103*0a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nexthop_group_ht); 104*0a23ae23SYevhen Orlov rhashtable_destroy(&sw->router->nh_neigh_ht); 105e179f045SYevhen Orlov } 106e179f045SYevhen Orlov 107bca5859bSYevhen Orlov static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw, 108bca5859bSYevhen Orlov u32 tb_id) 109bca5859bSYevhen Orlov { 110bca5859bSYevhen Orlov struct prestera_vr *vr; 111bca5859bSYevhen Orlov 112bca5859bSYevhen Orlov list_for_each_entry(vr, &sw->router->vr_list, router_node) { 113bca5859bSYevhen Orlov if (vr->tb_id == tb_id) 114bca5859bSYevhen Orlov return vr; 115bca5859bSYevhen Orlov } 116bca5859bSYevhen Orlov 117bca5859bSYevhen Orlov return NULL; 118bca5859bSYevhen Orlov } 119bca5859bSYevhen Orlov 120bca5859bSYevhen Orlov static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw, 121bca5859bSYevhen Orlov u32 tb_id, 122bca5859bSYevhen Orlov struct netlink_ext_ack *extack) 123bca5859bSYevhen Orlov { 124bca5859bSYevhen Orlov struct prestera_vr *vr; 125bca5859bSYevhen Orlov int err; 126bca5859bSYevhen Orlov 127bca5859bSYevhen Orlov vr = kzalloc(sizeof(*vr), GFP_KERNEL); 128bca5859bSYevhen Orlov if (!vr) { 129bca5859bSYevhen Orlov err = -ENOMEM; 130bca5859bSYevhen Orlov goto err_alloc_vr; 131bca5859bSYevhen Orlov } 132bca5859bSYevhen Orlov 133bca5859bSYevhen Orlov vr->tb_id = tb_id; 1346a1ba875SYevhen Orlov 1356a1ba875SYevhen Orlov err = prestera_hw_vr_create(sw, &vr->hw_vr_id); 1366a1ba875SYevhen Orlov if (err) 1376a1ba875SYevhen Orlov goto err_hw_create; 138bca5859bSYevhen Orlov 139bca5859bSYevhen Orlov list_add(&vr->router_node, &sw->router->vr_list); 140bca5859bSYevhen Orlov 141bca5859bSYevhen Orlov return vr; 142bca5859bSYevhen Orlov 1436a1ba875SYevhen Orlov err_hw_create: 144bca5859bSYevhen Orlov kfree(vr); 1456a1ba875SYevhen Orlov err_alloc_vr: 146bca5859bSYevhen Orlov return ERR_PTR(err); 147bca5859bSYevhen Orlov } 148bca5859bSYevhen Orlov 149bca5859bSYevhen Orlov static void __prestera_vr_destroy(struct prestera_switch *sw, 150bca5859bSYevhen Orlov struct prestera_vr *vr) 151bca5859bSYevhen Orlov { 152bca5859bSYevhen Orlov list_del(&vr->router_node); 1536a1ba875SYevhen Orlov prestera_hw_vr_delete(sw, vr->hw_vr_id); 154bca5859bSYevhen Orlov kfree(vr); 155bca5859bSYevhen Orlov } 156bca5859bSYevhen Orlov 157bca5859bSYevhen Orlov static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id, 158bca5859bSYevhen Orlov struct netlink_ext_ack *extack) 159bca5859bSYevhen Orlov { 160bca5859bSYevhen Orlov struct prestera_vr *vr; 161bca5859bSYevhen Orlov 162bca5859bSYevhen Orlov vr = __prestera_vr_find(sw, tb_id); 1636a1ba875SYevhen Orlov if (vr) { 1646a1ba875SYevhen Orlov refcount_inc(&vr->refcount); 1656a1ba875SYevhen Orlov } else { 166bca5859bSYevhen Orlov vr = __prestera_vr_create(sw, tb_id, extack); 167bca5859bSYevhen Orlov if (IS_ERR(vr)) 168bca5859bSYevhen Orlov return ERR_CAST(vr); 169bca5859bSYevhen Orlov 1706a1ba875SYevhen Orlov refcount_set(&vr->refcount, 1); 1716a1ba875SYevhen Orlov } 1726a1ba875SYevhen Orlov 173bca5859bSYevhen Orlov return vr; 174bca5859bSYevhen Orlov } 175bca5859bSYevhen Orlov 176bca5859bSYevhen Orlov static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr) 177bca5859bSYevhen Orlov { 1786a1ba875SYevhen Orlov if (refcount_dec_and_test(&vr->refcount)) 179bca5859bSYevhen Orlov __prestera_vr_destroy(sw, vr); 180bca5859bSYevhen Orlov } 181bca5859bSYevhen Orlov 182bca5859bSYevhen Orlov /* iface is overhead struct. vr_id also can be removed. */ 183bca5859bSYevhen Orlov static int 184bca5859bSYevhen Orlov __prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in, 185bca5859bSYevhen Orlov struct prestera_rif_entry_key *out) 186bca5859bSYevhen Orlov { 187bca5859bSYevhen Orlov memset(out, 0, sizeof(*out)); 188bca5859bSYevhen Orlov 189bca5859bSYevhen Orlov switch (in->iface.type) { 190bca5859bSYevhen Orlov case PRESTERA_IF_PORT_E: 191bca5859bSYevhen Orlov out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num; 192bca5859bSYevhen Orlov out->iface.dev_port.port_num = in->iface.dev_port.port_num; 193bca5859bSYevhen Orlov break; 194bca5859bSYevhen Orlov case PRESTERA_IF_LAG_E: 195bca5859bSYevhen Orlov out->iface.lag_id = in->iface.lag_id; 196bca5859bSYevhen Orlov break; 197bca5859bSYevhen Orlov case PRESTERA_IF_VID_E: 198bca5859bSYevhen Orlov out->iface.vlan_id = in->iface.vlan_id; 199bca5859bSYevhen Orlov break; 200bca5859bSYevhen Orlov default: 20132d098bbSYevhen Orlov WARN(1, "Unsupported iface type"); 202bca5859bSYevhen Orlov return -EINVAL; 203bca5859bSYevhen Orlov } 204bca5859bSYevhen Orlov 205bca5859bSYevhen Orlov out->iface.type = in->iface.type; 206bca5859bSYevhen Orlov return 0; 207bca5859bSYevhen Orlov } 208bca5859bSYevhen Orlov 209bca5859bSYevhen Orlov struct prestera_rif_entry * 210bca5859bSYevhen Orlov prestera_rif_entry_find(const struct prestera_switch *sw, 211bca5859bSYevhen Orlov const struct prestera_rif_entry_key *k) 212bca5859bSYevhen Orlov { 213bca5859bSYevhen Orlov struct prestera_rif_entry *rif_entry; 214bca5859bSYevhen Orlov struct prestera_rif_entry_key lk; /* lookup key */ 215bca5859bSYevhen Orlov 216bca5859bSYevhen Orlov if (__prestera_rif_entry_key_copy(k, &lk)) 217bca5859bSYevhen Orlov return NULL; 218bca5859bSYevhen Orlov 219bca5859bSYevhen Orlov list_for_each_entry(rif_entry, &sw->router->rif_entry_list, 220bca5859bSYevhen Orlov router_node) { 221bca5859bSYevhen Orlov if (!memcmp(k, &rif_entry->key, sizeof(*k))) 222bca5859bSYevhen Orlov return rif_entry; 223bca5859bSYevhen Orlov } 224bca5859bSYevhen Orlov 225bca5859bSYevhen Orlov return NULL; 226bca5859bSYevhen Orlov } 227bca5859bSYevhen Orlov 228bca5859bSYevhen Orlov void prestera_rif_entry_destroy(struct prestera_switch *sw, 229bca5859bSYevhen Orlov struct prestera_rif_entry *e) 230bca5859bSYevhen Orlov { 231bca5859bSYevhen Orlov struct prestera_iface iface; 232bca5859bSYevhen Orlov 233bca5859bSYevhen Orlov list_del(&e->router_node); 234bca5859bSYevhen Orlov 235bca5859bSYevhen Orlov memcpy(&iface, &e->key.iface, sizeof(iface)); 236bca5859bSYevhen Orlov iface.vr_id = e->vr->hw_vr_id; 237bca5859bSYevhen Orlov prestera_hw_rif_delete(sw, e->hw_id, &iface); 238bca5859bSYevhen Orlov 239bca5859bSYevhen Orlov prestera_vr_put(sw, e->vr); 240bca5859bSYevhen Orlov kfree(e); 241bca5859bSYevhen Orlov } 242bca5859bSYevhen Orlov 243bca5859bSYevhen Orlov struct prestera_rif_entry * 244bca5859bSYevhen Orlov prestera_rif_entry_create(struct prestera_switch *sw, 245bca5859bSYevhen Orlov struct prestera_rif_entry_key *k, 246bca5859bSYevhen Orlov u32 tb_id, const unsigned char *addr) 247bca5859bSYevhen Orlov { 248bca5859bSYevhen Orlov int err; 249bca5859bSYevhen Orlov struct prestera_rif_entry *e; 250bca5859bSYevhen Orlov struct prestera_iface iface; 251bca5859bSYevhen Orlov 252bca5859bSYevhen Orlov e = kzalloc(sizeof(*e), GFP_KERNEL); 253bca5859bSYevhen Orlov if (!e) 254bca5859bSYevhen Orlov goto err_kzalloc; 255bca5859bSYevhen Orlov 256bca5859bSYevhen Orlov if (__prestera_rif_entry_key_copy(k, &e->key)) 257bca5859bSYevhen Orlov goto err_key_copy; 258bca5859bSYevhen Orlov 259bca5859bSYevhen Orlov e->vr = prestera_vr_get(sw, tb_id, NULL); 260bca5859bSYevhen Orlov if (IS_ERR(e->vr)) 261bca5859bSYevhen Orlov goto err_vr_get; 262bca5859bSYevhen Orlov 263bca5859bSYevhen Orlov memcpy(&e->addr, addr, sizeof(e->addr)); 264bca5859bSYevhen Orlov 265bca5859bSYevhen Orlov /* HW */ 266bca5859bSYevhen Orlov memcpy(&iface, &e->key.iface, sizeof(iface)); 267bca5859bSYevhen Orlov iface.vr_id = e->vr->hw_vr_id; 268bca5859bSYevhen Orlov err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id); 269bca5859bSYevhen Orlov if (err) 270bca5859bSYevhen Orlov goto err_hw_create; 271bca5859bSYevhen Orlov 272bca5859bSYevhen Orlov list_add(&e->router_node, &sw->router->rif_entry_list); 273bca5859bSYevhen Orlov 274bca5859bSYevhen Orlov return e; 275bca5859bSYevhen Orlov 276bca5859bSYevhen Orlov err_hw_create: 277bca5859bSYevhen Orlov prestera_vr_put(sw, e->vr); 278bca5859bSYevhen Orlov err_vr_get: 279bca5859bSYevhen Orlov err_key_copy: 280bca5859bSYevhen Orlov kfree(e); 281bca5859bSYevhen Orlov err_kzalloc: 282bca5859bSYevhen Orlov return NULL; 283bca5859bSYevhen Orlov } 28416de3db1SYevhen Orlov 285*0a23ae23SYevhen Orlov static void __prestera_nh_neigh_destroy(struct prestera_switch *sw, 286*0a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh) 287*0a23ae23SYevhen Orlov { 288*0a23ae23SYevhen Orlov rhashtable_remove_fast(&sw->router->nh_neigh_ht, 289*0a23ae23SYevhen Orlov &neigh->ht_node, 290*0a23ae23SYevhen Orlov __prestera_nh_neigh_ht_params); 291*0a23ae23SYevhen Orlov kfree(neigh); 292*0a23ae23SYevhen Orlov } 293*0a23ae23SYevhen Orlov 294*0a23ae23SYevhen Orlov static struct prestera_nh_neigh * 295*0a23ae23SYevhen Orlov __prestera_nh_neigh_create(struct prestera_switch *sw, 296*0a23ae23SYevhen Orlov struct prestera_nh_neigh_key *key) 297*0a23ae23SYevhen Orlov { 298*0a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh; 299*0a23ae23SYevhen Orlov int err; 300*0a23ae23SYevhen Orlov 301*0a23ae23SYevhen Orlov neigh = kzalloc(sizeof(*neigh), GFP_KERNEL); 302*0a23ae23SYevhen Orlov if (!neigh) 303*0a23ae23SYevhen Orlov goto err_kzalloc; 304*0a23ae23SYevhen Orlov 305*0a23ae23SYevhen Orlov memcpy(&neigh->key, key, sizeof(*key)); 306*0a23ae23SYevhen Orlov neigh->info.connected = false; 307*0a23ae23SYevhen Orlov INIT_LIST_HEAD(&neigh->nexthop_group_list); 308*0a23ae23SYevhen Orlov err = rhashtable_insert_fast(&sw->router->nh_neigh_ht, 309*0a23ae23SYevhen Orlov &neigh->ht_node, 310*0a23ae23SYevhen Orlov __prestera_nh_neigh_ht_params); 311*0a23ae23SYevhen Orlov if (err) 312*0a23ae23SYevhen Orlov goto err_rhashtable_insert; 313*0a23ae23SYevhen Orlov 314*0a23ae23SYevhen Orlov return neigh; 315*0a23ae23SYevhen Orlov 316*0a23ae23SYevhen Orlov err_rhashtable_insert: 317*0a23ae23SYevhen Orlov kfree(neigh); 318*0a23ae23SYevhen Orlov err_kzalloc: 319*0a23ae23SYevhen Orlov return NULL; 320*0a23ae23SYevhen Orlov } 321*0a23ae23SYevhen Orlov 322*0a23ae23SYevhen Orlov struct prestera_nh_neigh * 323*0a23ae23SYevhen Orlov prestera_nh_neigh_find(struct prestera_switch *sw, 324*0a23ae23SYevhen Orlov struct prestera_nh_neigh_key *key) 325*0a23ae23SYevhen Orlov { 326*0a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh; 327*0a23ae23SYevhen Orlov 328*0a23ae23SYevhen Orlov nh_neigh = rhashtable_lookup_fast(&sw->router->nh_neigh_ht, 329*0a23ae23SYevhen Orlov key, __prestera_nh_neigh_ht_params); 330*0a23ae23SYevhen Orlov return IS_ERR(nh_neigh) ? NULL : nh_neigh; 331*0a23ae23SYevhen Orlov } 332*0a23ae23SYevhen Orlov 333*0a23ae23SYevhen Orlov struct prestera_nh_neigh * 334*0a23ae23SYevhen Orlov prestera_nh_neigh_get(struct prestera_switch *sw, 335*0a23ae23SYevhen Orlov struct prestera_nh_neigh_key *key) 336*0a23ae23SYevhen Orlov { 337*0a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh; 338*0a23ae23SYevhen Orlov 339*0a23ae23SYevhen Orlov neigh = prestera_nh_neigh_find(sw, key); 340*0a23ae23SYevhen Orlov if (!neigh) 341*0a23ae23SYevhen Orlov return __prestera_nh_neigh_create(sw, key); 342*0a23ae23SYevhen Orlov 343*0a23ae23SYevhen Orlov return neigh; 344*0a23ae23SYevhen Orlov } 345*0a23ae23SYevhen Orlov 346*0a23ae23SYevhen Orlov void prestera_nh_neigh_put(struct prestera_switch *sw, 347*0a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh) 348*0a23ae23SYevhen Orlov { 349*0a23ae23SYevhen Orlov if (list_empty(&neigh->nexthop_group_list)) 350*0a23ae23SYevhen Orlov __prestera_nh_neigh_destroy(sw, neigh); 351*0a23ae23SYevhen Orlov } 352*0a23ae23SYevhen Orlov 353*0a23ae23SYevhen Orlov /* Updates new prestera_neigh_info */ 354*0a23ae23SYevhen Orlov int prestera_nh_neigh_set(struct prestera_switch *sw, 355*0a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh) 356*0a23ae23SYevhen Orlov { 357*0a23ae23SYevhen Orlov struct prestera_nh_neigh_head *nh_head; 358*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 359*0a23ae23SYevhen Orlov int err; 360*0a23ae23SYevhen Orlov 361*0a23ae23SYevhen Orlov list_for_each_entry(nh_head, &neigh->nexthop_group_list, head) { 362*0a23ae23SYevhen Orlov nh_grp = nh_head->this; 363*0a23ae23SYevhen Orlov err = prestera_nexthop_group_set(sw, nh_grp); 364*0a23ae23SYevhen Orlov if (err) 365*0a23ae23SYevhen Orlov return err; 366*0a23ae23SYevhen Orlov } 367*0a23ae23SYevhen Orlov 368*0a23ae23SYevhen Orlov return 0; 369*0a23ae23SYevhen Orlov } 370*0a23ae23SYevhen Orlov 371*0a23ae23SYevhen Orlov bool prestera_nh_neigh_util_hw_state(struct prestera_switch *sw, 372*0a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh) 373*0a23ae23SYevhen Orlov { 374*0a23ae23SYevhen Orlov bool state; 375*0a23ae23SYevhen Orlov struct prestera_nh_neigh_head *nh_head, *tmp; 376*0a23ae23SYevhen Orlov 377*0a23ae23SYevhen Orlov state = false; 378*0a23ae23SYevhen Orlov list_for_each_entry_safe(nh_head, tmp, 379*0a23ae23SYevhen Orlov &nh_neigh->nexthop_group_list, head) { 380*0a23ae23SYevhen Orlov state = prestera_nexthop_group_util_hw_state(sw, nh_head->this); 381*0a23ae23SYevhen Orlov if (state) 382*0a23ae23SYevhen Orlov goto out; 383*0a23ae23SYevhen Orlov } 384*0a23ae23SYevhen Orlov 385*0a23ae23SYevhen Orlov out: 386*0a23ae23SYevhen Orlov return state; 387*0a23ae23SYevhen Orlov } 388*0a23ae23SYevhen Orlov 389*0a23ae23SYevhen Orlov static struct prestera_nexthop_group * 390*0a23ae23SYevhen Orlov __prestera_nexthop_group_create(struct prestera_switch *sw, 391*0a23ae23SYevhen Orlov struct prestera_nexthop_group_key *key) 392*0a23ae23SYevhen Orlov { 393*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 394*0a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh; 395*0a23ae23SYevhen Orlov int nh_cnt, err, gid; 396*0a23ae23SYevhen Orlov 397*0a23ae23SYevhen Orlov nh_grp = kzalloc(sizeof(*nh_grp), GFP_KERNEL); 398*0a23ae23SYevhen Orlov if (!nh_grp) 399*0a23ae23SYevhen Orlov goto err_kzalloc; 400*0a23ae23SYevhen Orlov 401*0a23ae23SYevhen Orlov memcpy(&nh_grp->key, key, sizeof(*key)); 402*0a23ae23SYevhen Orlov for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) { 403*0a23ae23SYevhen Orlov if (!prestera_nh_neigh_key_is_valid(&nh_grp->key.neigh[nh_cnt])) 404*0a23ae23SYevhen Orlov break; 405*0a23ae23SYevhen Orlov 406*0a23ae23SYevhen Orlov nh_neigh = prestera_nh_neigh_get(sw, 407*0a23ae23SYevhen Orlov &nh_grp->key.neigh[nh_cnt]); 408*0a23ae23SYevhen Orlov if (!nh_neigh) 409*0a23ae23SYevhen Orlov goto err_nh_neigh_get; 410*0a23ae23SYevhen Orlov 411*0a23ae23SYevhen Orlov nh_grp->nh_neigh_head[nh_cnt].neigh = nh_neigh; 412*0a23ae23SYevhen Orlov nh_grp->nh_neigh_head[nh_cnt].this = nh_grp; 413*0a23ae23SYevhen Orlov list_add(&nh_grp->nh_neigh_head[nh_cnt].head, 414*0a23ae23SYevhen Orlov &nh_neigh->nexthop_group_list); 415*0a23ae23SYevhen Orlov } 416*0a23ae23SYevhen Orlov 417*0a23ae23SYevhen Orlov err = prestera_hw_nh_group_create(sw, nh_cnt, &nh_grp->grp_id); 418*0a23ae23SYevhen Orlov if (err) 419*0a23ae23SYevhen Orlov goto err_nh_group_create; 420*0a23ae23SYevhen Orlov 421*0a23ae23SYevhen Orlov err = prestera_nexthop_group_set(sw, nh_grp); 422*0a23ae23SYevhen Orlov if (err) 423*0a23ae23SYevhen Orlov goto err_nexthop_group_set; 424*0a23ae23SYevhen Orlov 425*0a23ae23SYevhen Orlov err = rhashtable_insert_fast(&sw->router->nexthop_group_ht, 426*0a23ae23SYevhen Orlov &nh_grp->ht_node, 427*0a23ae23SYevhen Orlov __prestera_nexthop_group_ht_params); 428*0a23ae23SYevhen Orlov if (err) 429*0a23ae23SYevhen Orlov goto err_ht_insert; 430*0a23ae23SYevhen Orlov 431*0a23ae23SYevhen Orlov /* reset cache for created group */ 432*0a23ae23SYevhen Orlov gid = nh_grp->grp_id; 433*0a23ae23SYevhen Orlov sw->router->nhgrp_hw_state_cache[gid / 8] &= ~BIT(gid % 8); 434*0a23ae23SYevhen Orlov 435*0a23ae23SYevhen Orlov return nh_grp; 436*0a23ae23SYevhen Orlov 437*0a23ae23SYevhen Orlov err_ht_insert: 438*0a23ae23SYevhen Orlov err_nexthop_group_set: 439*0a23ae23SYevhen Orlov prestera_hw_nh_group_delete(sw, nh_cnt, nh_grp->grp_id); 440*0a23ae23SYevhen Orlov err_nh_group_create: 441*0a23ae23SYevhen Orlov err_nh_neigh_get: 442*0a23ae23SYevhen Orlov for (nh_cnt--; nh_cnt >= 0; nh_cnt--) { 443*0a23ae23SYevhen Orlov list_del(&nh_grp->nh_neigh_head[nh_cnt].head); 444*0a23ae23SYevhen Orlov prestera_nh_neigh_put(sw, nh_grp->nh_neigh_head[nh_cnt].neigh); 445*0a23ae23SYevhen Orlov } 446*0a23ae23SYevhen Orlov 447*0a23ae23SYevhen Orlov kfree(nh_grp); 448*0a23ae23SYevhen Orlov err_kzalloc: 449*0a23ae23SYevhen Orlov return NULL; 450*0a23ae23SYevhen Orlov } 451*0a23ae23SYevhen Orlov 452*0a23ae23SYevhen Orlov static void 453*0a23ae23SYevhen Orlov __prestera_nexthop_group_destroy(struct prestera_switch *sw, 454*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 455*0a23ae23SYevhen Orlov { 456*0a23ae23SYevhen Orlov struct prestera_nh_neigh *nh_neigh; 457*0a23ae23SYevhen Orlov int nh_cnt; 458*0a23ae23SYevhen Orlov 459*0a23ae23SYevhen Orlov rhashtable_remove_fast(&sw->router->nexthop_group_ht, 460*0a23ae23SYevhen Orlov &nh_grp->ht_node, 461*0a23ae23SYevhen Orlov __prestera_nexthop_group_ht_params); 462*0a23ae23SYevhen Orlov 463*0a23ae23SYevhen Orlov for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) { 464*0a23ae23SYevhen Orlov nh_neigh = nh_grp->nh_neigh_head[nh_cnt].neigh; 465*0a23ae23SYevhen Orlov if (!nh_neigh) 466*0a23ae23SYevhen Orlov break; 467*0a23ae23SYevhen Orlov 468*0a23ae23SYevhen Orlov list_del(&nh_grp->nh_neigh_head[nh_cnt].head); 469*0a23ae23SYevhen Orlov prestera_nh_neigh_put(sw, nh_neigh); 470*0a23ae23SYevhen Orlov } 471*0a23ae23SYevhen Orlov 472*0a23ae23SYevhen Orlov prestera_hw_nh_group_delete(sw, nh_cnt, nh_grp->grp_id); 473*0a23ae23SYevhen Orlov kfree(nh_grp); 474*0a23ae23SYevhen Orlov } 475*0a23ae23SYevhen Orlov 476*0a23ae23SYevhen Orlov static struct prestera_nexthop_group * 477*0a23ae23SYevhen Orlov __prestera_nexthop_group_find(struct prestera_switch *sw, 478*0a23ae23SYevhen Orlov struct prestera_nexthop_group_key *key) 479*0a23ae23SYevhen Orlov { 480*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 481*0a23ae23SYevhen Orlov 482*0a23ae23SYevhen Orlov nh_grp = rhashtable_lookup_fast(&sw->router->nexthop_group_ht, 483*0a23ae23SYevhen Orlov key, __prestera_nexthop_group_ht_params); 484*0a23ae23SYevhen Orlov return IS_ERR(nh_grp) ? NULL : nh_grp; 485*0a23ae23SYevhen Orlov } 486*0a23ae23SYevhen Orlov 487*0a23ae23SYevhen Orlov static struct prestera_nexthop_group * 488*0a23ae23SYevhen Orlov prestera_nexthop_group_get(struct prestera_switch *sw, 489*0a23ae23SYevhen Orlov struct prestera_nexthop_group_key *key) 490*0a23ae23SYevhen Orlov { 491*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp; 492*0a23ae23SYevhen Orlov 493*0a23ae23SYevhen Orlov nh_grp = __prestera_nexthop_group_find(sw, key); 494*0a23ae23SYevhen Orlov if (nh_grp) { 495*0a23ae23SYevhen Orlov refcount_inc(&nh_grp->refcount); 496*0a23ae23SYevhen Orlov } else { 497*0a23ae23SYevhen Orlov nh_grp = __prestera_nexthop_group_create(sw, key); 498*0a23ae23SYevhen Orlov if (IS_ERR(nh_grp)) 499*0a23ae23SYevhen Orlov return ERR_CAST(nh_grp); 500*0a23ae23SYevhen Orlov 501*0a23ae23SYevhen Orlov refcount_set(&nh_grp->refcount, 1); 502*0a23ae23SYevhen Orlov } 503*0a23ae23SYevhen Orlov 504*0a23ae23SYevhen Orlov return nh_grp; 505*0a23ae23SYevhen Orlov } 506*0a23ae23SYevhen Orlov 507*0a23ae23SYevhen Orlov static void prestera_nexthop_group_put(struct prestera_switch *sw, 508*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 509*0a23ae23SYevhen Orlov { 510*0a23ae23SYevhen Orlov if (refcount_dec_and_test(&nh_grp->refcount)) 511*0a23ae23SYevhen Orlov __prestera_nexthop_group_destroy(sw, nh_grp); 512*0a23ae23SYevhen Orlov } 513*0a23ae23SYevhen Orlov 514*0a23ae23SYevhen Orlov /* Updates with new nh_neigh's info */ 515*0a23ae23SYevhen Orlov static int prestera_nexthop_group_set(struct prestera_switch *sw, 516*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 517*0a23ae23SYevhen Orlov { 518*0a23ae23SYevhen Orlov struct prestera_neigh_info info[PRESTERA_NHGR_SIZE_MAX]; 519*0a23ae23SYevhen Orlov struct prestera_nh_neigh *neigh; 520*0a23ae23SYevhen Orlov int nh_cnt; 521*0a23ae23SYevhen Orlov 522*0a23ae23SYevhen Orlov memset(&info[0], 0, sizeof(info)); 523*0a23ae23SYevhen Orlov for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) { 524*0a23ae23SYevhen Orlov neigh = nh_grp->nh_neigh_head[nh_cnt].neigh; 525*0a23ae23SYevhen Orlov if (!neigh) 526*0a23ae23SYevhen Orlov break; 527*0a23ae23SYevhen Orlov 528*0a23ae23SYevhen Orlov memcpy(&info[nh_cnt], &neigh->info, sizeof(neigh->info)); 529*0a23ae23SYevhen Orlov } 530*0a23ae23SYevhen Orlov 531*0a23ae23SYevhen Orlov return prestera_hw_nh_entries_set(sw, nh_cnt, &info[0], nh_grp->grp_id); 532*0a23ae23SYevhen Orlov } 533*0a23ae23SYevhen Orlov 534*0a23ae23SYevhen Orlov static bool 535*0a23ae23SYevhen Orlov prestera_nexthop_group_util_hw_state(struct prestera_switch *sw, 536*0a23ae23SYevhen Orlov struct prestera_nexthop_group *nh_grp) 537*0a23ae23SYevhen Orlov { 538*0a23ae23SYevhen Orlov int err; 539*0a23ae23SYevhen Orlov u32 buf_size = sw->size_tbl_router_nexthop / 8 + 1; 540*0a23ae23SYevhen Orlov u32 gid = nh_grp->grp_id; 541*0a23ae23SYevhen Orlov u8 *cache = sw->router->nhgrp_hw_state_cache; 542*0a23ae23SYevhen Orlov 543*0a23ae23SYevhen Orlov /* Antijitter 544*0a23ae23SYevhen Orlov * Prevent situation, when we read state of nh_grp twice in short time, 545*0a23ae23SYevhen Orlov * and state bit is still cleared on second call. So just stuck active 546*0a23ae23SYevhen Orlov * state for PRESTERA_NH_ACTIVE_JIFFER_FILTER, after last occurred. 547*0a23ae23SYevhen Orlov */ 548*0a23ae23SYevhen Orlov if (!time_before(jiffies, sw->router->nhgrp_hw_cache_kick + 549*0a23ae23SYevhen Orlov msecs_to_jiffies(PRESTERA_NH_ACTIVE_JIFFER_FILTER))) { 550*0a23ae23SYevhen Orlov err = prestera_hw_nhgrp_blk_get(sw, cache, buf_size); 551*0a23ae23SYevhen Orlov if (err) { 552*0a23ae23SYevhen Orlov pr_err("Failed to get hw state nh_grp's"); 553*0a23ae23SYevhen Orlov return false; 554*0a23ae23SYevhen Orlov } 555*0a23ae23SYevhen Orlov 556*0a23ae23SYevhen Orlov sw->router->nhgrp_hw_cache_kick = jiffies; 557*0a23ae23SYevhen Orlov } 558*0a23ae23SYevhen Orlov 559*0a23ae23SYevhen Orlov if (cache[gid / 8] & BIT(gid % 8)) 560*0a23ae23SYevhen Orlov return true; 561*0a23ae23SYevhen Orlov 562*0a23ae23SYevhen Orlov return false; 563*0a23ae23SYevhen Orlov } 564*0a23ae23SYevhen Orlov 56516de3db1SYevhen Orlov struct prestera_fib_node * 56616de3db1SYevhen Orlov prestera_fib_node_find(struct prestera_switch *sw, struct prestera_fib_key *key) 56716de3db1SYevhen Orlov { 56816de3db1SYevhen Orlov struct prestera_fib_node *fib_node; 56916de3db1SYevhen Orlov 57016de3db1SYevhen Orlov fib_node = rhashtable_lookup_fast(&sw->router->fib_ht, key, 57116de3db1SYevhen Orlov __prestera_fib_ht_params); 572d434ee9dSYang Yingliang return fib_node; 57316de3db1SYevhen Orlov } 57416de3db1SYevhen Orlov 57516de3db1SYevhen Orlov static void __prestera_fib_node_destruct(struct prestera_switch *sw, 57616de3db1SYevhen Orlov struct prestera_fib_node *fib_node) 57716de3db1SYevhen Orlov { 57816de3db1SYevhen Orlov struct prestera_vr *vr; 57916de3db1SYevhen Orlov 58016de3db1SYevhen Orlov vr = fib_node->info.vr; 58116de3db1SYevhen Orlov prestera_hw_lpm_del(sw, vr->hw_vr_id, fib_node->key.addr.u.ipv4, 58216de3db1SYevhen Orlov fib_node->key.prefix_len); 58316de3db1SYevhen Orlov switch (fib_node->info.type) { 584*0a23ae23SYevhen Orlov case PRESTERA_FIB_TYPE_UC_NH: 585*0a23ae23SYevhen Orlov prestera_nexthop_group_put(sw, fib_node->info.nh_grp); 586*0a23ae23SYevhen Orlov break; 58716de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_TRAP: 58816de3db1SYevhen Orlov break; 58916de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_DROP: 59016de3db1SYevhen Orlov break; 59116de3db1SYevhen Orlov default: 59216de3db1SYevhen Orlov pr_err("Unknown fib_node->info.type = %d", 59316de3db1SYevhen Orlov fib_node->info.type); 59416de3db1SYevhen Orlov } 59516de3db1SYevhen Orlov 59616de3db1SYevhen Orlov prestera_vr_put(sw, vr); 59716de3db1SYevhen Orlov } 59816de3db1SYevhen Orlov 59916de3db1SYevhen Orlov void prestera_fib_node_destroy(struct prestera_switch *sw, 60016de3db1SYevhen Orlov struct prestera_fib_node *fib_node) 60116de3db1SYevhen Orlov { 60216de3db1SYevhen Orlov __prestera_fib_node_destruct(sw, fib_node); 60316de3db1SYevhen Orlov rhashtable_remove_fast(&sw->router->fib_ht, &fib_node->ht_node, 60416de3db1SYevhen Orlov __prestera_fib_ht_params); 60516de3db1SYevhen Orlov kfree(fib_node); 60616de3db1SYevhen Orlov } 60716de3db1SYevhen Orlov 60816de3db1SYevhen Orlov struct prestera_fib_node * 60916de3db1SYevhen Orlov prestera_fib_node_create(struct prestera_switch *sw, 61016de3db1SYevhen Orlov struct prestera_fib_key *key, 611*0a23ae23SYevhen Orlov enum prestera_fib_type fib_type, 612*0a23ae23SYevhen Orlov struct prestera_nexthop_group_key *nh_grp_key) 61316de3db1SYevhen Orlov { 61416de3db1SYevhen Orlov struct prestera_fib_node *fib_node; 61516de3db1SYevhen Orlov u32 grp_id; 61616de3db1SYevhen Orlov struct prestera_vr *vr; 61716de3db1SYevhen Orlov int err; 61816de3db1SYevhen Orlov 61916de3db1SYevhen Orlov fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL); 62016de3db1SYevhen Orlov if (!fib_node) 62116de3db1SYevhen Orlov goto err_kzalloc; 62216de3db1SYevhen Orlov 62316de3db1SYevhen Orlov memcpy(&fib_node->key, key, sizeof(*key)); 62416de3db1SYevhen Orlov fib_node->info.type = fib_type; 62516de3db1SYevhen Orlov 62616de3db1SYevhen Orlov vr = prestera_vr_get(sw, key->tb_id, NULL); 62716de3db1SYevhen Orlov if (IS_ERR(vr)) 62816de3db1SYevhen Orlov goto err_vr_get; 62916de3db1SYevhen Orlov 63016de3db1SYevhen Orlov fib_node->info.vr = vr; 63116de3db1SYevhen Orlov 63216de3db1SYevhen Orlov switch (fib_type) { 63316de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_TRAP: 63416de3db1SYevhen Orlov grp_id = PRESTERA_NHGR_UNUSED; 63516de3db1SYevhen Orlov break; 63616de3db1SYevhen Orlov case PRESTERA_FIB_TYPE_DROP: 63716de3db1SYevhen Orlov grp_id = PRESTERA_NHGR_DROP; 63816de3db1SYevhen Orlov break; 639*0a23ae23SYevhen Orlov case PRESTERA_FIB_TYPE_UC_NH: 640*0a23ae23SYevhen Orlov fib_node->info.nh_grp = prestera_nexthop_group_get(sw, 641*0a23ae23SYevhen Orlov nh_grp_key); 642*0a23ae23SYevhen Orlov if (!fib_node->info.nh_grp) 643*0a23ae23SYevhen Orlov goto err_nh_grp_get; 644*0a23ae23SYevhen Orlov 645*0a23ae23SYevhen Orlov grp_id = fib_node->info.nh_grp->grp_id; 646*0a23ae23SYevhen Orlov break; 64716de3db1SYevhen Orlov default: 64816de3db1SYevhen Orlov pr_err("Unsupported fib_type %d", fib_type); 64916de3db1SYevhen Orlov goto err_nh_grp_get; 65016de3db1SYevhen Orlov } 65116de3db1SYevhen Orlov 65216de3db1SYevhen Orlov err = prestera_hw_lpm_add(sw, vr->hw_vr_id, key->addr.u.ipv4, 65316de3db1SYevhen Orlov key->prefix_len, grp_id); 65416de3db1SYevhen Orlov if (err) 65516de3db1SYevhen Orlov goto err_lpm_add; 65616de3db1SYevhen Orlov 65716de3db1SYevhen Orlov err = rhashtable_insert_fast(&sw->router->fib_ht, &fib_node->ht_node, 65816de3db1SYevhen Orlov __prestera_fib_ht_params); 65916de3db1SYevhen Orlov if (err) 66016de3db1SYevhen Orlov goto err_ht_insert; 66116de3db1SYevhen Orlov 66216de3db1SYevhen Orlov return fib_node; 66316de3db1SYevhen Orlov 66416de3db1SYevhen Orlov err_ht_insert: 66516de3db1SYevhen Orlov prestera_hw_lpm_del(sw, vr->hw_vr_id, key->addr.u.ipv4, 66616de3db1SYevhen Orlov key->prefix_len); 66716de3db1SYevhen Orlov err_lpm_add: 668*0a23ae23SYevhen Orlov if (fib_type == PRESTERA_FIB_TYPE_UC_NH) 669*0a23ae23SYevhen Orlov prestera_nexthop_group_put(sw, fib_node->info.nh_grp); 67016de3db1SYevhen Orlov err_nh_grp_get: 67116de3db1SYevhen Orlov prestera_vr_put(sw, vr); 67216de3db1SYevhen Orlov err_vr_get: 67316de3db1SYevhen Orlov kfree(fib_node); 67416de3db1SYevhen Orlov err_kzalloc: 67516de3db1SYevhen Orlov return NULL; 67616de3db1SYevhen Orlov } 677