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 */
prestera_nh_neigh_key_is_valid(struct prestera_nh_neigh_key * key)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 
prestera_router_hw_init(struct prestera_switch * sw)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 
prestera_router_hw_fini(struct prestera_switch * sw)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 
__prestera_vr_find(struct prestera_switch * sw,u32 tb_id)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 
__prestera_vr_create(struct prestera_switch * sw,u32 tb_id,struct netlink_ext_ack * extack)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 
__prestera_vr_destroy(struct prestera_switch * sw,struct prestera_vr * vr)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 
prestera_vr_get(struct prestera_switch * sw,u32 tb_id,struct netlink_ext_ack * extack)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 
prestera_vr_put(struct prestera_switch * sw,struct prestera_vr * vr)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
__prestera_rif_entry_key_copy(const struct prestera_rif_entry_key * in,struct prestera_rif_entry_key * out)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 *
prestera_rif_entry_find(const struct prestera_switch * sw,const struct prestera_rif_entry_key * k)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 
prestera_rif_entry_destroy(struct prestera_switch * sw,struct prestera_rif_entry * e)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 *
prestera_rif_entry_create(struct prestera_switch * sw,struct prestera_rif_entry_key * k,u32 tb_id,const unsigned char * addr)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 
__prestera_nh_neigh_destroy(struct prestera_switch * sw,struct prestera_nh_neigh * neigh)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 *
__prestera_nh_neigh_create(struct prestera_switch * sw,struct prestera_nh_neigh_key * key)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 *
prestera_nh_neigh_find(struct prestera_switch * sw,struct prestera_nh_neigh_key * key)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);
333*e493bec3SShang XiaoJing 	return nh_neigh;
3340a23ae23SYevhen Orlov }
3350a23ae23SYevhen Orlov 
3360a23ae23SYevhen Orlov struct prestera_nh_neigh *
prestera_nh_neigh_get(struct prestera_switch * sw,struct prestera_nh_neigh_key * key)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 
prestera_nh_neigh_put(struct prestera_switch * sw,struct prestera_nh_neigh * neigh)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 */
prestera_nh_neigh_set(struct prestera_switch * sw,struct prestera_nh_neigh * neigh)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 
prestera_nh_neigh_util_hw_state(struct prestera_switch * sw,struct prestera_nh_neigh * nh_neigh)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 *
__prestera_nexthop_group_create(struct prestera_switch * sw,struct prestera_nexthop_group_key * key)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
__prestera_nexthop_group_destroy(struct prestera_switch * sw,struct prestera_nexthop_group * nh_grp)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 *
__prestera_nexthop_group_find(struct prestera_switch * sw,struct prestera_nexthop_group_key * key)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);
487*e493bec3SShang XiaoJing 	return nh_grp;
4880a23ae23SYevhen Orlov }
4890a23ae23SYevhen Orlov 
4900a23ae23SYevhen Orlov static struct prestera_nexthop_group *
prestera_nexthop_group_get(struct prestera_switch * sw,struct prestera_nexthop_group_key * key)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);
50130e9672aSDan Carpenter 		if (!nh_grp)
50230e9672aSDan 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 
prestera_nexthop_group_put(struct prestera_switch * sw,struct prestera_nexthop_group * nh_grp)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 */
prestera_nexthop_group_set(struct prestera_switch * sw,struct prestera_nexthop_group * nh_grp)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
prestera_nexthop_group_util_hw_state(struct prestera_switch * sw,struct prestera_nexthop_group * nh_grp)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 *
prestera_fib_node_find(struct prestera_switch * sw,struct prestera_fib_key * key)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 
__prestera_fib_node_destruct(struct prestera_switch * sw,struct prestera_fib_node * fib_node)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 
prestera_fib_node_destroy(struct prestera_switch * sw,struct prestera_fib_node * fib_node)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 
prestera_fib_node_destroy_ht_cb(void * ptr,void * arg)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 *
prestera_fib_node_create(struct prestera_switch * sw,struct prestera_fib_key * key,enum prestera_fib_type fib_type,struct prestera_nexthop_group_key * nh_grp_key)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);
65430e9672aSDan 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