1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */
3
4#include <linux/rhashtable.h>
5
6#include "prestera.h"
7#include "prestera_hw.h"
8#include "prestera_router_hw.h"
9#include "prestera_acl.h"
10
11/*                                Nexthop is pointed
12 *                                to port (not rif)
13 *                                +-------+
14 *                              +>|nexthop|
15 *                              | +-------+
16 *                              |
17 *            +--+        +-----++
18 *   +------->|vr|<-+   +>|nh_grp|
19 *   |        +--+  |   | +------+
20 *   |              |   |
21 * +-+-------+   +--+---+-+
22 * |rif_entry|   |fib_node|
23 * +---------+   +--------+
24 *  Rif is        Fib - is exit point
25 *  used as
26 *  entry point
27 *  for vr in hw
28 */
29
30#define PRESTERA_NHGR_UNUSED (0)
31#define PRESTERA_NHGR_DROP (0xFFFFFFFF)
32/* Need to merge it with router_manager */
33#define PRESTERA_NH_ACTIVE_JIFFER_FILTER 3000 /* ms */
34
35static const struct rhashtable_params __prestera_fib_ht_params = {
36	.key_offset  = offsetof(struct prestera_fib_node, key),
37	.head_offset = offsetof(struct prestera_fib_node, ht_node),
38	.key_len     = sizeof(struct prestera_fib_key),
39	.automatic_shrinking = true,
40};
41
42static const struct rhashtable_params __prestera_nh_neigh_ht_params = {
43	.key_offset  = offsetof(struct prestera_nh_neigh, key),
44	.key_len     = sizeof(struct prestera_nh_neigh_key),
45	.head_offset = offsetof(struct prestera_nh_neigh, ht_node),
46};
47
48static const struct rhashtable_params __prestera_nexthop_group_ht_params = {
49	.key_offset  = offsetof(struct prestera_nexthop_group, key),
50	.key_len     = sizeof(struct prestera_nexthop_group_key),
51	.head_offset = offsetof(struct prestera_nexthop_group, ht_node),
52};
53
54static int prestera_nexthop_group_set(struct prestera_switch *sw,
55				      struct prestera_nexthop_group *nh_grp);
56static bool
57prestera_nexthop_group_util_hw_state(struct prestera_switch *sw,
58				     struct prestera_nexthop_group *nh_grp);
59static void prestera_fib_node_destroy_ht_cb(void *ptr, void *arg);
60
61/* TODO: move to router.h as macros */
62static bool prestera_nh_neigh_key_is_valid(struct prestera_nh_neigh_key *key)
63{
64	return memchr_inv(key, 0, sizeof(*key)) ? true : false;
65}
66
67int prestera_router_hw_init(struct prestera_switch *sw)
68{
69	int err;
70
71	err = rhashtable_init(&sw->router->nh_neigh_ht,
72			      &__prestera_nh_neigh_ht_params);
73	if (err)
74		goto err_nh_neigh_ht_init;
75
76	err = rhashtable_init(&sw->router->nexthop_group_ht,
77			      &__prestera_nexthop_group_ht_params);
78	if (err)
79		goto err_nexthop_grp_ht_init;
80
81	err = rhashtable_init(&sw->router->fib_ht,
82			      &__prestera_fib_ht_params);
83	if (err)
84		goto err_fib_ht_init;
85
86	INIT_LIST_HEAD(&sw->router->vr_list);
87	INIT_LIST_HEAD(&sw->router->rif_entry_list);
88
89	return 0;
90
91err_fib_ht_init:
92	rhashtable_destroy(&sw->router->nexthop_group_ht);
93err_nexthop_grp_ht_init:
94	rhashtable_destroy(&sw->router->nh_neigh_ht);
95err_nh_neigh_ht_init:
96	return 0;
97}
98
99void prestera_router_hw_fini(struct prestera_switch *sw)
100{
101	rhashtable_free_and_destroy(&sw->router->fib_ht,
102				    prestera_fib_node_destroy_ht_cb, sw);
103	WARN_ON(!list_empty(&sw->router->vr_list));
104	WARN_ON(!list_empty(&sw->router->rif_entry_list));
105	rhashtable_destroy(&sw->router->fib_ht);
106	rhashtable_destroy(&sw->router->nexthop_group_ht);
107	rhashtable_destroy(&sw->router->nh_neigh_ht);
108}
109
110static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw,
111					      u32 tb_id)
112{
113	struct prestera_vr *vr;
114
115	list_for_each_entry(vr, &sw->router->vr_list, router_node) {
116		if (vr->tb_id == tb_id)
117			return vr;
118	}
119
120	return NULL;
121}
122
123static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw,
124						u32 tb_id,
125						struct netlink_ext_ack *extack)
126{
127	struct prestera_vr *vr;
128	int err;
129
130	vr = kzalloc(sizeof(*vr), GFP_KERNEL);
131	if (!vr) {
132		err = -ENOMEM;
133		goto err_alloc_vr;
134	}
135
136	vr->tb_id = tb_id;
137
138	err = prestera_hw_vr_create(sw, &vr->hw_vr_id);
139	if (err)
140		goto err_hw_create;
141
142	list_add(&vr->router_node, &sw->router->vr_list);
143
144	return vr;
145
146err_hw_create:
147	kfree(vr);
148err_alloc_vr:
149	return ERR_PTR(err);
150}
151
152static void __prestera_vr_destroy(struct prestera_switch *sw,
153				  struct prestera_vr *vr)
154{
155	list_del(&vr->router_node);
156	prestera_hw_vr_delete(sw, vr->hw_vr_id);
157	kfree(vr);
158}
159
160static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id,
161					   struct netlink_ext_ack *extack)
162{
163	struct prestera_vr *vr;
164
165	vr = __prestera_vr_find(sw, tb_id);
166	if (vr) {
167		refcount_inc(&vr->refcount);
168	} else {
169		vr = __prestera_vr_create(sw, tb_id, extack);
170		if (IS_ERR(vr))
171			return ERR_CAST(vr);
172
173		refcount_set(&vr->refcount, 1);
174	}
175
176	return vr;
177}
178
179static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr)
180{
181	if (refcount_dec_and_test(&vr->refcount))
182		__prestera_vr_destroy(sw, vr);
183}
184
185/* iface is overhead struct. vr_id also can be removed. */
186static int
187__prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in,
188			      struct prestera_rif_entry_key *out)
189{
190	memset(out, 0, sizeof(*out));
191
192	switch (in->iface.type) {
193	case PRESTERA_IF_PORT_E:
194		out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num;
195		out->iface.dev_port.port_num = in->iface.dev_port.port_num;
196		break;
197	case PRESTERA_IF_LAG_E:
198		out->iface.lag_id = in->iface.lag_id;
199		break;
200	case PRESTERA_IF_VID_E:
201		out->iface.vlan_id = in->iface.vlan_id;
202		break;
203	default:
204		WARN(1, "Unsupported iface type");
205		return -EINVAL;
206	}
207
208	out->iface.type = in->iface.type;
209	return 0;
210}
211
212struct prestera_rif_entry *
213prestera_rif_entry_find(const struct prestera_switch *sw,
214			const struct prestera_rif_entry_key *k)
215{
216	struct prestera_rif_entry *rif_entry;
217	struct prestera_rif_entry_key lk; /* lookup key */
218
219	if (__prestera_rif_entry_key_copy(k, &lk))
220		return NULL;
221
222	list_for_each_entry(rif_entry, &sw->router->rif_entry_list,
223			    router_node) {
224		if (!memcmp(k, &rif_entry->key, sizeof(*k)))
225			return rif_entry;
226	}
227
228	return NULL;
229}
230
231void prestera_rif_entry_destroy(struct prestera_switch *sw,
232				struct prestera_rif_entry *e)
233{
234	struct prestera_iface iface;
235
236	list_del(&e->router_node);
237
238	memcpy(&iface, &e->key.iface, sizeof(iface));
239	iface.vr_id = e->vr->hw_vr_id;
240	prestera_hw_rif_delete(sw, e->hw_id, &iface);
241
242	prestera_vr_put(sw, e->vr);
243	kfree(e);
244}
245
246struct prestera_rif_entry *
247prestera_rif_entry_create(struct prestera_switch *sw,
248			  struct prestera_rif_entry_key *k,
249			  u32 tb_id, const unsigned char *addr)
250{
251	int err;
252	struct prestera_rif_entry *e;
253	struct prestera_iface iface;
254
255	e = kzalloc(sizeof(*e), GFP_KERNEL);
256	if (!e)
257		goto err_kzalloc;
258
259	if (__prestera_rif_entry_key_copy(k, &e->key))
260		goto err_key_copy;
261
262	e->vr = prestera_vr_get(sw, tb_id, NULL);
263	if (IS_ERR(e->vr))
264		goto err_vr_get;
265
266	memcpy(&e->addr, addr, sizeof(e->addr));
267
268	/* HW */
269	memcpy(&iface, &e->key.iface, sizeof(iface));
270	iface.vr_id = e->vr->hw_vr_id;
271	err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id);
272	if (err)
273		goto err_hw_create;
274
275	list_add(&e->router_node, &sw->router->rif_entry_list);
276
277	return e;
278
279err_hw_create:
280	prestera_vr_put(sw, e->vr);
281err_vr_get:
282err_key_copy:
283	kfree(e);
284err_kzalloc:
285	return NULL;
286}
287
288static void __prestera_nh_neigh_destroy(struct prestera_switch *sw,
289					struct prestera_nh_neigh *neigh)
290{
291	rhashtable_remove_fast(&sw->router->nh_neigh_ht,
292			       &neigh->ht_node,
293			       __prestera_nh_neigh_ht_params);
294	kfree(neigh);
295}
296
297static struct prestera_nh_neigh *
298__prestera_nh_neigh_create(struct prestera_switch *sw,
299			   struct prestera_nh_neigh_key *key)
300{
301	struct prestera_nh_neigh *neigh;
302	int err;
303
304	neigh = kzalloc(sizeof(*neigh), GFP_KERNEL);
305	if (!neigh)
306		goto err_kzalloc;
307
308	memcpy(&neigh->key, key, sizeof(*key));
309	neigh->info.connected = false;
310	INIT_LIST_HEAD(&neigh->nexthop_group_list);
311	err = rhashtable_insert_fast(&sw->router->nh_neigh_ht,
312				     &neigh->ht_node,
313				     __prestera_nh_neigh_ht_params);
314	if (err)
315		goto err_rhashtable_insert;
316
317	return neigh;
318
319err_rhashtable_insert:
320	kfree(neigh);
321err_kzalloc:
322	return NULL;
323}
324
325struct prestera_nh_neigh *
326prestera_nh_neigh_find(struct prestera_switch *sw,
327		       struct prestera_nh_neigh_key *key)
328{
329	struct prestera_nh_neigh *nh_neigh;
330
331	nh_neigh = rhashtable_lookup_fast(&sw->router->nh_neigh_ht,
332					  key, __prestera_nh_neigh_ht_params);
333	return nh_neigh;
334}
335
336struct prestera_nh_neigh *
337prestera_nh_neigh_get(struct prestera_switch *sw,
338		      struct prestera_nh_neigh_key *key)
339{
340	struct prestera_nh_neigh *neigh;
341
342	neigh = prestera_nh_neigh_find(sw, key);
343	if (!neigh)
344		return __prestera_nh_neigh_create(sw, key);
345
346	return neigh;
347}
348
349void prestera_nh_neigh_put(struct prestera_switch *sw,
350			   struct prestera_nh_neigh *neigh)
351{
352	if (list_empty(&neigh->nexthop_group_list))
353		__prestera_nh_neigh_destroy(sw, neigh);
354}
355
356/* Updates new prestera_neigh_info */
357int prestera_nh_neigh_set(struct prestera_switch *sw,
358			  struct prestera_nh_neigh *neigh)
359{
360	struct prestera_nh_neigh_head *nh_head;
361	struct prestera_nexthop_group *nh_grp;
362	int err;
363
364	list_for_each_entry(nh_head, &neigh->nexthop_group_list, head) {
365		nh_grp = nh_head->this;
366		err = prestera_nexthop_group_set(sw, nh_grp);
367		if (err)
368			return err;
369	}
370
371	return 0;
372}
373
374bool prestera_nh_neigh_util_hw_state(struct prestera_switch *sw,
375				     struct prestera_nh_neigh *nh_neigh)
376{
377	bool state;
378	struct prestera_nh_neigh_head *nh_head, *tmp;
379
380	state = false;
381	list_for_each_entry_safe(nh_head, tmp,
382				 &nh_neigh->nexthop_group_list, head) {
383		state = prestera_nexthop_group_util_hw_state(sw, nh_head->this);
384		if (state)
385			goto out;
386	}
387
388out:
389	return state;
390}
391
392static struct prestera_nexthop_group *
393__prestera_nexthop_group_create(struct prestera_switch *sw,
394				struct prestera_nexthop_group_key *key)
395{
396	struct prestera_nexthop_group *nh_grp;
397	struct prestera_nh_neigh *nh_neigh;
398	int nh_cnt, err, gid;
399
400	nh_grp = kzalloc(sizeof(*nh_grp), GFP_KERNEL);
401	if (!nh_grp)
402		goto err_kzalloc;
403
404	memcpy(&nh_grp->key, key, sizeof(*key));
405	for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) {
406		if (!prestera_nh_neigh_key_is_valid(&nh_grp->key.neigh[nh_cnt]))
407			break;
408
409		nh_neigh = prestera_nh_neigh_get(sw,
410						 &nh_grp->key.neigh[nh_cnt]);
411		if (!nh_neigh)
412			goto err_nh_neigh_get;
413
414		nh_grp->nh_neigh_head[nh_cnt].neigh = nh_neigh;
415		nh_grp->nh_neigh_head[nh_cnt].this = nh_grp;
416		list_add(&nh_grp->nh_neigh_head[nh_cnt].head,
417			 &nh_neigh->nexthop_group_list);
418	}
419
420	err = prestera_hw_nh_group_create(sw, nh_cnt, &nh_grp->grp_id);
421	if (err)
422		goto err_nh_group_create;
423
424	err = prestera_nexthop_group_set(sw, nh_grp);
425	if (err)
426		goto err_nexthop_group_set;
427
428	err = rhashtable_insert_fast(&sw->router->nexthop_group_ht,
429				     &nh_grp->ht_node,
430				     __prestera_nexthop_group_ht_params);
431	if (err)
432		goto err_ht_insert;
433
434	/* reset cache for created group */
435	gid = nh_grp->grp_id;
436	sw->router->nhgrp_hw_state_cache[gid / 8] &= ~BIT(gid % 8);
437
438	return nh_grp;
439
440err_ht_insert:
441err_nexthop_group_set:
442	prestera_hw_nh_group_delete(sw, nh_cnt, nh_grp->grp_id);
443err_nh_group_create:
444err_nh_neigh_get:
445	for (nh_cnt--; nh_cnt >= 0; nh_cnt--) {
446		list_del(&nh_grp->nh_neigh_head[nh_cnt].head);
447		prestera_nh_neigh_put(sw, nh_grp->nh_neigh_head[nh_cnt].neigh);
448	}
449
450	kfree(nh_grp);
451err_kzalloc:
452	return NULL;
453}
454
455static void
456__prestera_nexthop_group_destroy(struct prestera_switch *sw,
457				 struct prestera_nexthop_group *nh_grp)
458{
459	struct prestera_nh_neigh *nh_neigh;
460	int nh_cnt;
461
462	rhashtable_remove_fast(&sw->router->nexthop_group_ht,
463			       &nh_grp->ht_node,
464			       __prestera_nexthop_group_ht_params);
465
466	for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) {
467		nh_neigh = nh_grp->nh_neigh_head[nh_cnt].neigh;
468		if (!nh_neigh)
469			break;
470
471		list_del(&nh_grp->nh_neigh_head[nh_cnt].head);
472		prestera_nh_neigh_put(sw, nh_neigh);
473	}
474
475	prestera_hw_nh_group_delete(sw, nh_cnt, nh_grp->grp_id);
476	kfree(nh_grp);
477}
478
479static struct prestera_nexthop_group *
480__prestera_nexthop_group_find(struct prestera_switch *sw,
481			      struct prestera_nexthop_group_key *key)
482{
483	struct prestera_nexthop_group *nh_grp;
484
485	nh_grp = rhashtable_lookup_fast(&sw->router->nexthop_group_ht,
486					key, __prestera_nexthop_group_ht_params);
487	return nh_grp;
488}
489
490static struct prestera_nexthop_group *
491prestera_nexthop_group_get(struct prestera_switch *sw,
492			   struct prestera_nexthop_group_key *key)
493{
494	struct prestera_nexthop_group *nh_grp;
495
496	nh_grp = __prestera_nexthop_group_find(sw, key);
497	if (nh_grp) {
498		refcount_inc(&nh_grp->refcount);
499	} else {
500		nh_grp = __prestera_nexthop_group_create(sw, key);
501		if (!nh_grp)
502			return ERR_PTR(-ENOMEM);
503
504		refcount_set(&nh_grp->refcount, 1);
505	}
506
507	return nh_grp;
508}
509
510static void prestera_nexthop_group_put(struct prestera_switch *sw,
511				       struct prestera_nexthop_group *nh_grp)
512{
513	if (refcount_dec_and_test(&nh_grp->refcount))
514		__prestera_nexthop_group_destroy(sw, nh_grp);
515}
516
517/* Updates with new nh_neigh's info */
518static int prestera_nexthop_group_set(struct prestera_switch *sw,
519				      struct prestera_nexthop_group *nh_grp)
520{
521	struct prestera_neigh_info info[PRESTERA_NHGR_SIZE_MAX];
522	struct prestera_nh_neigh *neigh;
523	int nh_cnt;
524
525	memset(&info[0], 0, sizeof(info));
526	for (nh_cnt = 0; nh_cnt < PRESTERA_NHGR_SIZE_MAX; nh_cnt++) {
527		neigh = nh_grp->nh_neigh_head[nh_cnt].neigh;
528		if (!neigh)
529			break;
530
531		memcpy(&info[nh_cnt], &neigh->info, sizeof(neigh->info));
532	}
533
534	return prestera_hw_nh_entries_set(sw, nh_cnt, &info[0], nh_grp->grp_id);
535}
536
537static bool
538prestera_nexthop_group_util_hw_state(struct prestera_switch *sw,
539				     struct prestera_nexthop_group *nh_grp)
540{
541	int err;
542	u32 buf_size = sw->size_tbl_router_nexthop / 8 + 1;
543	u32 gid = nh_grp->grp_id;
544	u8 *cache = sw->router->nhgrp_hw_state_cache;
545
546	/* Antijitter
547	 * Prevent situation, when we read state of nh_grp twice in short time,
548	 * and state bit is still cleared on second call. So just stuck active
549	 * state for PRESTERA_NH_ACTIVE_JIFFER_FILTER, after last occurred.
550	 */
551	if (!time_before(jiffies, sw->router->nhgrp_hw_cache_kick +
552			msecs_to_jiffies(PRESTERA_NH_ACTIVE_JIFFER_FILTER))) {
553		err = prestera_hw_nhgrp_blk_get(sw, cache, buf_size);
554		if (err) {
555			pr_err("Failed to get hw state nh_grp's");
556			return false;
557		}
558
559		sw->router->nhgrp_hw_cache_kick = jiffies;
560	}
561
562	if (cache[gid / 8] & BIT(gid % 8))
563		return true;
564
565	return false;
566}
567
568struct prestera_fib_node *
569prestera_fib_node_find(struct prestera_switch *sw, struct prestera_fib_key *key)
570{
571	struct prestera_fib_node *fib_node;
572
573	fib_node = rhashtable_lookup_fast(&sw->router->fib_ht, key,
574					  __prestera_fib_ht_params);
575	return fib_node;
576}
577
578static void __prestera_fib_node_destruct(struct prestera_switch *sw,
579					 struct prestera_fib_node *fib_node)
580{
581	struct prestera_vr *vr;
582
583	vr = fib_node->info.vr;
584	prestera_hw_lpm_del(sw, vr->hw_vr_id, fib_node->key.addr.u.ipv4,
585			    fib_node->key.prefix_len);
586	switch (fib_node->info.type) {
587	case PRESTERA_FIB_TYPE_UC_NH:
588		prestera_nexthop_group_put(sw, fib_node->info.nh_grp);
589		break;
590	case PRESTERA_FIB_TYPE_TRAP:
591		break;
592	case PRESTERA_FIB_TYPE_DROP:
593		break;
594	default:
595	      pr_err("Unknown fib_node->info.type = %d",
596		     fib_node->info.type);
597	}
598
599	prestera_vr_put(sw, vr);
600}
601
602void prestera_fib_node_destroy(struct prestera_switch *sw,
603			       struct prestera_fib_node *fib_node)
604{
605	__prestera_fib_node_destruct(sw, fib_node);
606	rhashtable_remove_fast(&sw->router->fib_ht, &fib_node->ht_node,
607			       __prestera_fib_ht_params);
608	kfree(fib_node);
609}
610
611static void prestera_fib_node_destroy_ht_cb(void *ptr, void *arg)
612{
613	struct prestera_fib_node *node = ptr;
614	struct prestera_switch *sw = arg;
615
616	__prestera_fib_node_destruct(sw, node);
617	kfree(node);
618}
619
620struct prestera_fib_node *
621prestera_fib_node_create(struct prestera_switch *sw,
622			 struct prestera_fib_key *key,
623			 enum prestera_fib_type fib_type,
624			 struct prestera_nexthop_group_key *nh_grp_key)
625{
626	struct prestera_fib_node *fib_node;
627	u32 grp_id;
628	struct prestera_vr *vr;
629	int err;
630
631	fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL);
632	if (!fib_node)
633		goto err_kzalloc;
634
635	memcpy(&fib_node->key, key, sizeof(*key));
636	fib_node->info.type = fib_type;
637
638	vr = prestera_vr_get(sw, key->tb_id, NULL);
639	if (IS_ERR(vr))
640		goto err_vr_get;
641
642	fib_node->info.vr = vr;
643
644	switch (fib_type) {
645	case PRESTERA_FIB_TYPE_TRAP:
646		grp_id = PRESTERA_NHGR_UNUSED;
647		break;
648	case PRESTERA_FIB_TYPE_DROP:
649		grp_id = PRESTERA_NHGR_DROP;
650		break;
651	case PRESTERA_FIB_TYPE_UC_NH:
652		fib_node->info.nh_grp = prestera_nexthop_group_get(sw,
653								   nh_grp_key);
654		if (IS_ERR(fib_node->info.nh_grp))
655			goto err_nh_grp_get;
656
657		grp_id = fib_node->info.nh_grp->grp_id;
658		break;
659	default:
660		pr_err("Unsupported fib_type %d", fib_type);
661		goto err_nh_grp_get;
662	}
663
664	err = prestera_hw_lpm_add(sw, vr->hw_vr_id, key->addr.u.ipv4,
665				  key->prefix_len, grp_id);
666	if (err)
667		goto err_lpm_add;
668
669	err = rhashtable_insert_fast(&sw->router->fib_ht, &fib_node->ht_node,
670				     __prestera_fib_ht_params);
671	if (err)
672		goto err_ht_insert;
673
674	return fib_node;
675
676err_ht_insert:
677	prestera_hw_lpm_del(sw, vr->hw_vr_id, key->addr.u.ipv4,
678			    key->prefix_len);
679err_lpm_add:
680	if (fib_type == PRESTERA_FIB_TYPE_UC_NH)
681		prestera_nexthop_group_put(sw, fib_node->info.nh_grp);
682err_nh_grp_get:
683	prestera_vr_put(sw, vr);
684err_vr_get:
685	kfree(fib_node);
686err_kzalloc:
687	return NULL;
688}
689