1/*
2 * Copyright (c) 2018 Cumulus Networks. All rights reserved.
3 * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
4 *
5 * This software is licensed under the GNU General License Version 2,
6 * June 1991 as shown in the file COPYING in the top-level directory of this
7 * source tree.
8 *
9 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
10 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
11 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
13 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
14 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
15 */
16
17#include <linux/bitmap.h>
18#include <linux/in6.h>
19#include <linux/kernel.h>
20#include <linux/list.h>
21#include <linux/rhashtable.h>
22#include <linux/spinlock_types.h>
23#include <linux/types.h>
24#include <net/fib_notifier.h>
25#include <net/inet_dscp.h>
26#include <net/ip_fib.h>
27#include <net/ip6_fib.h>
28#include <net/fib_rules.h>
29#include <net/net_namespace.h>
30#include <net/nexthop.h>
31#include <linux/debugfs.h>
32
33#include "netdevsim.h"
34
35struct nsim_fib_entry {
36	u64 max;
37	atomic64_t num;
38};
39
40struct nsim_per_fib_data {
41	struct nsim_fib_entry fib;
42	struct nsim_fib_entry rules;
43};
44
45struct nsim_fib_data {
46	struct notifier_block fib_nb;
47	struct nsim_per_fib_data ipv4;
48	struct nsim_per_fib_data ipv6;
49	struct nsim_fib_entry nexthops;
50	struct rhashtable fib_rt_ht;
51	struct list_head fib_rt_list;
52	struct mutex fib_lock; /* Protects FIB HT and list */
53	struct notifier_block nexthop_nb;
54	struct rhashtable nexthop_ht;
55	struct devlink *devlink;
56	struct work_struct fib_event_work;
57	struct work_struct fib_flush_work;
58	struct list_head fib_event_queue;
59	spinlock_t fib_event_queue_lock; /* Protects fib event queue list */
60	struct mutex nh_lock; /* Protects NH HT */
61	struct dentry *ddir;
62	bool fail_route_offload;
63	bool fail_res_nexthop_group_replace;
64	bool fail_nexthop_bucket_replace;
65	bool fail_route_delete;
66};
67
68struct nsim_fib_rt_key {
69	unsigned char addr[sizeof(struct in6_addr)];
70	unsigned char prefix_len;
71	int family;
72	u32 tb_id;
73};
74
75struct nsim_fib_rt {
76	struct nsim_fib_rt_key key;
77	struct rhash_head ht_node;
78	struct list_head list;	/* Member of fib_rt_list */
79};
80
81struct nsim_fib4_rt {
82	struct nsim_fib_rt common;
83	struct fib_info *fi;
84	dscp_t dscp;
85	u8 type;
86};
87
88struct nsim_fib6_rt {
89	struct nsim_fib_rt common;
90	struct list_head nh_list;
91	unsigned int nhs;
92};
93
94struct nsim_fib6_rt_nh {
95	struct list_head list;	/* Member of nh_list */
96	struct fib6_info *rt;
97};
98
99struct nsim_fib6_event {
100	struct fib6_info **rt_arr;
101	unsigned int nrt6;
102};
103
104struct nsim_fib_event {
105	struct list_head list; /* node in fib queue */
106	union {
107		struct fib_entry_notifier_info fen_info;
108		struct nsim_fib6_event fib6_event;
109	};
110	struct nsim_fib_data *data;
111	unsigned long event;
112	int family;
113};
114
115static const struct rhashtable_params nsim_fib_rt_ht_params = {
116	.key_offset = offsetof(struct nsim_fib_rt, key),
117	.head_offset = offsetof(struct nsim_fib_rt, ht_node),
118	.key_len = sizeof(struct nsim_fib_rt_key),
119	.automatic_shrinking = true,
120};
121
122struct nsim_nexthop {
123	struct rhash_head ht_node;
124	u64 occ;
125	u32 id;
126	bool is_resilient;
127};
128
129static const struct rhashtable_params nsim_nexthop_ht_params = {
130	.key_offset = offsetof(struct nsim_nexthop, id),
131	.head_offset = offsetof(struct nsim_nexthop, ht_node),
132	.key_len = sizeof(u32),
133	.automatic_shrinking = true,
134};
135
136u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
137		     enum nsim_resource_id res_id, bool max)
138{
139	struct nsim_fib_entry *entry;
140
141	switch (res_id) {
142	case NSIM_RESOURCE_IPV4_FIB:
143		entry = &fib_data->ipv4.fib;
144		break;
145	case NSIM_RESOURCE_IPV4_FIB_RULES:
146		entry = &fib_data->ipv4.rules;
147		break;
148	case NSIM_RESOURCE_IPV6_FIB:
149		entry = &fib_data->ipv6.fib;
150		break;
151	case NSIM_RESOURCE_IPV6_FIB_RULES:
152		entry = &fib_data->ipv6.rules;
153		break;
154	case NSIM_RESOURCE_NEXTHOPS:
155		entry = &fib_data->nexthops;
156		break;
157	default:
158		return 0;
159	}
160
161	return max ? entry->max : atomic64_read(&entry->num);
162}
163
164static void nsim_fib_set_max(struct nsim_fib_data *fib_data,
165			     enum nsim_resource_id res_id, u64 val)
166{
167	struct nsim_fib_entry *entry;
168
169	switch (res_id) {
170	case NSIM_RESOURCE_IPV4_FIB:
171		entry = &fib_data->ipv4.fib;
172		break;
173	case NSIM_RESOURCE_IPV4_FIB_RULES:
174		entry = &fib_data->ipv4.rules;
175		break;
176	case NSIM_RESOURCE_IPV6_FIB:
177		entry = &fib_data->ipv6.fib;
178		break;
179	case NSIM_RESOURCE_IPV6_FIB_RULES:
180		entry = &fib_data->ipv6.rules;
181		break;
182	case NSIM_RESOURCE_NEXTHOPS:
183		entry = &fib_data->nexthops;
184		break;
185	default:
186		WARN_ON(1);
187		return;
188	}
189	entry->max = val;
190}
191
192static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add,
193				 struct netlink_ext_ack *extack)
194{
195	int err = 0;
196
197	if (add) {
198		if (!atomic64_add_unless(&entry->num, 1, entry->max)) {
199			err = -ENOSPC;
200			NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib rule entries");
201		}
202	} else {
203		atomic64_dec_if_positive(&entry->num);
204	}
205
206	return err;
207}
208
209static int nsim_fib_rule_event(struct nsim_fib_data *data,
210			       struct fib_notifier_info *info, bool add)
211{
212	struct netlink_ext_ack *extack = info->extack;
213	int err = 0;
214
215	switch (info->family) {
216	case AF_INET:
217		err = nsim_fib_rule_account(&data->ipv4.rules, add, extack);
218		break;
219	case AF_INET6:
220		err = nsim_fib_rule_account(&data->ipv6.rules, add, extack);
221		break;
222	}
223
224	return err;
225}
226
227static int nsim_fib_account(struct nsim_fib_entry *entry, bool add)
228{
229	int err = 0;
230
231	if (add) {
232		if (!atomic64_add_unless(&entry->num, 1, entry->max))
233			err = -ENOSPC;
234	} else {
235		atomic64_dec_if_positive(&entry->num);
236	}
237
238	return err;
239}
240
241static void nsim_fib_rt_init(struct nsim_fib_data *data,
242			     struct nsim_fib_rt *fib_rt, const void *addr,
243			     size_t addr_len, unsigned int prefix_len,
244			     int family, u32 tb_id)
245{
246	memcpy(fib_rt->key.addr, addr, addr_len);
247	fib_rt->key.prefix_len = prefix_len;
248	fib_rt->key.family = family;
249	fib_rt->key.tb_id = tb_id;
250	list_add(&fib_rt->list, &data->fib_rt_list);
251}
252
253static void nsim_fib_rt_fini(struct nsim_fib_rt *fib_rt)
254{
255	list_del(&fib_rt->list);
256}
257
258static struct nsim_fib_rt *nsim_fib_rt_lookup(struct rhashtable *fib_rt_ht,
259					      const void *addr, size_t addr_len,
260					      unsigned int prefix_len,
261					      int family, u32 tb_id)
262{
263	struct nsim_fib_rt_key key;
264
265	memset(&key, 0, sizeof(key));
266	memcpy(key.addr, addr, addr_len);
267	key.prefix_len = prefix_len;
268	key.family = family;
269	key.tb_id = tb_id;
270
271	return rhashtable_lookup_fast(fib_rt_ht, &key, nsim_fib_rt_ht_params);
272}
273
274static struct nsim_fib4_rt *
275nsim_fib4_rt_create(struct nsim_fib_data *data,
276		    struct fib_entry_notifier_info *fen_info)
277{
278	struct nsim_fib4_rt *fib4_rt;
279
280	fib4_rt = kzalloc(sizeof(*fib4_rt), GFP_KERNEL);
281	if (!fib4_rt)
282		return NULL;
283
284	nsim_fib_rt_init(data, &fib4_rt->common, &fen_info->dst, sizeof(u32),
285			 fen_info->dst_len, AF_INET, fen_info->tb_id);
286
287	fib4_rt->fi = fen_info->fi;
288	fib_info_hold(fib4_rt->fi);
289	fib4_rt->dscp = fen_info->dscp;
290	fib4_rt->type = fen_info->type;
291
292	return fib4_rt;
293}
294
295static void nsim_fib4_rt_destroy(struct nsim_fib4_rt *fib4_rt)
296{
297	fib_info_put(fib4_rt->fi);
298	nsim_fib_rt_fini(&fib4_rt->common);
299	kfree(fib4_rt);
300}
301
302static struct nsim_fib4_rt *
303nsim_fib4_rt_lookup(struct rhashtable *fib_rt_ht,
304		    const struct fib_entry_notifier_info *fen_info)
305{
306	struct nsim_fib_rt *fib_rt;
307
308	fib_rt = nsim_fib_rt_lookup(fib_rt_ht, &fen_info->dst, sizeof(u32),
309				    fen_info->dst_len, AF_INET,
310				    fen_info->tb_id);
311	if (!fib_rt)
312		return NULL;
313
314	return container_of(fib_rt, struct nsim_fib4_rt, common);
315}
316
317static void
318nsim_fib4_rt_offload_failed_flag_set(struct net *net,
319				     struct fib_entry_notifier_info *fen_info)
320{
321	u32 *p_dst = (u32 *)&fen_info->dst;
322	struct fib_rt_info fri;
323
324	fri.fi = fen_info->fi;
325	fri.tb_id = fen_info->tb_id;
326	fri.dst = cpu_to_be32(*p_dst);
327	fri.dst_len = fen_info->dst_len;
328	fri.dscp = fen_info->dscp;
329	fri.type = fen_info->type;
330	fri.offload = false;
331	fri.trap = false;
332	fri.offload_failed = true;
333	fib_alias_hw_flags_set(net, &fri);
334}
335
336static void nsim_fib4_rt_hw_flags_set(struct net *net,
337				      const struct nsim_fib4_rt *fib4_rt,
338				      bool trap)
339{
340	u32 *p_dst = (u32 *) fib4_rt->common.key.addr;
341	int dst_len = fib4_rt->common.key.prefix_len;
342	struct fib_rt_info fri;
343
344	fri.fi = fib4_rt->fi;
345	fri.tb_id = fib4_rt->common.key.tb_id;
346	fri.dst = cpu_to_be32(*p_dst);
347	fri.dst_len = dst_len;
348	fri.dscp = fib4_rt->dscp;
349	fri.type = fib4_rt->type;
350	fri.offload = false;
351	fri.trap = trap;
352	fri.offload_failed = false;
353	fib_alias_hw_flags_set(net, &fri);
354}
355
356static int nsim_fib4_rt_add(struct nsim_fib_data *data,
357			    struct nsim_fib4_rt *fib4_rt)
358{
359	struct net *net = devlink_net(data->devlink);
360	int err;
361
362	err = rhashtable_insert_fast(&data->fib_rt_ht,
363				     &fib4_rt->common.ht_node,
364				     nsim_fib_rt_ht_params);
365	if (err)
366		goto err_fib_dismiss;
367
368	/* Simulate hardware programming latency. */
369	msleep(1);
370	nsim_fib4_rt_hw_flags_set(net, fib4_rt, true);
371
372	return 0;
373
374err_fib_dismiss:
375	/* Drop the accounting that was increased from the notification
376	 * context when FIB_EVENT_ENTRY_REPLACE was triggered.
377	 */
378	nsim_fib_account(&data->ipv4.fib, false);
379	return err;
380}
381
382static int nsim_fib4_rt_replace(struct nsim_fib_data *data,
383				struct nsim_fib4_rt *fib4_rt,
384				struct nsim_fib4_rt *fib4_rt_old)
385{
386	struct net *net = devlink_net(data->devlink);
387	int err;
388
389	/* We are replacing a route, so need to remove the accounting which
390	 * was increased when FIB_EVENT_ENTRY_REPLACE was triggered.
391	 */
392	err = nsim_fib_account(&data->ipv4.fib, false);
393	if (err)
394		return err;
395	err = rhashtable_replace_fast(&data->fib_rt_ht,
396				      &fib4_rt_old->common.ht_node,
397				      &fib4_rt->common.ht_node,
398				      nsim_fib_rt_ht_params);
399	if (err)
400		return err;
401
402	msleep(1);
403	nsim_fib4_rt_hw_flags_set(net, fib4_rt, true);
404
405	nsim_fib4_rt_hw_flags_set(net, fib4_rt_old, false);
406	nsim_fib4_rt_destroy(fib4_rt_old);
407
408	return 0;
409}
410
411static int nsim_fib4_rt_insert(struct nsim_fib_data *data,
412			       struct fib_entry_notifier_info *fen_info)
413{
414	struct nsim_fib4_rt *fib4_rt, *fib4_rt_old;
415	int err;
416
417	if (data->fail_route_offload) {
418		/* For testing purposes, user set debugfs fail_route_offload
419		 * value to true. Simulate hardware programming latency and then
420		 * fail.
421		 */
422		msleep(1);
423		return -EINVAL;
424	}
425
426	fib4_rt = nsim_fib4_rt_create(data, fen_info);
427	if (!fib4_rt)
428		return -ENOMEM;
429
430	fib4_rt_old = nsim_fib4_rt_lookup(&data->fib_rt_ht, fen_info);
431	if (!fib4_rt_old)
432		err = nsim_fib4_rt_add(data, fib4_rt);
433	else
434		err = nsim_fib4_rt_replace(data, fib4_rt, fib4_rt_old);
435
436	if (err)
437		nsim_fib4_rt_destroy(fib4_rt);
438
439	return err;
440}
441
442static void nsim_fib4_rt_remove(struct nsim_fib_data *data,
443				const struct fib_entry_notifier_info *fen_info)
444{
445	struct nsim_fib4_rt *fib4_rt;
446
447	fib4_rt = nsim_fib4_rt_lookup(&data->fib_rt_ht, fen_info);
448	if (!fib4_rt)
449		return;
450
451	rhashtable_remove_fast(&data->fib_rt_ht, &fib4_rt->common.ht_node,
452			       nsim_fib_rt_ht_params);
453	nsim_fib4_rt_destroy(fib4_rt);
454}
455
456static int nsim_fib4_event(struct nsim_fib_data *data,
457			   struct fib_entry_notifier_info *fen_info,
458			   unsigned long event)
459{
460	int err = 0;
461
462	switch (event) {
463	case FIB_EVENT_ENTRY_REPLACE:
464		err = nsim_fib4_rt_insert(data, fen_info);
465		if (err) {
466			struct net *net = devlink_net(data->devlink);
467
468			nsim_fib4_rt_offload_failed_flag_set(net, fen_info);
469		}
470		break;
471	case FIB_EVENT_ENTRY_DEL:
472		nsim_fib4_rt_remove(data, fen_info);
473		break;
474	default:
475		break;
476	}
477
478	return err;
479}
480
481static struct nsim_fib6_rt_nh *
482nsim_fib6_rt_nh_find(const struct nsim_fib6_rt *fib6_rt,
483		     const struct fib6_info *rt)
484{
485	struct nsim_fib6_rt_nh *fib6_rt_nh;
486
487	list_for_each_entry(fib6_rt_nh, &fib6_rt->nh_list, list) {
488		if (fib6_rt_nh->rt == rt)
489			return fib6_rt_nh;
490	}
491
492	return NULL;
493}
494
495static int nsim_fib6_rt_nh_add(struct nsim_fib6_rt *fib6_rt,
496			       struct fib6_info *rt)
497{
498	struct nsim_fib6_rt_nh *fib6_rt_nh;
499
500	fib6_rt_nh = kzalloc(sizeof(*fib6_rt_nh), GFP_KERNEL);
501	if (!fib6_rt_nh)
502		return -ENOMEM;
503
504	fib6_info_hold(rt);
505	fib6_rt_nh->rt = rt;
506	list_add_tail(&fib6_rt_nh->list, &fib6_rt->nh_list);
507	fib6_rt->nhs++;
508
509	return 0;
510}
511
512#if IS_ENABLED(CONFIG_IPV6)
513static void nsim_rt6_release(struct fib6_info *rt)
514{
515	fib6_info_release(rt);
516}
517#else
518static void nsim_rt6_release(struct fib6_info *rt)
519{
520}
521#endif
522
523static void nsim_fib6_rt_nh_del(struct nsim_fib6_rt *fib6_rt,
524				const struct fib6_info *rt)
525{
526	struct nsim_fib6_rt_nh *fib6_rt_nh;
527
528	fib6_rt_nh = nsim_fib6_rt_nh_find(fib6_rt, rt);
529	if (!fib6_rt_nh)
530		return;
531
532	fib6_rt->nhs--;
533	list_del(&fib6_rt_nh->list);
534	nsim_rt6_release(fib6_rt_nh->rt);
535	kfree(fib6_rt_nh);
536}
537
538static struct nsim_fib6_rt *
539nsim_fib6_rt_create(struct nsim_fib_data *data,
540		    struct fib6_info **rt_arr, unsigned int nrt6)
541{
542	struct fib6_info *rt = rt_arr[0];
543	struct nsim_fib6_rt *fib6_rt;
544	int i = 0;
545	int err;
546
547	fib6_rt = kzalloc(sizeof(*fib6_rt), GFP_KERNEL);
548	if (!fib6_rt)
549		return ERR_PTR(-ENOMEM);
550
551	nsim_fib_rt_init(data, &fib6_rt->common, &rt->fib6_dst.addr,
552			 sizeof(rt->fib6_dst.addr), rt->fib6_dst.plen, AF_INET6,
553			 rt->fib6_table->tb6_id);
554
555	/* We consider a multipath IPv6 route as one entry, but it can be made
556	 * up from several fib6_info structs (one for each nexthop), so we
557	 * add them all to the same list under the entry.
558	 */
559	INIT_LIST_HEAD(&fib6_rt->nh_list);
560
561	for (i = 0; i < nrt6; i++) {
562		err = nsim_fib6_rt_nh_add(fib6_rt, rt_arr[i]);
563		if (err)
564			goto err_fib6_rt_nh_del;
565	}
566
567	return fib6_rt;
568
569err_fib6_rt_nh_del:
570	for (i--; i >= 0; i--) {
571		nsim_fib6_rt_nh_del(fib6_rt, rt_arr[i]);
572	}
573	nsim_fib_rt_fini(&fib6_rt->common);
574	kfree(fib6_rt);
575	return ERR_PTR(err);
576}
577
578static void nsim_fib6_rt_destroy(struct nsim_fib6_rt *fib6_rt)
579{
580	struct nsim_fib6_rt_nh *iter, *tmp;
581
582	list_for_each_entry_safe(iter, tmp, &fib6_rt->nh_list, list)
583		nsim_fib6_rt_nh_del(fib6_rt, iter->rt);
584	WARN_ON_ONCE(!list_empty(&fib6_rt->nh_list));
585	nsim_fib_rt_fini(&fib6_rt->common);
586	kfree(fib6_rt);
587}
588
589static struct nsim_fib6_rt *
590nsim_fib6_rt_lookup(struct rhashtable *fib_rt_ht, const struct fib6_info *rt)
591{
592	struct nsim_fib_rt *fib_rt;
593
594	fib_rt = nsim_fib_rt_lookup(fib_rt_ht, &rt->fib6_dst.addr,
595				    sizeof(rt->fib6_dst.addr),
596				    rt->fib6_dst.plen, AF_INET6,
597				    rt->fib6_table->tb6_id);
598	if (!fib_rt)
599		return NULL;
600
601	return container_of(fib_rt, struct nsim_fib6_rt, common);
602}
603
604static int nsim_fib6_rt_append(struct nsim_fib_data *data,
605			       struct nsim_fib6_event *fib6_event)
606{
607	struct fib6_info *rt = fib6_event->rt_arr[0];
608	struct nsim_fib6_rt *fib6_rt;
609	int i, err;
610
611	if (data->fail_route_offload) {
612		/* For testing purposes, user set debugfs fail_route_offload
613		 * value to true. Simulate hardware programming latency and then
614		 * fail.
615		 */
616		msleep(1);
617		return -EINVAL;
618	}
619
620	fib6_rt = nsim_fib6_rt_lookup(&data->fib_rt_ht, rt);
621	if (!fib6_rt)
622		return -EINVAL;
623
624	for (i = 0; i < fib6_event->nrt6; i++) {
625		err = nsim_fib6_rt_nh_add(fib6_rt, fib6_event->rt_arr[i]);
626		if (err)
627			goto err_fib6_rt_nh_del;
628
629		WRITE_ONCE(fib6_event->rt_arr[i]->trap, true);
630	}
631
632	return 0;
633
634err_fib6_rt_nh_del:
635	for (i--; i >= 0; i--) {
636		WRITE_ONCE(fib6_event->rt_arr[i]->trap, false);
637		nsim_fib6_rt_nh_del(fib6_rt, fib6_event->rt_arr[i]);
638	}
639	return err;
640}
641
642#if IS_ENABLED(CONFIG_IPV6)
643static void nsim_fib6_rt_offload_failed_flag_set(struct nsim_fib_data *data,
644						 struct fib6_info **rt_arr,
645						 unsigned int nrt6)
646
647{
648	struct net *net = devlink_net(data->devlink);
649	int i;
650
651	for (i = 0; i < nrt6; i++)
652		fib6_info_hw_flags_set(net, rt_arr[i], false, false, true);
653}
654#else
655static void nsim_fib6_rt_offload_failed_flag_set(struct nsim_fib_data *data,
656						 struct fib6_info **rt_arr,
657						 unsigned int nrt6)
658{
659}
660#endif
661
662#if IS_ENABLED(CONFIG_IPV6)
663static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data,
664				      const struct nsim_fib6_rt *fib6_rt,
665				      bool trap)
666{
667	struct net *net = devlink_net(data->devlink);
668	struct nsim_fib6_rt_nh *fib6_rt_nh;
669
670	list_for_each_entry(fib6_rt_nh, &fib6_rt->nh_list, list)
671		fib6_info_hw_flags_set(net, fib6_rt_nh->rt, false, trap, false);
672}
673#else
674static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data,
675				      const struct nsim_fib6_rt *fib6_rt,
676				      bool trap)
677{
678}
679#endif
680
681static int nsim_fib6_rt_add(struct nsim_fib_data *data,
682			    struct nsim_fib6_rt *fib6_rt)
683{
684	int err;
685
686	err = rhashtable_insert_fast(&data->fib_rt_ht,
687				     &fib6_rt->common.ht_node,
688				     nsim_fib_rt_ht_params);
689
690	if (err)
691		goto err_fib_dismiss;
692
693	msleep(1);
694	nsim_fib6_rt_hw_flags_set(data, fib6_rt, true);
695
696	return 0;
697
698err_fib_dismiss:
699	/* Drop the accounting that was increased from the notification
700	 * context when FIB_EVENT_ENTRY_REPLACE was triggered.
701	 */
702	nsim_fib_account(&data->ipv6.fib, false);
703	return err;
704}
705
706static int nsim_fib6_rt_replace(struct nsim_fib_data *data,
707				struct nsim_fib6_rt *fib6_rt,
708				struct nsim_fib6_rt *fib6_rt_old)
709{
710	int err;
711
712	/* We are replacing a route, so need to remove the accounting which
713	 * was increased when FIB_EVENT_ENTRY_REPLACE was triggered.
714	 */
715	err = nsim_fib_account(&data->ipv6.fib, false);
716	if (err)
717		return err;
718
719	err = rhashtable_replace_fast(&data->fib_rt_ht,
720				      &fib6_rt_old->common.ht_node,
721				      &fib6_rt->common.ht_node,
722				      nsim_fib_rt_ht_params);
723
724	if (err)
725		return err;
726
727	msleep(1);
728	nsim_fib6_rt_hw_flags_set(data, fib6_rt, true);
729
730	nsim_fib6_rt_hw_flags_set(data, fib6_rt_old, false);
731	nsim_fib6_rt_destroy(fib6_rt_old);
732
733	return 0;
734}
735
736static int nsim_fib6_rt_insert(struct nsim_fib_data *data,
737			       struct nsim_fib6_event *fib6_event)
738{
739	struct fib6_info *rt = fib6_event->rt_arr[0];
740	struct nsim_fib6_rt *fib6_rt, *fib6_rt_old;
741	int err;
742
743	if (data->fail_route_offload) {
744		/* For testing purposes, user set debugfs fail_route_offload
745		 * value to true. Simulate hardware programming latency and then
746		 * fail.
747		 */
748		msleep(1);
749		return -EINVAL;
750	}
751
752	fib6_rt = nsim_fib6_rt_create(data, fib6_event->rt_arr,
753				      fib6_event->nrt6);
754	if (IS_ERR(fib6_rt))
755		return PTR_ERR(fib6_rt);
756
757	fib6_rt_old = nsim_fib6_rt_lookup(&data->fib_rt_ht, rt);
758	if (!fib6_rt_old)
759		err = nsim_fib6_rt_add(data, fib6_rt);
760	else
761		err = nsim_fib6_rt_replace(data, fib6_rt, fib6_rt_old);
762
763	if (err)
764		nsim_fib6_rt_destroy(fib6_rt);
765
766	return err;
767}
768
769static void nsim_fib6_rt_remove(struct nsim_fib_data *data,
770				struct nsim_fib6_event *fib6_event)
771{
772	struct fib6_info *rt = fib6_event->rt_arr[0];
773	struct nsim_fib6_rt *fib6_rt;
774	int i;
775
776	/* Multipath routes are first added to the FIB trie and only then
777	 * notified. If we vetoed the addition, we will get a delete
778	 * notification for a route we do not have. Therefore, do not warn if
779	 * route was not found.
780	 */
781	fib6_rt = nsim_fib6_rt_lookup(&data->fib_rt_ht, rt);
782	if (!fib6_rt)
783		return;
784
785	/* If not all the nexthops are deleted, then only reduce the nexthop
786	 * group.
787	 */
788	if (fib6_event->nrt6 != fib6_rt->nhs) {
789		for (i = 0; i < fib6_event->nrt6; i++)
790			nsim_fib6_rt_nh_del(fib6_rt, fib6_event->rt_arr[i]);
791		return;
792	}
793
794	rhashtable_remove_fast(&data->fib_rt_ht, &fib6_rt->common.ht_node,
795			       nsim_fib_rt_ht_params);
796	nsim_fib6_rt_destroy(fib6_rt);
797}
798
799static int nsim_fib6_event_init(struct nsim_fib6_event *fib6_event,
800				struct fib6_entry_notifier_info *fen6_info)
801{
802	struct fib6_info *rt = fen6_info->rt;
803	struct fib6_info **rt_arr;
804	struct fib6_info *iter;
805	unsigned int nrt6;
806	int i = 0;
807
808	nrt6 = fen6_info->nsiblings + 1;
809
810	rt_arr = kcalloc(nrt6, sizeof(struct fib6_info *), GFP_ATOMIC);
811	if (!rt_arr)
812		return -ENOMEM;
813
814	fib6_event->rt_arr = rt_arr;
815	fib6_event->nrt6 = nrt6;
816
817	rt_arr[0] = rt;
818	fib6_info_hold(rt);
819
820	if (!fen6_info->nsiblings)
821		return 0;
822
823	list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
824		if (i == fen6_info->nsiblings)
825			break;
826
827		rt_arr[i + 1] = iter;
828		fib6_info_hold(iter);
829		i++;
830	}
831	WARN_ON_ONCE(i != fen6_info->nsiblings);
832
833	return 0;
834}
835
836static void nsim_fib6_event_fini(struct nsim_fib6_event *fib6_event)
837{
838	int i;
839
840	for (i = 0; i < fib6_event->nrt6; i++)
841		nsim_rt6_release(fib6_event->rt_arr[i]);
842	kfree(fib6_event->rt_arr);
843}
844
845static int nsim_fib6_event(struct nsim_fib_data *data,
846			   struct nsim_fib6_event *fib6_event,
847			   unsigned long event)
848{
849	int err;
850
851	if (fib6_event->rt_arr[0]->fib6_src.plen)
852		return 0;
853
854	switch (event) {
855	case FIB_EVENT_ENTRY_REPLACE:
856		err = nsim_fib6_rt_insert(data, fib6_event);
857		if (err)
858			goto err_rt_offload_failed_flag_set;
859		break;
860	case FIB_EVENT_ENTRY_APPEND:
861		err = nsim_fib6_rt_append(data, fib6_event);
862		if (err)
863			goto err_rt_offload_failed_flag_set;
864		break;
865	case FIB_EVENT_ENTRY_DEL:
866		nsim_fib6_rt_remove(data, fib6_event);
867		break;
868	default:
869		break;
870	}
871
872	return 0;
873
874err_rt_offload_failed_flag_set:
875	nsim_fib6_rt_offload_failed_flag_set(data, fib6_event->rt_arr,
876					     fib6_event->nrt6);
877	return err;
878}
879
880static void nsim_fib_event(struct nsim_fib_event *fib_event)
881{
882	switch (fib_event->family) {
883	case AF_INET:
884		nsim_fib4_event(fib_event->data, &fib_event->fen_info,
885				fib_event->event);
886		fib_info_put(fib_event->fen_info.fi);
887		break;
888	case AF_INET6:
889		nsim_fib6_event(fib_event->data, &fib_event->fib6_event,
890				fib_event->event);
891		nsim_fib6_event_fini(&fib_event->fib6_event);
892		break;
893	}
894}
895
896static int nsim_fib4_prepare_event(struct fib_notifier_info *info,
897				   struct nsim_fib_event *fib_event,
898				   unsigned long event)
899{
900	struct nsim_fib_data *data = fib_event->data;
901	struct fib_entry_notifier_info *fen_info;
902	struct netlink_ext_ack *extack;
903	int err = 0;
904
905	fen_info = container_of(info, struct fib_entry_notifier_info,
906				info);
907	fib_event->fen_info = *fen_info;
908	extack = info->extack;
909
910	switch (event) {
911	case FIB_EVENT_ENTRY_REPLACE:
912		err = nsim_fib_account(&data->ipv4.fib, true);
913		if (err) {
914			NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib entries");
915			return err;
916		}
917		break;
918	case FIB_EVENT_ENTRY_DEL:
919		if (data->fail_route_delete) {
920			NL_SET_ERR_MSG_MOD(extack, "Failed to process route deletion");
921			return -EINVAL;
922		}
923		nsim_fib_account(&data->ipv4.fib, false);
924		break;
925	}
926
927	/* Take reference on fib_info to prevent it from being
928	 * freed while event is queued. Release it afterwards.
929	 */
930	fib_info_hold(fib_event->fen_info.fi);
931
932	return 0;
933}
934
935static int nsim_fib6_prepare_event(struct fib_notifier_info *info,
936				   struct nsim_fib_event *fib_event,
937				   unsigned long event)
938{
939	struct nsim_fib_data *data = fib_event->data;
940	struct fib6_entry_notifier_info *fen6_info;
941	struct netlink_ext_ack *extack;
942	int err = 0;
943
944	fen6_info = container_of(info, struct fib6_entry_notifier_info,
945				 info);
946
947	err = nsim_fib6_event_init(&fib_event->fib6_event, fen6_info);
948	if (err)
949		return err;
950
951	extack = info->extack;
952	switch (event) {
953	case FIB_EVENT_ENTRY_REPLACE:
954		err = nsim_fib_account(&data->ipv6.fib, true);
955		if (err) {
956			NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib entries");
957			goto err_fib6_event_fini;
958		}
959		break;
960	case FIB_EVENT_ENTRY_DEL:
961		if (data->fail_route_delete) {
962			err = -EINVAL;
963			NL_SET_ERR_MSG_MOD(extack, "Failed to process route deletion");
964			goto err_fib6_event_fini;
965		}
966		nsim_fib_account(&data->ipv6.fib, false);
967		break;
968	}
969
970	return 0;
971
972err_fib6_event_fini:
973	nsim_fib6_event_fini(&fib_event->fib6_event);
974	return err;
975}
976
977static int nsim_fib_event_schedule_work(struct nsim_fib_data *data,
978					struct fib_notifier_info *info,
979					unsigned long event)
980{
981	struct nsim_fib_event *fib_event;
982	int err;
983
984	if (info->family != AF_INET && info->family != AF_INET6)
985		/* netdevsim does not support 'RTNL_FAMILY_IP6MR' and
986		 * 'RTNL_FAMILY_IPMR' and should ignore them.
987		 */
988		return NOTIFY_DONE;
989
990	fib_event = kzalloc(sizeof(*fib_event), GFP_ATOMIC);
991	if (!fib_event)
992		goto err_fib_event_alloc;
993
994	fib_event->data = data;
995	fib_event->event = event;
996	fib_event->family = info->family;
997
998	switch (info->family) {
999	case AF_INET:
1000		err = nsim_fib4_prepare_event(info, fib_event, event);
1001		break;
1002	case AF_INET6:
1003		err = nsim_fib6_prepare_event(info, fib_event, event);
1004		break;
1005	}
1006
1007	if (err)
1008		goto err_fib_prepare_event;
1009
1010	/* Enqueue the event and trigger the work */
1011	spin_lock_bh(&data->fib_event_queue_lock);
1012	list_add_tail(&fib_event->list, &data->fib_event_queue);
1013	spin_unlock_bh(&data->fib_event_queue_lock);
1014	schedule_work(&data->fib_event_work);
1015
1016	return NOTIFY_DONE;
1017
1018err_fib_prepare_event:
1019	kfree(fib_event);
1020err_fib_event_alloc:
1021	if (event == FIB_EVENT_ENTRY_DEL)
1022		schedule_work(&data->fib_flush_work);
1023	return NOTIFY_BAD;
1024}
1025
1026static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
1027			     void *ptr)
1028{
1029	struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
1030						  fib_nb);
1031	struct fib_notifier_info *info = ptr;
1032	int err;
1033
1034	switch (event) {
1035	case FIB_EVENT_RULE_ADD:
1036	case FIB_EVENT_RULE_DEL:
1037		err = nsim_fib_rule_event(data, info,
1038					  event == FIB_EVENT_RULE_ADD);
1039		return notifier_from_errno(err);
1040	case FIB_EVENT_ENTRY_REPLACE:
1041	case FIB_EVENT_ENTRY_APPEND:
1042	case FIB_EVENT_ENTRY_DEL:
1043		return nsim_fib_event_schedule_work(data, info, event);
1044	}
1045
1046	return NOTIFY_DONE;
1047}
1048
1049static void nsim_fib4_rt_free(struct nsim_fib_rt *fib_rt,
1050			      struct nsim_fib_data *data)
1051{
1052	struct devlink *devlink = data->devlink;
1053	struct nsim_fib4_rt *fib4_rt;
1054
1055	fib4_rt = container_of(fib_rt, struct nsim_fib4_rt, common);
1056	nsim_fib4_rt_hw_flags_set(devlink_net(devlink), fib4_rt, false);
1057	nsim_fib_account(&data->ipv4.fib, false);
1058	nsim_fib4_rt_destroy(fib4_rt);
1059}
1060
1061static void nsim_fib6_rt_free(struct nsim_fib_rt *fib_rt,
1062			      struct nsim_fib_data *data)
1063{
1064	struct nsim_fib6_rt *fib6_rt;
1065
1066	fib6_rt = container_of(fib_rt, struct nsim_fib6_rt, common);
1067	nsim_fib6_rt_hw_flags_set(data, fib6_rt, false);
1068	nsim_fib_account(&data->ipv6.fib, false);
1069	nsim_fib6_rt_destroy(fib6_rt);
1070}
1071
1072static void nsim_fib_rt_free(void *ptr, void *arg)
1073{
1074	struct nsim_fib_rt *fib_rt = ptr;
1075	struct nsim_fib_data *data = arg;
1076
1077	switch (fib_rt->key.family) {
1078	case AF_INET:
1079		nsim_fib4_rt_free(fib_rt, data);
1080		break;
1081	case AF_INET6:
1082		nsim_fib6_rt_free(fib_rt, data);
1083		break;
1084	default:
1085		WARN_ON_ONCE(1);
1086	}
1087}
1088
1089/* inconsistent dump, trying again */
1090static void nsim_fib_dump_inconsistent(struct notifier_block *nb)
1091{
1092	struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
1093						  fib_nb);
1094	struct nsim_fib_rt *fib_rt, *fib_rt_tmp;
1095
1096	/* Flush the work to make sure there is no race with notifications. */
1097	flush_work(&data->fib_event_work);
1098
1099	/* The notifier block is still not registered, so we do not need to
1100	 * take any locks here.
1101	 */
1102	list_for_each_entry_safe(fib_rt, fib_rt_tmp, &data->fib_rt_list, list) {
1103		rhashtable_remove_fast(&data->fib_rt_ht, &fib_rt->ht_node,
1104				       nsim_fib_rt_ht_params);
1105		nsim_fib_rt_free(fib_rt, data);
1106	}
1107
1108	atomic64_set(&data->ipv4.rules.num, 0ULL);
1109	atomic64_set(&data->ipv6.rules.num, 0ULL);
1110}
1111
1112static struct nsim_nexthop *nsim_nexthop_create(struct nsim_fib_data *data,
1113						struct nh_notifier_info *info)
1114{
1115	struct nsim_nexthop *nexthop;
1116	u64 occ = 0;
1117	int i;
1118
1119	nexthop = kzalloc(sizeof(*nexthop), GFP_KERNEL);
1120	if (!nexthop)
1121		return ERR_PTR(-ENOMEM);
1122
1123	nexthop->id = info->id;
1124
1125	/* Determine the number of nexthop entries the new nexthop will
1126	 * occupy.
1127	 */
1128
1129	switch (info->type) {
1130	case NH_NOTIFIER_INFO_TYPE_SINGLE:
1131		occ = 1;
1132		break;
1133	case NH_NOTIFIER_INFO_TYPE_GRP:
1134		for (i = 0; i < info->nh_grp->num_nh; i++)
1135			occ += info->nh_grp->nh_entries[i].weight;
1136		break;
1137	case NH_NOTIFIER_INFO_TYPE_RES_TABLE:
1138		occ = info->nh_res_table->num_nh_buckets;
1139		nexthop->is_resilient = true;
1140		break;
1141	default:
1142		NL_SET_ERR_MSG_MOD(info->extack, "Unsupported nexthop type");
1143		kfree(nexthop);
1144		return ERR_PTR(-EOPNOTSUPP);
1145	}
1146
1147	nexthop->occ = occ;
1148	return nexthop;
1149}
1150
1151static void nsim_nexthop_destroy(struct nsim_nexthop *nexthop)
1152{
1153	kfree(nexthop);
1154}
1155
1156static int nsim_nexthop_account(struct nsim_fib_data *data, u64 occ,
1157				bool add, struct netlink_ext_ack *extack)
1158{
1159	int i, err = 0;
1160
1161	if (add) {
1162		for (i = 0; i < occ; i++)
1163			if (!atomic64_add_unless(&data->nexthops.num, 1,
1164						 data->nexthops.max)) {
1165				err = -ENOSPC;
1166				NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported nexthops");
1167				goto err_num_decrease;
1168			}
1169	} else {
1170		if (WARN_ON(occ > atomic64_read(&data->nexthops.num)))
1171			return -EINVAL;
1172		atomic64_sub(occ, &data->nexthops.num);
1173	}
1174
1175	return err;
1176
1177err_num_decrease:
1178	atomic64_sub(i, &data->nexthops.num);
1179	return err;
1180
1181}
1182
1183static void nsim_nexthop_hw_flags_set(struct net *net,
1184				      const struct nsim_nexthop *nexthop,
1185				      bool trap)
1186{
1187	int i;
1188
1189	nexthop_set_hw_flags(net, nexthop->id, false, trap);
1190
1191	if (!nexthop->is_resilient)
1192		return;
1193
1194	for (i = 0; i < nexthop->occ; i++)
1195		nexthop_bucket_set_hw_flags(net, nexthop->id, i, false, trap);
1196}
1197
1198static int nsim_nexthop_add(struct nsim_fib_data *data,
1199			    struct nsim_nexthop *nexthop,
1200			    struct netlink_ext_ack *extack)
1201{
1202	struct net *net = devlink_net(data->devlink);
1203	int err;
1204
1205	err = nsim_nexthop_account(data, nexthop->occ, true, extack);
1206	if (err)
1207		return err;
1208
1209	err = rhashtable_insert_fast(&data->nexthop_ht, &nexthop->ht_node,
1210				     nsim_nexthop_ht_params);
1211	if (err) {
1212		NL_SET_ERR_MSG_MOD(extack, "Failed to insert nexthop");
1213		goto err_nexthop_dismiss;
1214	}
1215
1216	nsim_nexthop_hw_flags_set(net, nexthop, true);
1217
1218	return 0;
1219
1220err_nexthop_dismiss:
1221	nsim_nexthop_account(data, nexthop->occ, false, extack);
1222	return err;
1223}
1224
1225static int nsim_nexthop_replace(struct nsim_fib_data *data,
1226				struct nsim_nexthop *nexthop,
1227				struct nsim_nexthop *nexthop_old,
1228				struct netlink_ext_ack *extack)
1229{
1230	struct net *net = devlink_net(data->devlink);
1231	int err;
1232
1233	err = nsim_nexthop_account(data, nexthop->occ, true, extack);
1234	if (err)
1235		return err;
1236
1237	err = rhashtable_replace_fast(&data->nexthop_ht,
1238				      &nexthop_old->ht_node, &nexthop->ht_node,
1239				      nsim_nexthop_ht_params);
1240	if (err) {
1241		NL_SET_ERR_MSG_MOD(extack, "Failed to replace nexthop");
1242		goto err_nexthop_dismiss;
1243	}
1244
1245	nsim_nexthop_hw_flags_set(net, nexthop, true);
1246	nsim_nexthop_account(data, nexthop_old->occ, false, extack);
1247	nsim_nexthop_destroy(nexthop_old);
1248
1249	return 0;
1250
1251err_nexthop_dismiss:
1252	nsim_nexthop_account(data, nexthop->occ, false, extack);
1253	return err;
1254}
1255
1256static int nsim_nexthop_insert(struct nsim_fib_data *data,
1257			       struct nh_notifier_info *info)
1258{
1259	struct nsim_nexthop *nexthop, *nexthop_old;
1260	int err;
1261
1262	nexthop = nsim_nexthop_create(data, info);
1263	if (IS_ERR(nexthop))
1264		return PTR_ERR(nexthop);
1265
1266	nexthop_old = rhashtable_lookup_fast(&data->nexthop_ht, &info->id,
1267					     nsim_nexthop_ht_params);
1268	if (!nexthop_old)
1269		err = nsim_nexthop_add(data, nexthop, info->extack);
1270	else
1271		err = nsim_nexthop_replace(data, nexthop, nexthop_old,
1272					   info->extack);
1273
1274	if (err)
1275		nsim_nexthop_destroy(nexthop);
1276
1277	return err;
1278}
1279
1280static void nsim_nexthop_remove(struct nsim_fib_data *data,
1281				struct nh_notifier_info *info)
1282{
1283	struct nsim_nexthop *nexthop;
1284
1285	nexthop = rhashtable_lookup_fast(&data->nexthop_ht, &info->id,
1286					 nsim_nexthop_ht_params);
1287	if (!nexthop)
1288		return;
1289
1290	rhashtable_remove_fast(&data->nexthop_ht, &nexthop->ht_node,
1291			       nsim_nexthop_ht_params);
1292	nsim_nexthop_account(data, nexthop->occ, false, info->extack);
1293	nsim_nexthop_destroy(nexthop);
1294}
1295
1296static int nsim_nexthop_res_table_pre_replace(struct nsim_fib_data *data,
1297					      struct nh_notifier_info *info)
1298{
1299	if (data->fail_res_nexthop_group_replace) {
1300		NL_SET_ERR_MSG_MOD(info->extack, "Failed to replace a resilient nexthop group");
1301		return -EINVAL;
1302	}
1303
1304	return 0;
1305}
1306
1307static int nsim_nexthop_bucket_replace(struct nsim_fib_data *data,
1308				       struct nh_notifier_info *info)
1309{
1310	if (data->fail_nexthop_bucket_replace) {
1311		NL_SET_ERR_MSG_MOD(info->extack, "Failed to replace nexthop bucket");
1312		return -EINVAL;
1313	}
1314
1315	nexthop_bucket_set_hw_flags(info->net, info->id,
1316				    info->nh_res_bucket->bucket_index,
1317				    false, true);
1318
1319	return 0;
1320}
1321
1322static int nsim_nexthop_event_nb(struct notifier_block *nb, unsigned long event,
1323				 void *ptr)
1324{
1325	struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
1326						  nexthop_nb);
1327	struct nh_notifier_info *info = ptr;
1328	int err = 0;
1329
1330	mutex_lock(&data->nh_lock);
1331	switch (event) {
1332	case NEXTHOP_EVENT_REPLACE:
1333		err = nsim_nexthop_insert(data, info);
1334		break;
1335	case NEXTHOP_EVENT_DEL:
1336		nsim_nexthop_remove(data, info);
1337		break;
1338	case NEXTHOP_EVENT_RES_TABLE_PRE_REPLACE:
1339		err = nsim_nexthop_res_table_pre_replace(data, info);
1340		break;
1341	case NEXTHOP_EVENT_BUCKET_REPLACE:
1342		err = nsim_nexthop_bucket_replace(data, info);
1343		break;
1344	default:
1345		break;
1346	}
1347
1348	mutex_unlock(&data->nh_lock);
1349	return notifier_from_errno(err);
1350}
1351
1352static void nsim_nexthop_free(void *ptr, void *arg)
1353{
1354	struct nsim_nexthop *nexthop = ptr;
1355	struct nsim_fib_data *data = arg;
1356	struct net *net;
1357
1358	net = devlink_net(data->devlink);
1359	nsim_nexthop_hw_flags_set(net, nexthop, false);
1360	nsim_nexthop_account(data, nexthop->occ, false, NULL);
1361	nsim_nexthop_destroy(nexthop);
1362}
1363
1364static ssize_t nsim_nexthop_bucket_activity_write(struct file *file,
1365						  const char __user *user_buf,
1366						  size_t size, loff_t *ppos)
1367{
1368	struct nsim_fib_data *data = file->private_data;
1369	struct net *net = devlink_net(data->devlink);
1370	struct nsim_nexthop *nexthop;
1371	unsigned long *activity;
1372	loff_t pos = *ppos;
1373	u16 bucket_index;
1374	char buf[128];
1375	int err = 0;
1376	u32 nhid;
1377
1378	if (pos != 0)
1379		return -EINVAL;
1380	if (size > sizeof(buf))
1381		return -EINVAL;
1382	if (copy_from_user(buf, user_buf, size))
1383		return -EFAULT;
1384	if (sscanf(buf, "%u %hu", &nhid, &bucket_index) != 2)
1385		return -EINVAL;
1386
1387	rtnl_lock();
1388
1389	nexthop = rhashtable_lookup_fast(&data->nexthop_ht, &nhid,
1390					 nsim_nexthop_ht_params);
1391	if (!nexthop || !nexthop->is_resilient ||
1392	    bucket_index >= nexthop->occ) {
1393		err = -EINVAL;
1394		goto out;
1395	}
1396
1397	activity = bitmap_zalloc(nexthop->occ, GFP_KERNEL);
1398	if (!activity) {
1399		err = -ENOMEM;
1400		goto out;
1401	}
1402
1403	bitmap_set(activity, bucket_index, 1);
1404	nexthop_res_grp_activity_update(net, nhid, nexthop->occ, activity);
1405	bitmap_free(activity);
1406
1407out:
1408	rtnl_unlock();
1409
1410	*ppos = size;
1411	return err ?: size;
1412}
1413
1414static const struct file_operations nsim_nexthop_bucket_activity_fops = {
1415	.open = simple_open,
1416	.write = nsim_nexthop_bucket_activity_write,
1417	.llseek = no_llseek,
1418	.owner = THIS_MODULE,
1419};
1420
1421static u64 nsim_fib_ipv4_resource_occ_get(void *priv)
1422{
1423	struct nsim_fib_data *data = priv;
1424
1425	return nsim_fib_get_val(data, NSIM_RESOURCE_IPV4_FIB, false);
1426}
1427
1428static u64 nsim_fib_ipv4_rules_res_occ_get(void *priv)
1429{
1430	struct nsim_fib_data *data = priv;
1431
1432	return nsim_fib_get_val(data, NSIM_RESOURCE_IPV4_FIB_RULES, false);
1433}
1434
1435static u64 nsim_fib_ipv6_resource_occ_get(void *priv)
1436{
1437	struct nsim_fib_data *data = priv;
1438
1439	return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB, false);
1440}
1441
1442static u64 nsim_fib_ipv6_rules_res_occ_get(void *priv)
1443{
1444	struct nsim_fib_data *data = priv;
1445
1446	return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB_RULES, false);
1447}
1448
1449static u64 nsim_fib_nexthops_res_occ_get(void *priv)
1450{
1451	struct nsim_fib_data *data = priv;
1452
1453	return nsim_fib_get_val(data, NSIM_RESOURCE_NEXTHOPS, false);
1454}
1455
1456static void nsim_fib_set_max_all(struct nsim_fib_data *data,
1457				 struct devlink *devlink)
1458{
1459	static const enum nsim_resource_id res_ids[] = {
1460		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
1461		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES,
1462		NSIM_RESOURCE_NEXTHOPS,
1463	};
1464	int i;
1465
1466	for (i = 0; i < ARRAY_SIZE(res_ids); i++) {
1467		int err;
1468		u64 val;
1469
1470		err = devl_resource_size_get(devlink, res_ids[i], &val);
1471		if (err)
1472			val = (u64) -1;
1473		nsim_fib_set_max(data, res_ids[i], val);
1474	}
1475}
1476
1477static void nsim_fib_event_work(struct work_struct *work)
1478{
1479	struct nsim_fib_data *data = container_of(work, struct nsim_fib_data,
1480						  fib_event_work);
1481	struct nsim_fib_event *fib_event, *next_fib_event;
1482
1483	LIST_HEAD(fib_event_queue);
1484
1485	spin_lock_bh(&data->fib_event_queue_lock);
1486	list_splice_init(&data->fib_event_queue, &fib_event_queue);
1487	spin_unlock_bh(&data->fib_event_queue_lock);
1488
1489	mutex_lock(&data->fib_lock);
1490	list_for_each_entry_safe(fib_event, next_fib_event, &fib_event_queue,
1491				 list) {
1492		nsim_fib_event(fib_event);
1493		list_del(&fib_event->list);
1494		kfree(fib_event);
1495		cond_resched();
1496	}
1497	mutex_unlock(&data->fib_lock);
1498}
1499
1500static void nsim_fib_flush_work(struct work_struct *work)
1501{
1502	struct nsim_fib_data *data = container_of(work, struct nsim_fib_data,
1503						  fib_flush_work);
1504	struct nsim_fib_rt *fib_rt, *fib_rt_tmp;
1505
1506	/* Process pending work. */
1507	flush_work(&data->fib_event_work);
1508
1509	mutex_lock(&data->fib_lock);
1510	list_for_each_entry_safe(fib_rt, fib_rt_tmp, &data->fib_rt_list, list) {
1511		rhashtable_remove_fast(&data->fib_rt_ht, &fib_rt->ht_node,
1512				       nsim_fib_rt_ht_params);
1513		nsim_fib_rt_free(fib_rt, data);
1514	}
1515	mutex_unlock(&data->fib_lock);
1516}
1517
1518static int
1519nsim_fib_debugfs_init(struct nsim_fib_data *data, struct nsim_dev *nsim_dev)
1520{
1521	data->ddir = debugfs_create_dir("fib", nsim_dev->ddir);
1522	if (IS_ERR(data->ddir))
1523		return PTR_ERR(data->ddir);
1524
1525	data->fail_route_offload = false;
1526	debugfs_create_bool("fail_route_offload", 0600, data->ddir,
1527			    &data->fail_route_offload);
1528
1529	data->fail_res_nexthop_group_replace = false;
1530	debugfs_create_bool("fail_res_nexthop_group_replace", 0600, data->ddir,
1531			    &data->fail_res_nexthop_group_replace);
1532
1533	data->fail_nexthop_bucket_replace = false;
1534	debugfs_create_bool("fail_nexthop_bucket_replace", 0600, data->ddir,
1535			    &data->fail_nexthop_bucket_replace);
1536
1537	debugfs_create_file("nexthop_bucket_activity", 0200, data->ddir,
1538			    data, &nsim_nexthop_bucket_activity_fops);
1539
1540	data->fail_route_delete = false;
1541	debugfs_create_bool("fail_route_delete", 0600, data->ddir,
1542			    &data->fail_route_delete);
1543	return 0;
1544}
1545
1546static void nsim_fib_debugfs_exit(struct nsim_fib_data *data)
1547{
1548	debugfs_remove_recursive(data->ddir);
1549}
1550
1551struct nsim_fib_data *nsim_fib_create(struct devlink *devlink,
1552				      struct netlink_ext_ack *extack)
1553{
1554	struct nsim_fib_data *data;
1555	struct nsim_dev *nsim_dev;
1556	int err;
1557
1558	data = kzalloc(sizeof(*data), GFP_KERNEL);
1559	if (!data)
1560		return ERR_PTR(-ENOMEM);
1561	data->devlink = devlink;
1562
1563	nsim_dev = devlink_priv(devlink);
1564	err = nsim_fib_debugfs_init(data, nsim_dev);
1565	if (err)
1566		goto err_data_free;
1567
1568	mutex_init(&data->nh_lock);
1569	err = rhashtable_init(&data->nexthop_ht, &nsim_nexthop_ht_params);
1570	if (err)
1571		goto err_debugfs_exit;
1572
1573	mutex_init(&data->fib_lock);
1574	INIT_LIST_HEAD(&data->fib_rt_list);
1575	err = rhashtable_init(&data->fib_rt_ht, &nsim_fib_rt_ht_params);
1576	if (err)
1577		goto err_rhashtable_nexthop_destroy;
1578
1579	INIT_WORK(&data->fib_event_work, nsim_fib_event_work);
1580	INIT_WORK(&data->fib_flush_work, nsim_fib_flush_work);
1581	INIT_LIST_HEAD(&data->fib_event_queue);
1582	spin_lock_init(&data->fib_event_queue_lock);
1583
1584	nsim_fib_set_max_all(data, devlink);
1585
1586	data->nexthop_nb.notifier_call = nsim_nexthop_event_nb;
1587	err = register_nexthop_notifier(devlink_net(devlink), &data->nexthop_nb,
1588					extack);
1589	if (err) {
1590		pr_err("Failed to register nexthop notifier\n");
1591		goto err_rhashtable_fib_destroy;
1592	}
1593
1594	data->fib_nb.notifier_call = nsim_fib_event_nb;
1595	err = register_fib_notifier(devlink_net(devlink), &data->fib_nb,
1596				    nsim_fib_dump_inconsistent, extack);
1597	if (err) {
1598		pr_err("Failed to register fib notifier\n");
1599		goto err_nexthop_nb_unregister;
1600	}
1601
1602	devl_resource_occ_get_register(devlink,
1603				       NSIM_RESOURCE_IPV4_FIB,
1604				       nsim_fib_ipv4_resource_occ_get,
1605				       data);
1606	devl_resource_occ_get_register(devlink,
1607				       NSIM_RESOURCE_IPV4_FIB_RULES,
1608				       nsim_fib_ipv4_rules_res_occ_get,
1609				       data);
1610	devl_resource_occ_get_register(devlink,
1611				       NSIM_RESOURCE_IPV6_FIB,
1612				       nsim_fib_ipv6_resource_occ_get,
1613				       data);
1614	devl_resource_occ_get_register(devlink,
1615				       NSIM_RESOURCE_IPV6_FIB_RULES,
1616				       nsim_fib_ipv6_rules_res_occ_get,
1617				       data);
1618	devl_resource_occ_get_register(devlink,
1619				       NSIM_RESOURCE_NEXTHOPS,
1620				       nsim_fib_nexthops_res_occ_get,
1621				       data);
1622	return data;
1623
1624err_nexthop_nb_unregister:
1625	unregister_nexthop_notifier(devlink_net(devlink), &data->nexthop_nb);
1626err_rhashtable_fib_destroy:
1627	cancel_work_sync(&data->fib_flush_work);
1628	flush_work(&data->fib_event_work);
1629	rhashtable_free_and_destroy(&data->fib_rt_ht, nsim_fib_rt_free,
1630				    data);
1631err_rhashtable_nexthop_destroy:
1632	rhashtable_free_and_destroy(&data->nexthop_ht, nsim_nexthop_free,
1633				    data);
1634	mutex_destroy(&data->fib_lock);
1635err_debugfs_exit:
1636	mutex_destroy(&data->nh_lock);
1637	nsim_fib_debugfs_exit(data);
1638err_data_free:
1639	kfree(data);
1640	return ERR_PTR(err);
1641}
1642
1643void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data)
1644{
1645	devl_resource_occ_get_unregister(devlink,
1646					 NSIM_RESOURCE_NEXTHOPS);
1647	devl_resource_occ_get_unregister(devlink,
1648					 NSIM_RESOURCE_IPV6_FIB_RULES);
1649	devl_resource_occ_get_unregister(devlink,
1650					 NSIM_RESOURCE_IPV6_FIB);
1651	devl_resource_occ_get_unregister(devlink,
1652					 NSIM_RESOURCE_IPV4_FIB_RULES);
1653	devl_resource_occ_get_unregister(devlink,
1654					 NSIM_RESOURCE_IPV4_FIB);
1655	unregister_fib_notifier(devlink_net(devlink), &data->fib_nb);
1656	unregister_nexthop_notifier(devlink_net(devlink), &data->nexthop_nb);
1657	cancel_work_sync(&data->fib_flush_work);
1658	flush_work(&data->fib_event_work);
1659	rhashtable_free_and_destroy(&data->fib_rt_ht, nsim_fib_rt_free,
1660				    data);
1661	rhashtable_free_and_destroy(&data->nexthop_ht, nsim_nexthop_free,
1662				    data);
1663	WARN_ON_ONCE(!list_empty(&data->fib_event_queue));
1664	WARN_ON_ONCE(!list_empty(&data->fib_rt_list));
1665	mutex_destroy(&data->fib_lock);
1666	mutex_destroy(&data->nh_lock);
1667	nsim_fib_debugfs_exit(data);
1668	kfree(data);
1669}
1670