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