xref: /freebsd/sys/net/route/fib_algo.c (revision 3d030136ad1906e6d463673a8d2ef313eb054fb3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Alexander V. Chernikov
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include "opt_inet.h"
30 #include "opt_inet6.h"
31 #include "opt_route.h"
32 
33 #include <sys/param.h>
34 #include <sys/eventhandler.h>
35 #include <sys/kernel.h>
36 #include <sys/sbuf.h>
37 #include <sys/lock.h>
38 #include <sys/rmlock.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/module.h>
42 #include <sys/kernel.h>
43 #include <sys/priv.h>
44 #include <sys/proc.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/stdarg.h>
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50 #include <sys/queue.h>
51 #include <net/vnet.h>
52 
53 #include <net/if.h>
54 #include <net/if_var.h>
55 
56 #include <netinet/in.h>
57 #include <netinet/in_var.h>
58 #include <netinet/ip.h>
59 #include <netinet/ip_var.h>
60 #ifdef INET6
61 #include <netinet/ip6.h>
62 #include <netinet6/ip6_var.h>
63 #endif
64 
65 #include <net/route.h>
66 #include <net/route/nhop.h>
67 #include <net/route/route_ctl.h>
68 #include <net/route/route_var.h>
69 #include <net/route/fib_algo.h>
70 
71 /*
72  * Fib lookup framework.
73  *
74  * This framework enables accelerated longest-prefix-match lookups for the
75  *  routing tables by adding the ability to dynamically attach/detach lookup
76  *  algorithms implementation to/from the datapath.
77  *
78  * flm - fib lookup modules - implementation of particular lookup algorithm
79  * fd - fib data - instance of an flm bound to specific routing table
80  *
81  * This file provides main framework functionality.
82  *
83  * The following are the features provided by the framework
84  *
85  * 1) nexhops abstraction -> provides transparent referencing, indexing
86  *   and efficient idx->ptr mappings for nexthop and nexthop groups.
87  * 2) Routing table synchronisation
88  * 3) dataplane attachment points
89  * 4) automatic algorithm selection based on the provided preference.
90  *
91  *
92  * DATAPATH
93  * For each supported address family, there is a an allocated array of fib_dp
94  *  structures, indexed by fib number. Each array entry contains callback function
95  *  and its argument. This function will be called with a family-specific lookup key,
96  *  scope and provided argument. This array gets re-created every time when new algo
97  *  instance gets created. Please take a look at the replace_rtables_family() function
98  *  for more details.
99  *
100  */
101 
102 SYSCTL_DECL(_net_route);
103 SYSCTL_NODE(_net_route, OID_AUTO, algo, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
104     "Fib algorithm lookups");
105 
106 /* Algorithm sync policy */
107 
108 /* Time interval to bucket updates */
109 VNET_DEFINE_STATIC(unsigned int, update_bucket_time_ms) = 50;
110 #define	V_update_bucket_time_ms	VNET(update_bucket_time_ms)
111 SYSCTL_UINT(_net_route_algo, OID_AUTO, bucket_time_ms, CTLFLAG_RW | CTLFLAG_VNET,
112     &VNET_NAME(update_bucket_time_ms), 0, "Time interval to calculate update rate");
113 
114 /* Minimum update rate to delay sync */
115 VNET_DEFINE_STATIC(unsigned int, bucket_change_threshold_rate) = 500;
116 #define	V_bucket_change_threshold_rate	VNET(bucket_change_threshold_rate)
117 SYSCTL_UINT(_net_route_algo, OID_AUTO, bucket_change_threshold_rate, CTLFLAG_RW | CTLFLAG_VNET,
118     &VNET_NAME(bucket_change_threshold_rate), 0, "Minimum update rate to delay sync");
119 
120 /* Max allowed delay to sync */
121 VNET_DEFINE_STATIC(unsigned int, fib_max_sync_delay_ms) = 1000;
122 #define	V_fib_max_sync_delay_ms	VNET(fib_max_sync_delay_ms)
123 SYSCTL_UINT(_net_route_algo, OID_AUTO, fib_max_sync_delay_ms, CTLFLAG_RW | CTLFLAG_VNET,
124     &VNET_NAME(fib_max_sync_delay_ms), 0, "Maximum time to delay sync (ms)");
125 
126 
127 #ifdef INET6
128 VNET_DEFINE_STATIC(bool, algo_fixed_inet6) = false;
129 #define	V_algo_fixed_inet6	VNET(algo_fixed_inet6)
130 SYSCTL_NODE(_net_route_algo, OID_AUTO, inet6, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
131     "IPv6 longest prefix match lookups");
132 #endif
133 #ifdef INET
134 VNET_DEFINE_STATIC(bool, algo_fixed_inet) = false;
135 #define	V_algo_fixed_inet	VNET(algo_fixed_inet)
136 SYSCTL_NODE(_net_route_algo, OID_AUTO, inet, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
137     "IPv4 longest prefix match lookups");
138 #endif
139 
140 /* Fib instance counter */
141 static uint32_t fib_gen = 0;
142 
143 struct nhop_ref_table {
144 	uint32_t		count;
145 	int32_t			refcnt[0];
146 };
147 
148 /*
149  * Nexthop indexes are allocated per-rib, and ribs are keyed by
150  * (fibnum, neighbor family). A route with a gateway belonging to another
151  * family (an IPv4 prefix via an IPv6 nexthop, RFC 5549) therefore gets
152  * its index from that other family's space, where it can collide with the
153  * index of a native nexthop.
154  *
155  * Keep one flat idx->nhop array, but give every index space a contiguous
156  * segment within it, so the array offset is nhaf_base + nhop index.
157  * The rib's own family always owns the first segment, making the offset
158  * identical to the nexthop index for every table with no cross-family nexthops.
159  */
160 struct nhop_af_table {
161 	uint8_t			nhaf_family;	/* AF owning this index space */
162 	bool			nhaf_hit;	/* true if out of index space */
163 	uint32_t		nhaf_count;	/* # of indexes reserved */
164 	uint32_t		nhaf_base;	/* offset within fd->nh_idx */
165 };
166 
167 /* # of nhop index spaces per instance, currently 4o6 for now */
168 #define	FD_MAX_NH_AF	2
169 
170 enum fib_callout_action {
171 	FDA_NONE,	/* No callout scheduled */
172 	FDA_REBUILD,	/* Asks to rebuild algo instance */
173 	FDA_EVAL,	/* Asks to evaluate if the current algo is still be best */
174 	FDA_BATCH,	/* Asks to submit batch of updates to the algo */
175 };
176 
177 struct fib_sync_status {
178 	struct timeval		diverge_time;	/* ts when diverged */
179 	uint32_t		num_changes;	/* number of changes since sync */
180 	uint32_t		bucket_changes;	/* num changes within the current bucket */
181 	uint64_t		bucket_id;	/* 50ms bucket # */
182 	struct fib_change_queue	fd_change_queue;/* list of scheduled entries */
183 };
184 
185 /*
186  * Data structure for the fib lookup instance tied to the particular rib.
187  *
188  * Key:
189  * (f) - Protected by the FIB_MOD lock
190  * (r) - Protected by the RIB lock
191  */
192 struct fib_data {
193 	uint32_t		number_nhops;	/* (r) total size of the nhop arrays */
194 	uint32_t		fd_dead:1,	/* (f) Scheduled for deletion */
195 				fd_linked:1;	/* (f) true if linked */
196 	uint32_t		init_done:1,	/* (r) true if init is competed */
197 				fd_need_rebuild:1,	/* (r) true if rebuild scheduled */
198 				fd_batch:1,	/* (r) true if batched notification scheduled */
199 				hit_nhops:1;	/* (r) true if out of nhop limit */
200 	uint8_t			fd_num_af;	/* (r) # of nhop index spaces in use */
201 	uint8_t			fd_family;	/* family */
202 	uint32_t		fd_fibnum;	/* fibnum */
203 	uint32_t		fd_failed_rebuilds;	/* stat: failed rebuilds */
204 	uint32_t		fd_gen;		/* instance gen# */
205 	struct callout		fd_callout;	/* rebuild callout */
206 	enum fib_callout_action	fd_callout_action;	/* Callout action to take */
207 	void			*fd_algo_data;	/* algorithm data */
208 	struct nhop_af_table	fd_af[FD_MAX_NH_AF];	/* (r) index space descriptors */
209 	struct nhop_object	**nh_idx;	/* nhop idx->ptr array */
210 	struct nhop_ref_table	*nh_ref_table;	/* array with # of nhop references */
211 	struct rib_head		*fd_rh;		/* RIB table we're attached to */
212 	struct rib_subscription	*fd_rs;		/* storing table subscription */
213 	struct fib_dp		fd_dp;		/* fib datapath data */
214 	struct vnet		*fd_vnet;	/* vnet fib belongs to */
215 	struct epoch_context	fd_epoch_ctx;	/* epoch context for deletion */
216 	struct fib_lookup_module	*fd_flm;/* pointer to the lookup module */
217 	struct fib_sync_status	fd_ss;		/* State relevant to the rib sync  */
218 	uint32_t		fd_num_changes;	/* number of changes since last callout */
219 	TAILQ_ENTRY(fib_data)	entries;	/* list of all fds in vnet */
220 };
221 
222 static bool rebuild_fd(struct fib_data *fd, const char *reason);
223 static bool rebuild_fd_flm(struct fib_data *fd, struct fib_lookup_module *flm_new);
224 static void handle_fd_callout(void *_data);
225 static void destroy_fd_instance_epoch(epoch_context_t ctx);
226 static bool is_idx_free(struct fib_data *fd, uint32_t index);
227 static void set_algo_fixed(struct rib_head *rh);
228 static bool is_algo_fixed(struct rib_head *rh);
229 
230 static uint32_t fib_ref_nhop(struct fib_data *fd, struct nhop_object *nh);
231 static void fib_unref_nhop(struct fib_data *fd, struct nhop_object *nh);
232 
233 static struct fib_lookup_module *fib_check_best_algo(struct rib_head *rh,
234     struct fib_lookup_module *orig_flm);
235 static void fib_unref_algo(struct fib_lookup_module *flm);
236 static bool flm_error_check(const struct fib_lookup_module *flm, uint32_t fibnum);
237 
238 struct mtx fib_mtx;
239 #define	FIB_MOD_LOCK()		mtx_lock(&fib_mtx)
240 #define	FIB_MOD_UNLOCK()	mtx_unlock(&fib_mtx)
241 #define	FIB_MOD_LOCK_ASSERT()	mtx_assert(&fib_mtx, MA_OWNED)
242 
243 MTX_SYSINIT(fib_mtx, &fib_mtx, "algo list mutex", MTX_DEF);
244 
245 /* Algorithm has to be this percent better than the current to switch */
246 #define	BEST_DIFF_PERCENT	(5 * 256 / 100)
247 /* Schedule algo re-evaluation X seconds after a change */
248 #define	ALGO_EVAL_DELAY_MS	30000
249 /* Force algo re-evaluation after X changes */
250 #define	ALGO_EVAL_NUM_ROUTES	100
251 /* Try to setup algorithm X times */
252 #define	FIB_MAX_TRIES		32
253 /* Max amount of supported nexthops */
254 #define	FIB_MAX_NHOPS		262144
255 #define	FIB_CALLOUT_DELAY_MS	50
256 
257 
258 /* Debug */
259 static int flm_debug_level = LOG_NOTICE;
260 SYSCTL_INT(_net_route_algo, OID_AUTO, debug_level, CTLFLAG_RW | CTLFLAG_RWTUN,
261     &flm_debug_level, 0, "debuglevel");
262 #define	FLM_MAX_DEBUG_LEVEL	LOG_DEBUG
263 #ifndef	LOG_DEBUG2
264 #define	LOG_DEBUG2	8
265 #endif
266 
267 #define	_PASS_MSG(_l)	(flm_debug_level >= (_l))
268 #define	ALGO_PRINTF(_l, _fmt, ...)	if (_PASS_MSG(_l)) {		\
269 	printf("[fib_algo] %s: " _fmt "\n", __func__, ##__VA_ARGS__);	\
270 }
271 #define	_ALGO_PRINTF(_fib, _fam, _aname, _gen, _func, _fmt, ...) \
272     printf("[fib_algo] %s.%u (%s#%u) %s: " _fmt "\n",\
273     print_family(_fam), _fib, _aname, _gen, _func, ## __VA_ARGS__)
274 #define	_RH_PRINTF(_fib, _fam, _func, _fmt, ...) \
275     printf("[fib_algo] %s.%u %s: " _fmt "\n", print_family(_fam), _fib, _func, ## __VA_ARGS__)
276 #define	RH_PRINTF(_l, _rh, _fmt, ...)	if (_PASS_MSG(_l)) {	\
277     _RH_PRINTF(_rh->rib_fibnum, _rh->rib_family, __func__, _fmt, ## __VA_ARGS__);\
278 }
279 #define	FD_PRINTF(_l, _fd, _fmt, ...)	FD_PRINTF_##_l(_l, _fd, _fmt, ## __VA_ARGS__)
280 #define	_FD_PRINTF(_l, _fd, _fmt, ...)	if (_PASS_MSG(_l)) {		\
281     _ALGO_PRINTF(_fd->fd_fibnum, _fd->fd_family, _fd->fd_flm->flm_name,	\
282     _fd->fd_gen, __func__, _fmt, ## __VA_ARGS__);			\
283 }
284 #if FLM_MAX_DEBUG_LEVEL>=LOG_DEBUG2
285 #define	FD_PRINTF_LOG_DEBUG2	_FD_PRINTF
286 #else
287 #define	FD_PRINTF_LOG_DEBUG2(_l, _fd, _fmt, ...)
288 #endif
289 #if FLM_MAX_DEBUG_LEVEL>=LOG_DEBUG
290 #define	FD_PRINTF_LOG_DEBUG	_FD_PRINTF
291 #else
292 #define	FD_PRINTF_LOG_DEBUG()
293 #endif
294 #if FLM_MAX_DEBUG_LEVEL>=LOG_INFO
295 #define	FD_PRINTF_LOG_INFO	_FD_PRINTF
296 #else
297 #define	FD_PRINTF_LOG_INFO()
298 #endif
299 #define	FD_PRINTF_LOG_NOTICE	_FD_PRINTF
300 #define	FD_PRINTF_LOG_ERR	_FD_PRINTF
301 #define	FD_PRINTF_LOG_WARNING	_FD_PRINTF
302 
303 
304 /* List of all registered lookup algorithms */
305 static TAILQ_HEAD(, fib_lookup_module) all_algo_list = TAILQ_HEAD_INITIALIZER(all_algo_list);
306 
307 /* List of all fib lookup instances in the vnet */
308 VNET_DEFINE_STATIC(TAILQ_HEAD(fib_data_head, fib_data), fib_data_list);
309 #define	V_fib_data_list	VNET(fib_data_list)
310 
311 /* Datastructure for storing non-transient fib lookup module failures */
312 struct fib_error {
313 	int				fe_family;
314 	uint32_t			fe_fibnum;	/* failed rtable */
315 	struct fib_lookup_module	*fe_flm;	/* failed module */
316 	TAILQ_ENTRY(fib_error)		entries;/* list of all errored entries */
317 };
318 VNET_DEFINE_STATIC(TAILQ_HEAD(fib_error_head, fib_error), fib_error_list);
319 #define	V_fib_error_list VNET(fib_error_list)
320 
321 /* Per-family array of fibnum -> {func, arg} mappings used in datapath */
322 struct fib_dp_header {
323 	struct epoch_context	fdh_epoch_ctx;
324 	uint32_t		fdh_num_tables;
325 	struct fib_dp		fdh_idx[0];
326 };
327 
328 /*
329  * Tries to add new non-transient algorithm error to the list of
330  *  errors.
331  * Returns true on success.
332  */
333 static bool
334 flm_error_add(struct fib_lookup_module *flm, uint32_t fibnum)
335 {
336 	struct fib_error *fe;
337 
338 	fe = malloc(sizeof(struct fib_error), M_TEMP, M_NOWAIT | M_ZERO);
339 	if (fe == NULL)
340 		return (false);
341 	fe->fe_flm = flm;
342 	fe->fe_family = flm->flm_family;
343 	fe->fe_fibnum = fibnum;
344 
345 	FIB_MOD_LOCK();
346 	/* Avoid duplicates by checking if error already exists first */
347 	if (flm_error_check(flm, fibnum)) {
348 		FIB_MOD_UNLOCK();
349 		free(fe, M_TEMP);
350 		return (true);
351 	}
352 	TAILQ_INSERT_HEAD(&V_fib_error_list, fe, entries);
353 	FIB_MOD_UNLOCK();
354 
355 	return (true);
356 }
357 
358 /*
359  * True if non-transient error has been registered for @flm in @fibnum.
360  */
361 static bool
362 flm_error_check(const struct fib_lookup_module *flm, uint32_t fibnum)
363 {
364 	const struct fib_error *fe;
365 
366 	TAILQ_FOREACH(fe, &V_fib_error_list, entries) {
367 		if ((fe->fe_flm == flm) && (fe->fe_fibnum == fibnum))
368 			return (true);
369 	}
370 
371 	return (false);
372 }
373 
374 /*
375  * Clear all errors of algo specified by @flm.
376  */
377 static void
378 fib_error_clear_flm(struct fib_lookup_module *flm)
379 {
380 	struct fib_error *fe, *fe_tmp;
381 
382 	FIB_MOD_LOCK_ASSERT();
383 
384 	TAILQ_FOREACH_SAFE(fe, &V_fib_error_list, entries, fe_tmp) {
385 		if (fe->fe_flm == flm) {
386 			TAILQ_REMOVE(&V_fib_error_list, fe, entries);
387 			free(fe, M_TEMP);
388 		}
389 	}
390 }
391 
392 /*
393  * Clears all errors in current VNET.
394  */
395 static void
396 fib_error_clear(void)
397 {
398 	struct fib_error *fe, *fe_tmp;
399 
400 	FIB_MOD_LOCK_ASSERT();
401 
402 	TAILQ_FOREACH_SAFE(fe, &V_fib_error_list, entries, fe_tmp) {
403 		TAILQ_REMOVE(&V_fib_error_list, fe, entries);
404 		free(fe, M_TEMP);
405 	}
406 }
407 
408 static const char *
409 print_op_result(enum flm_op_result result)
410 {
411 	switch (result) {
412 	case FLM_SUCCESS:
413 		return "success";
414 	case FLM_REBUILD:
415 		return "rebuild";
416 	case FLM_BATCH:
417 		return "batch";
418 	case FLM_ERROR:
419 		return "error";
420 	}
421 
422 	return "unknown";
423 }
424 
425 static const char *
426 print_family(int family)
427 {
428 
429 	if (family == AF_INET)
430 		return ("inet");
431 	else if (family == AF_INET6)
432 		return ("inet6");
433 	else
434 		return ("unknown");
435 }
436 
437 /*
438  * Debug function used by lookup algorithms.
439  * Outputs message denoted by @fmt, prepended by "[fib_algo] inetX.Y (algo) "
440  */
441 void
442 fib_printf(int level, struct fib_data *fd, const char *func, char *fmt, ...)
443 {
444 	char buf[128];
445 	va_list ap;
446 
447 	if (level > flm_debug_level)
448 		return;
449 
450 	va_start(ap, fmt);
451 	vsnprintf(buf, sizeof(buf), fmt, ap);
452 	va_end(ap);
453 
454 	_ALGO_PRINTF(fd->fd_fibnum, fd->fd_family, fd->fd_flm->flm_name,
455 	    fd->fd_gen, func, "%s", buf);
456 }
457 
458 /*
459  * Outputs list of algorithms supported by the provided address family.
460  */
461 static int
462 print_algos_sysctl(struct sysctl_req *req, int family)
463 {
464 	struct fib_lookup_module *flm;
465 	struct sbuf sbuf;
466 	int error, count = 0;
467 
468 	error = sysctl_wire_old_buffer(req, 0);
469 	if (error == 0) {
470 		sbuf_new_for_sysctl(&sbuf, NULL, 512, req);
471 		TAILQ_FOREACH(flm, &all_algo_list, entries) {
472 			if (flm->flm_family == family) {
473 				if (count++ > 0)
474 					sbuf_cat(&sbuf, ", ");
475 				sbuf_cat(&sbuf, flm->flm_name);
476 			}
477 		}
478 		error = sbuf_finish(&sbuf);
479 		sbuf_delete(&sbuf);
480 	}
481 	return (error);
482 }
483 
484 #ifdef INET6
485 static int
486 print_algos_sysctl_inet6(SYSCTL_HANDLER_ARGS)
487 {
488 
489 	return (print_algos_sysctl(req, AF_INET6));
490 }
491 SYSCTL_PROC(_net_route_algo_inet6, OID_AUTO, algo_list,
492     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
493     print_algos_sysctl_inet6, "A", "List of IPv6 lookup algorithms");
494 #endif
495 
496 #ifdef INET
497 static int
498 print_algos_sysctl_inet(SYSCTL_HANDLER_ARGS)
499 {
500 
501 	return (print_algos_sysctl(req, AF_INET));
502 }
503 SYSCTL_PROC(_net_route_algo_inet, OID_AUTO, algo_list,
504     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
505     print_algos_sysctl_inet, "A", "List of IPv4 lookup algorithms");
506 #endif
507 
508 /*
509  * Calculate delay between repeated failures.
510  * Returns current delay in milliseconds.
511  */
512 static uint32_t
513 callout_calc_delay_ms(struct fib_data *fd)
514 {
515 	uint32_t shift;
516 
517 	if (fd->fd_failed_rebuilds > 10)
518 		shift = 10;
519 	else
520 		shift = fd->fd_failed_rebuilds;
521 
522 	return ((1 << shift) * FIB_CALLOUT_DELAY_MS);
523 }
524 
525 static void
526 schedule_callout(struct fib_data *fd, enum fib_callout_action action, int delay_ms)
527 {
528 
529 	FD_PRINTF(LOG_DEBUG, fd, "delay=%d action=%d", delay_ms, action);
530 	fd->fd_callout_action = action;
531 	callout_reset_sbt(&fd->fd_callout, SBT_1MS * delay_ms, 0,
532 	    handle_fd_callout, fd, 0);
533 }
534 
535 static void
536 schedule_fd_rebuild(struct fib_data *fd, const char *reason)
537 {
538 
539 	RIB_WLOCK_ASSERT(fd->fd_rh);
540 
541 	if (!fd->fd_need_rebuild) {
542 		fd->fd_need_rebuild = true;
543 		/* Stop batch updates */
544 		fd->fd_batch = false;
545 
546 		/*
547 		 * Potentially re-schedules pending callout
548 		 *  initiated by schedule_algo_eval.
549 		 */
550 		FD_PRINTF(LOG_INFO, fd, "Scheduling rebuild: %s (failures=%d)",
551 		    reason, fd->fd_failed_rebuilds);
552 		schedule_callout(fd, FDA_REBUILD, callout_calc_delay_ms(fd));
553 	}
554 }
555 
556 static void
557 sync_rib_gen(struct fib_data *fd)
558 {
559 	FD_PRINTF(LOG_DEBUG, fd, "Sync gen %u -> %u", fd->fd_rh->rnh_gen, fd->fd_rh->rnh_gen_rib);
560 	fd->fd_rh->rnh_gen = fd->fd_rh->rnh_gen_rib;
561 }
562 
563 static int64_t
564 get_tv_diff_ms(const struct timeval *old_tv, const struct timeval *new_tv)
565 {
566 	int64_t diff = 0;
567 
568 	diff = ((int64_t)(new_tv->tv_sec - old_tv->tv_sec)) * 1000;
569 	diff += (new_tv->tv_usec - old_tv->tv_usec) / 1000;
570 
571 	return (diff);
572 }
573 
574 static void
575 add_tv_diff_ms(struct timeval *tv, int ms)
576 {
577 	tv->tv_sec += ms / 1000;
578 	ms = ms % 1000;
579 	if (ms * 1000 + tv->tv_usec < 1000000)
580 		tv->tv_usec += ms * 1000;
581 	else {
582 		tv->tv_sec += 1;
583 		tv->tv_usec = ms * 1000 + tv->tv_usec - 1000000;
584 	}
585 }
586 
587 /*
588  * Marks the time when algo state diverges from the rib state.
589  */
590 static void
591 mark_diverge_time(struct fib_data *fd)
592 {
593 	struct fib_sync_status *fd_ss = &fd->fd_ss;
594 
595 	getmicrouptime(&fd_ss->diverge_time);
596 	fd_ss->bucket_id = 0;
597 	fd_ss->bucket_changes = 0;
598 }
599 
600 /*
601  * Calculates and updates the next algorithm sync time, based on the current activity.
602  *
603  * The intent is to provide reasonable balance between the update
604  *  latency and efficient batching when changing large amount of routes.
605  *
606  * High-level algorithm looks the following:
607  * 1) all changes are bucketed in 50ms intervals
608  * 2) If amount of changes within the bucket is greater than the threshold,
609  *   the update gets delayed, up to maximum delay threshold.
610  */
611 static void
612 update_rebuild_delay(struct fib_data *fd, enum fib_callout_action action)
613 {
614 	uint32_t bucket_id, new_delay = 0;
615 	struct timeval tv;
616 
617 	/* Fetch all variables at once to ensure consistent reads */
618 	uint32_t bucket_time_ms = V_update_bucket_time_ms;
619 	uint32_t threshold_rate = V_bucket_change_threshold_rate;
620 	uint32_t max_delay_ms = V_fib_max_sync_delay_ms;
621 
622 	if (bucket_time_ms == 0)
623 		bucket_time_ms = 50;
624 	/* calculate per-bucket threshold rate */
625 	threshold_rate = threshold_rate * bucket_time_ms / 1000;
626 
627 	getmicrouptime(&tv);
628 
629 	struct fib_sync_status *fd_ss = &fd->fd_ss;
630 
631 	bucket_id = get_tv_diff_ms(&fd_ss->diverge_time, &tv) / bucket_time_ms;
632 
633 	if (fd_ss->bucket_id == bucket_id) {
634 		fd_ss->bucket_changes++;
635 		if (fd_ss->bucket_changes == threshold_rate) {
636 			new_delay = (bucket_id + 2) * bucket_time_ms;
637 			if (new_delay <= max_delay_ms) {
638 				FD_PRINTF(LOG_DEBUG, fd,
639 				    "hit threshold of %u routes, delay update,"
640 				    "bucket: %u, total delay: %u",
641 				    threshold_rate, bucket_id + 1, new_delay);
642 			} else {
643 				new_delay = 0;
644 				FD_PRINTF(LOG_DEBUG, fd,
645 				    "maximum sync delay (%u ms) reached", max_delay_ms);
646 			}
647 		} else if ((bucket_id == 0) && (fd_ss->bucket_changes == 1))
648 			new_delay = bucket_time_ms;
649 	} else {
650 		fd_ss->bucket_id = bucket_id;
651 		fd_ss->bucket_changes = 1;
652 	}
653 
654 	if (new_delay > 0) {
655 		/* Calculated time has been updated */
656 		struct timeval new_tv = fd_ss->diverge_time;
657 		add_tv_diff_ms(&new_tv, new_delay);
658 
659 		int32_t delay_ms = get_tv_diff_ms(&tv, &new_tv);
660 		schedule_callout(fd, action, delay_ms);
661 	}
662 }
663 
664 static void
665 update_algo_state(struct fib_data *fd)
666 {
667 
668 	RIB_WLOCK_ASSERT(fd->fd_rh);
669 
670 	if (fd->fd_batch || fd->fd_need_rebuild) {
671 		enum fib_callout_action action = fd->fd_need_rebuild ? FDA_REBUILD : FDA_BATCH;
672 		update_rebuild_delay(fd, action);
673 		return;
674 	}
675 
676 	if (fd->fd_num_changes++ == 0) {
677 		/* Start callout to consider switch */
678 		if (!callout_pending(&fd->fd_callout))
679 			schedule_callout(fd, FDA_EVAL, ALGO_EVAL_DELAY_MS);
680 	} else if (fd->fd_num_changes == ALGO_EVAL_NUM_ROUTES) {
681 		/* Reset callout to exec immediately */
682 		if (fd->fd_callout_action == FDA_EVAL)
683 			schedule_callout(fd, FDA_EVAL, 1);
684 	}
685 }
686 
687 static bool
688 need_immediate_sync(struct fib_data *fd, struct rib_cmd_info *rc)
689 {
690 	struct nhop_object *nh;
691 
692 	/* Sync addition/removal of interface routes */
693 	switch (rc->rc_cmd) {
694 	case RTM_ADD:
695 		nh = rc->rc_nh_new;
696 		if (!NH_IS_NHGRP(nh)) {
697 			if (!(nh->nh_flags & NHF_GATEWAY))
698 				return (true);
699 			if (nhop_get_rtflags(nh) & RTF_STATIC)
700 				return (true);
701 		}
702 		break;
703 	case RTM_DELETE:
704 		nh = rc->rc_nh_old;
705 		if (!NH_IS_NHGRP(nh)) {
706 			if (!(nh->nh_flags & NHF_GATEWAY))
707 				return (true);
708 			if (nhop_get_rtflags(nh) & RTF_STATIC)
709 				return (true);
710 		}
711 		break;
712 	}
713 
714 	return (false);
715 }
716 
717 static bool
718 apply_rtable_changes(struct fib_data *fd)
719 {
720 	enum flm_op_result result;
721 	struct fib_change_queue *q = &fd->fd_ss.fd_change_queue;
722 
723 	result = fd->fd_flm->flm_change_rib_items_cb(fd->fd_rh, q, fd->fd_algo_data);
724 
725 	if (result == FLM_SUCCESS) {
726 		sync_rib_gen(fd);
727 		for (int i = 0; i < q->count; i++)
728 			if (q->entries[i].nh_old)
729 				fib_unref_nhop(fd, q->entries[i].nh_old);
730 		q->count = 0;
731 	}
732 	fd->fd_batch = false;
733 
734 	return (result == FLM_SUCCESS);
735 }
736 
737 static bool
738 fill_change_entry(struct fib_data *fd, struct fib_change_entry *ce, struct rib_cmd_info *rc)
739 {
740 	int plen = 0;
741 
742 	switch (fd->fd_family) {
743 #ifdef INET
744 	case AF_INET:
745 		rt_get_inet_prefix_plen(rc->rc_rt, &ce->addr4, &plen, &ce->scopeid);
746 		break;
747 #endif
748 #ifdef INET6
749 	case AF_INET6:
750 		rt_get_inet6_prefix_plen(rc->rc_rt, &ce->addr6, &plen, &ce->scopeid);
751 		break;
752 #endif
753 	}
754 
755 	ce->plen = plen;
756 	ce->nh_old = rc->rc_nh_old;
757 	ce->nh_new = rc->rc_nh_new;
758 	if (ce->nh_new != NULL) {
759 		if (fib_ref_nhop(fd, ce->nh_new) == 0)
760 			return (false);
761 	}
762 
763 	return (true);
764 }
765 
766 static bool
767 queue_rtable_change(struct fib_data *fd, struct rib_cmd_info *rc)
768 {
769 	struct fib_change_queue *q = &fd->fd_ss.fd_change_queue;
770 
771 	if (q->count >= q->size) {
772 		uint32_t q_size;
773 
774 		if (q->size == 0)
775 			q_size = 256; /* ~18k memory */
776 		else
777 			q_size = q->size * 2;
778 
779 		size_t size = q_size * sizeof(struct fib_change_entry);
780 		void *a = realloc(q->entries, size, M_TEMP, M_NOWAIT | M_ZERO);
781 		if (a == NULL) {
782 			FD_PRINTF(LOG_INFO, fd, "Unable to realloc queue for %u elements",
783 			    q_size);
784 			return (false);
785 		}
786 		q->entries = a;
787 		q->size = q_size;
788 	}
789 
790 	return (fill_change_entry(fd, &q->entries[q->count++], rc));
791 }
792 
793 /*
794  * Rib subscription handler. Checks if the algorithm is ready to
795  *  receive updates, handles nexthop refcounting and passes change
796  *  data to the algorithm callback.
797  */
798 static void
799 handle_rtable_change_cb(struct rib_head *rnh, struct rib_cmd_info *rc,
800     void *_data)
801 {
802 	struct fib_data *fd = (struct fib_data *)_data;
803 	enum flm_op_result result;
804 
805 	RIB_WLOCK_ASSERT(rnh);
806 
807 	/*
808 	 * There is a small gap between subscribing for route changes
809 	 *  and initiating rtable dump. Avoid receiving route changes
810 	 *  prior to finishing rtable dump by checking `init_done`.
811 	 */
812 	if (!fd->init_done)
813 		return;
814 
815 	bool immediate_sync = need_immediate_sync(fd, rc);
816 
817 	/* Consider scheduling algorithm re-evaluation */
818 	update_algo_state(fd);
819 
820 	/*
821 	 * If algo requested rebuild, stop sending updates by default.
822 	 * This simplifies nexthop refcount handling logic.
823 	 */
824 	if (fd->fd_need_rebuild) {
825 		if (immediate_sync)
826 			rebuild_fd(fd, "rtable change type enforced sync");
827 		return;
828 	}
829 
830 	/*
831 	 * Algo requested updates to be delivered in batches.
832 	 * Add the current change to the queue and return.
833 	 */
834 	if (fd->fd_batch) {
835 		if (immediate_sync) {
836 			if (!queue_rtable_change(fd, rc) || !apply_rtable_changes(fd))
837 				rebuild_fd(fd, "batch sync failed");
838 		} else {
839 			if (!queue_rtable_change(fd, rc))
840 				schedule_fd_rebuild(fd, "batch queue failed");
841 		}
842 		return;
843 	}
844 
845 	/*
846 	 * Maintain guarantee that every nexthop returned by the dataplane
847 	 *  lookup has > 0 refcount, so can be safely referenced within current
848 	 *  epoch.
849 	 */
850 	if (rc->rc_nh_new != NULL) {
851 		if (fib_ref_nhop(fd, rc->rc_nh_new) == 0) {
852 			if (immediate_sync)
853 				rebuild_fd(fd, "ran out of nhop indexes");
854 			else
855 				schedule_fd_rebuild(fd, "ran out of nhop indexes");
856 			return;
857 		}
858 	}
859 
860 	result = fd->fd_flm->flm_change_rib_item_cb(rnh, rc, fd->fd_algo_data);
861 
862 	switch (result) {
863 	case FLM_SUCCESS:
864 		sync_rib_gen(fd);
865 		/* Unref old nexthop on success */
866 		if (rc->rc_nh_old != NULL)
867 			fib_unref_nhop(fd, rc->rc_nh_old);
868 		break;
869 	case FLM_BATCH:
870 
871 		/*
872 		 * Algo asks to batch the changes.
873 		 */
874 		if (queue_rtable_change(fd, rc)) {
875 			if (!immediate_sync) {
876 				fd->fd_batch = true;
877 				mark_diverge_time(fd);
878 				update_rebuild_delay(fd, FDA_BATCH);
879 				break;
880 			}
881 			if (apply_rtable_changes(fd))
882 				break;
883 		}
884 		FD_PRINTF(LOG_ERR, fd, "batched sync failed, force the rebuild");
885 
886 	case FLM_REBUILD:
887 
888 		/*
889 		 * Algo is not able to apply the update.
890 		 * Schedule algo rebuild.
891 		 */
892 		if (!immediate_sync) {
893 			mark_diverge_time(fd);
894 			schedule_fd_rebuild(fd, "algo requested rebuild");
895 			break;
896 		}
897 
898 		FD_PRINTF(LOG_INFO, fd, "running sync rebuild");
899 		rebuild_fd(fd, "rtable change type enforced sync");
900 		break;
901 	case FLM_ERROR:
902 
903 		/*
904 		 * Algo reported a non-recoverable error.
905 		 * Record the error and schedule rebuild, which will
906 		 *  trigger best algo selection.
907 		 */
908 		FD_PRINTF(LOG_ERR, fd, "algo reported non-recoverable error");
909 		if (!flm_error_add(fd->fd_flm, fd->fd_fibnum))
910 			FD_PRINTF(LOG_ERR, fd, "failed to ban algo");
911 		schedule_fd_rebuild(fd, "algo reported non-recoverable error");
912 	}
913 }
914 
915 static void
916 estimate_nhop_scale(const struct fib_data *old_fd, struct fib_data *fd)
917 {
918 	uint32_t base = 0;
919 
920 	if (old_fd == NULL) {
921 		fd->fd_num_af = 1;
922 		fd->fd_af[0].nhaf_family = fd->fd_family;
923 		// TODO: read from rtable
924 		fd->fd_af[0].nhaf_count = 16;
925 	} else {
926 		fd->fd_num_af = old_fd->fd_num_af;
927 		memcpy(fd->fd_af, old_fd->fd_af, sizeof(fd->fd_af));
928 
929 		for (int i = 0; i < fd->fd_num_af; i++) {
930 			struct nhop_af_table *nt;
931 
932 			nt = &fd->fd_af[i];
933 			nt->nhaf_hit = false;
934 			if (!old_fd->fd_af[i].nhaf_hit)
935 				continue;
936 			if (nt->nhaf_count == 0)
937 				/* half of the main family */
938 				nt->nhaf_count = 8;
939 			else if (nt->nhaf_count < FIB_MAX_NHOPS)
940 				nt->nhaf_count *= 2;
941 		}
942 	}
943 
944 	for (int i = 0; i < fd->fd_num_af; i++) {
945 		fd->fd_af[i].nhaf_base = base;
946 		base += fd->fd_af[i].nhaf_count;
947 	}
948 	fd->number_nhops = base;
949 }
950 
951 struct walk_cbdata {
952 	struct fib_data		*fd;
953 	flm_dump_t		*func;
954 	enum flm_op_result	result;
955 };
956 
957 /*
958  * Handler called after all rtenties have been dumped.
959  * Performs post-dump framework checks and calls
960  * algo:flm_dump_end_cb().
961  *
962  * Updates walk_cbdata result.
963  */
964 static void
965 sync_algo_end_cb(struct rib_head *rnh, enum rib_walk_hook stage, void *_data)
966 {
967 	struct walk_cbdata *w = (struct walk_cbdata *)_data;
968 	struct fib_data *fd = w->fd;
969 
970 	RIB_WLOCK_ASSERT(w->fd->fd_rh);
971 
972 	if (rnh->rib_dying) {
973 		w->result = FLM_ERROR;
974 		return;
975 	}
976 
977 	if (fd->hit_nhops) {
978 		FD_PRINTF(LOG_INFO, fd, "ran out of nexthops at %u nhops",
979 		    fd->nh_ref_table->count);
980 		if (w->result == FLM_SUCCESS)
981 			w->result = FLM_REBUILD;
982 		return;
983 	}
984 
985 	if (stage != RIB_WALK_HOOK_POST || w->result != FLM_SUCCESS)
986 		return;
987 
988 	/* Post-dump hook, dump successful */
989 	w->result = fd->fd_flm->flm_dump_end_cb(fd->fd_algo_data, &fd->fd_dp);
990 
991 	if (w->result == FLM_SUCCESS) {
992 		/* Mark init as done to allow routing updates */
993 		fd->init_done = true;
994 	}
995 }
996 
997 /*
998  * Callback for each entry in rib.
999  * Calls algo:flm_dump_rib_item_cb func as a part of initial
1000  *  route table synchronisation.
1001  */
1002 static int
1003 sync_algo_cb(struct rtentry *rt, void *_data)
1004 {
1005 	struct walk_cbdata *w = (struct walk_cbdata *)_data;
1006 
1007 	RIB_WLOCK_ASSERT(w->fd->fd_rh);
1008 
1009 	if (w->result == FLM_SUCCESS && w->func) {
1010 
1011 		/*
1012 		 * Reference nexthops to maintain guarantee that
1013 		 *  each nexthop returned by datapath has > 0 references
1014 		 *  and can be safely referenced within current epoch.
1015 		 */
1016 		struct nhop_object *nh = rt_get_raw_nhop(rt);
1017 		if (fib_ref_nhop(w->fd, nh) != 0)
1018 			w->result = w->func(rt, w->fd->fd_algo_data);
1019 		else
1020 			w->result = FLM_REBUILD;
1021 	}
1022 
1023 	return (0);
1024 }
1025 
1026 /*
1027  * Dump all routing table state to the algo instance.
1028  */
1029 static enum flm_op_result
1030 sync_algo(struct fib_data *fd)
1031 {
1032 	struct walk_cbdata w = {
1033 		.fd = fd,
1034 		.func = fd->fd_flm->flm_dump_rib_item_cb,
1035 		.result = FLM_SUCCESS,
1036 	};
1037 
1038 	rib_walk_ext_locked(fd->fd_rh, sync_algo_cb, sync_algo_end_cb, &w);
1039 
1040 	FD_PRINTF(LOG_INFO, fd,
1041 	    "initial dump completed (rtable version: %d), result: %s",
1042 	    fd->fd_rh->rnh_gen, print_op_result(w.result));
1043 
1044 	return (w.result);
1045 }
1046 
1047 /*
1048  * Schedules epoch-backed @fd instance deletion.
1049  * * Unlinks @fd from the list of active algo instances.
1050  * * Removes rib subscription.
1051  * * Stops callout.
1052  * * Schedules actual deletion.
1053  *
1054  * Assume @fd is already unlinked from the datapath.
1055  */
1056 static int
1057 schedule_destroy_fd_instance(struct fib_data *fd, bool in_callout)
1058 {
1059 	bool is_dead;
1060 
1061 	NET_EPOCH_ASSERT();
1062 	RIB_WLOCK_ASSERT(fd->fd_rh);
1063 
1064 	FIB_MOD_LOCK();
1065 	is_dead = fd->fd_dead;
1066 	if (!is_dead)
1067 		fd->fd_dead = true;
1068 	if (fd->fd_linked) {
1069 		TAILQ_REMOVE(&V_fib_data_list, fd, entries);
1070 		fd->fd_linked = false;
1071 	}
1072 	FIB_MOD_UNLOCK();
1073 	if (is_dead)
1074 		return (0);
1075 
1076 	FD_PRINTF(LOG_INFO, fd, "DETACH");
1077 
1078 	if (fd->fd_rs != NULL)
1079 		rib_unsubscribe_locked(fd->fd_rs);
1080 
1081 	/*
1082 	 * After rib_unsubscribe() no _new_ handle_rtable_change_cb() calls
1083 	 * will be executed, hence no _new_ callout schedules will happen.
1084 	 */
1085 	callout_stop(&fd->fd_callout);
1086 
1087 	fib_epoch_call(destroy_fd_instance_epoch, &fd->fd_epoch_ctx);
1088 
1089 	return (0);
1090 }
1091 
1092 /*
1093  * Wipe all fd instances from the list matching rib specified by @rh.
1094  * If @keep_first is set, remove all but the first record.
1095  */
1096 static void
1097 fib_cleanup_algo(struct rib_head *rh, bool keep_first, bool in_callout)
1098 {
1099 	struct fib_data_head tmp_head = TAILQ_HEAD_INITIALIZER(tmp_head);
1100 	struct fib_data *fd, *fd_tmp;
1101 	struct epoch_tracker et;
1102 
1103 	FIB_MOD_LOCK();
1104 	TAILQ_FOREACH_SAFE(fd, &V_fib_data_list, entries, fd_tmp) {
1105 		if (fd->fd_rh == rh) {
1106 			if (keep_first) {
1107 				keep_first = false;
1108 				continue;
1109 			}
1110 			TAILQ_REMOVE(&V_fib_data_list, fd, entries);
1111 			fd->fd_linked = false;
1112 			TAILQ_INSERT_TAIL(&tmp_head, fd, entries);
1113 		}
1114 	}
1115 	FIB_MOD_UNLOCK();
1116 
1117 	/* Pass 2: remove each entry */
1118 	NET_EPOCH_ENTER(et);
1119 	TAILQ_FOREACH_SAFE(fd, &tmp_head, entries, fd_tmp) {
1120 		if (!in_callout)
1121 			RIB_WLOCK(fd->fd_rh);
1122 		schedule_destroy_fd_instance(fd, in_callout);
1123 		if (!in_callout)
1124 			RIB_WUNLOCK(fd->fd_rh);
1125 	}
1126 	NET_EPOCH_EXIT(et);
1127 }
1128 
1129 void
1130 fib_destroy_rib(struct rib_head *rh)
1131 {
1132 
1133 	/*
1134 	 * rnh has `is_dying` flag set, so setup of new fd's will fail at
1135 	 *  sync_algo() stage, preventing new entries to be added to the list
1136 	 *  of active algos. Remove all existing entries for the particular rib.
1137 	 */
1138 	fib_cleanup_algo(rh, false, false);
1139 }
1140 
1141 /*
1142  * Finalises fd destruction by freeing all fd resources.
1143  */
1144 static void
1145 destroy_fd_instance(struct fib_data *fd)
1146 {
1147 
1148 	FD_PRINTF(LOG_INFO, fd, "destroy fd %p", fd);
1149 
1150 	/* Call destroy callback first */
1151 	if (fd->fd_algo_data != NULL)
1152 		fd->fd_flm->flm_destroy_cb(fd->fd_algo_data);
1153 
1154 	/* Nhop table */
1155 	if ((fd->nh_idx != NULL) && (fd->nh_ref_table != NULL)) {
1156 		for (int i = 0; i < fd->number_nhops; i++) {
1157 			if (!is_idx_free(fd, i)) {
1158 				FD_PRINTF(LOG_DEBUG2, fd, " FREE nhop %d %p",
1159 				    i, fd->nh_idx[i]);
1160 				nhop_free_any(fd->nh_idx[i]);
1161 			}
1162 		}
1163 		free(fd->nh_idx, M_RTABLE);
1164 	}
1165 	if (fd->nh_ref_table != NULL)
1166 		free(fd->nh_ref_table, M_RTABLE);
1167 
1168 	if (fd->fd_ss.fd_change_queue.entries != NULL)
1169 		free(fd->fd_ss.fd_change_queue.entries, M_TEMP);
1170 
1171 	fib_unref_algo(fd->fd_flm);
1172 
1173 	free(fd, M_RTABLE);
1174 }
1175 
1176 /*
1177  * Epoch callback indicating fd is safe to destroy
1178  */
1179 static void
1180 destroy_fd_instance_epoch(epoch_context_t ctx)
1181 {
1182 	struct fib_data *fd;
1183 
1184 	fd = __containerof(ctx, struct fib_data, fd_epoch_ctx);
1185 
1186 	CURVNET_SET(fd->fd_vnet);
1187 	destroy_fd_instance(fd);
1188 	CURVNET_RESTORE();
1189 }
1190 
1191 /*
1192  * Tries to setup fd instance.
1193  * - Allocates fd/nhop table
1194  * - Runs algo:flm_init_cb algo init
1195  * - Subscribes fd to the rib
1196  * - Runs rtable dump
1197  * - Adds instance to the list of active instances.
1198  *
1199  * Returns: operation result. Fills in @pfd with resulting fd on success.
1200  *
1201  */
1202 static enum flm_op_result
1203 try_setup_fd_instance(struct fib_lookup_module *flm, struct rib_head *rh,
1204     struct fib_data *old_fd, struct fib_data **pfd)
1205 {
1206 	struct fib_data *fd;
1207 	size_t size;
1208 	enum flm_op_result result;
1209 
1210 	/* Allocate */
1211 	fd = malloc(sizeof(struct fib_data), M_RTABLE, M_NOWAIT | M_ZERO);
1212 	if (fd == NULL)  {
1213 		*pfd = NULL;
1214 		RH_PRINTF(LOG_INFO, rh, "Unable to allocate fib_data structure");
1215 		return (FLM_REBUILD);
1216 	}
1217 	*pfd = fd;
1218 
1219 	fd->fd_rh = rh;
1220 	fd->fd_family = rh->rib_family;
1221 	fd->fd_fibnum = rh->rib_fibnum;
1222 	callout_init_rm(&fd->fd_callout, &rh->rib_lock, 0);
1223 	fd->fd_vnet = curvnet;
1224 	fd->fd_flm = flm;
1225 
1226 	estimate_nhop_scale(old_fd, fd);
1227 
1228 	FIB_MOD_LOCK();
1229 	flm->flm_refcount++;
1230 	fd->fd_gen = ++fib_gen;
1231 	FIB_MOD_UNLOCK();
1232 
1233 	FD_PRINTF(LOG_DEBUG, fd, "allocated fd %p", fd);
1234 
1235 	/* Allocate nhidx -> nhop_ptr table */
1236 	size = fd->number_nhops * sizeof(void *);
1237 	fd->nh_idx = malloc(size, M_RTABLE, M_NOWAIT | M_ZERO);
1238 	if (fd->nh_idx == NULL) {
1239 		FD_PRINTF(LOG_INFO, fd, "Unable to allocate nhop table idx (sz:%zu)", size);
1240 		return (FLM_REBUILD);
1241 	}
1242 
1243 	/* Allocate nhop index refcount table */
1244 	size = sizeof(struct nhop_ref_table);
1245 	size += fd->number_nhops * sizeof(uint32_t);
1246 	fd->nh_ref_table = malloc(size, M_RTABLE, M_NOWAIT | M_ZERO);
1247 	if (fd->nh_ref_table == NULL) {
1248 		FD_PRINTF(LOG_INFO, fd, "Unable to allocate nhop refcount table (sz:%zu)", size);
1249 		return (FLM_REBUILD);
1250 	}
1251 	FD_PRINTF(LOG_DEBUG, fd, "Allocated %u nhop indexes", fd->number_nhops);
1252 
1253 	/* Okay, we're ready for algo init */
1254 	void *old_algo_data = (old_fd != NULL) ? old_fd->fd_algo_data : NULL;
1255 	result = flm->flm_init_cb(fd->fd_fibnum, fd, old_algo_data, &fd->fd_algo_data);
1256 	if (result != FLM_SUCCESS) {
1257 		FD_PRINTF(LOG_INFO, fd, "%s algo init failed", flm->flm_name);
1258 		return (result);
1259 	}
1260 
1261 	/* Try to subscribe */
1262 	if (flm->flm_change_rib_item_cb != NULL) {
1263 		fd->fd_rs = rib_subscribe_locked(fd->fd_rh,
1264 		    handle_rtable_change_cb, fd, RIB_NOTIFY_IMMEDIATE);
1265 		if (fd->fd_rs == NULL) {
1266 			FD_PRINTF(LOG_INFO, fd, "failed to subscribe to the rib changes");
1267 			return (FLM_REBUILD);
1268 		}
1269 	}
1270 
1271 	/* Dump */
1272 	result = sync_algo(fd);
1273 	if (result != FLM_SUCCESS) {
1274 		FD_PRINTF(LOG_INFO, fd, "rib sync failed");
1275 		return (result);
1276 	}
1277 	FD_PRINTF(LOG_INFO, fd, "DUMP completed successfully.");
1278 
1279 	FIB_MOD_LOCK();
1280 	/*
1281 	 * Insert fd in the beginning of a list, to maintain invariant
1282 	 *  that first matching entry for the AF/fib is always the active
1283 	 *  one.
1284 	 */
1285 	TAILQ_INSERT_HEAD(&V_fib_data_list, fd, entries);
1286 	fd->fd_linked = true;
1287 	FIB_MOD_UNLOCK();
1288 
1289 	return (FLM_SUCCESS);
1290 }
1291 
1292 /*
1293  * Sets up algo @flm for table @rh and links it to the datapath.
1294  *
1295  */
1296 static enum flm_op_result
1297 setup_fd_instance(struct fib_lookup_module *flm, struct rib_head *rh,
1298     struct fib_data *orig_fd, struct fib_data **pfd, bool attach)
1299 {
1300 	struct fib_data *prev_fd, *new_fd;
1301 	enum flm_op_result result;
1302 
1303 	NET_EPOCH_ASSERT();
1304 	RIB_WLOCK_ASSERT(rh);
1305 
1306 	prev_fd = orig_fd;
1307 	new_fd = NULL;
1308 	for (int i = 0; i < FIB_MAX_TRIES; i++) {
1309 		result = try_setup_fd_instance(flm, rh, prev_fd, &new_fd);
1310 
1311 		if ((result == FLM_SUCCESS) && attach) {
1312 			if (fib_set_datapath_ptr(new_fd, &new_fd->fd_dp))
1313 				sync_rib_gen(new_fd);
1314 			else
1315 				result = FLM_REBUILD;
1316 		}
1317 
1318 		if ((prev_fd != NULL) && (prev_fd != orig_fd)) {
1319 			schedule_destroy_fd_instance(prev_fd, false);
1320 			prev_fd = NULL;
1321 		}
1322 
1323 		RH_PRINTF(LOG_INFO, rh, "try %d: fib algo result: %s", i,
1324 		    print_op_result(result));
1325 
1326 		if (result == FLM_REBUILD) {
1327 			prev_fd = new_fd;
1328 			new_fd = NULL;
1329 			continue;
1330 		}
1331 
1332 		break;
1333 	}
1334 
1335 	if (result != FLM_SUCCESS) {
1336 		RH_PRINTF(LOG_WARNING, rh,
1337 		    "%s algo instance setup failed, failures=%d", flm->flm_name,
1338 		    orig_fd ? orig_fd->fd_failed_rebuilds + 1 : 0);
1339 		/* update failure count */
1340 		FIB_MOD_LOCK();
1341 		if (orig_fd != NULL)
1342 			orig_fd->fd_failed_rebuilds++;
1343 		FIB_MOD_UNLOCK();
1344 
1345 		/* Ban algo on non-recoverable error */
1346 		if (result == FLM_ERROR)
1347 			flm_error_add(flm, rh->rib_fibnum);
1348 
1349 		if ((prev_fd != NULL) && (prev_fd != orig_fd))
1350 			schedule_destroy_fd_instance(prev_fd, false);
1351 		if (new_fd != NULL) {
1352 			schedule_destroy_fd_instance(new_fd, false);
1353 			new_fd = NULL;
1354 		}
1355 	}
1356 
1357 	*pfd = new_fd;
1358 	return (result);
1359 }
1360 
1361 /*
1362  * Tries to sync algo with the current rtable state, either
1363  * by executing batch update or rebuilding.
1364  * Returns true on success.
1365  */
1366 static bool
1367 execute_callout_action(struct fib_data *fd)
1368 {
1369 	enum fib_callout_action action = fd->fd_callout_action;
1370 	struct fib_lookup_module *flm_new = NULL;
1371 	bool result = true;
1372 
1373 	NET_EPOCH_ASSERT();
1374 	RIB_WLOCK_ASSERT(fd->fd_rh);
1375 
1376 	fd->fd_need_rebuild = false;
1377 	fd->fd_batch = false;
1378 	fd->fd_num_changes = 0;
1379 
1380 	/* First, check if we're still OK to use this algo */
1381 	if (!is_algo_fixed(fd->fd_rh))
1382 		flm_new = fib_check_best_algo(fd->fd_rh, fd->fd_flm);
1383 	if (flm_new != NULL)
1384 		action = FDA_REBUILD;
1385 
1386 	if (action == FDA_BATCH) {
1387 		/* Try to sync */
1388 		if (!apply_rtable_changes(fd))
1389 			action = FDA_REBUILD;
1390 	}
1391 
1392 	if (action == FDA_REBUILD)
1393 		result = rebuild_fd_flm(fd, flm_new != NULL ? flm_new : fd->fd_flm);
1394 	if (flm_new != NULL)
1395 		fib_unref_algo(flm_new);
1396 
1397 	return (result);
1398 }
1399 
1400 /*
1401  * Callout for all scheduled fd-related work.
1402  * - Checks if the current algo is still the best algo
1403  * - Synchronises algo instance to the rtable (batch usecase)
1404  * - Creates a new instance of an algo for af/fib if desired.
1405  */
1406 static void
1407 handle_fd_callout(void *_data)
1408 {
1409 	struct fib_data *fd = (struct fib_data *)_data;
1410 	struct epoch_tracker et;
1411 
1412 	FD_PRINTF(LOG_INFO, fd, "running callout type=%d", fd->fd_callout_action);
1413 
1414 	NET_EPOCH_ENTER(et);
1415 	CURVNET_SET(fd->fd_vnet);
1416 	execute_callout_action(fd);
1417 	CURVNET_RESTORE();
1418 	NET_EPOCH_EXIT(et);
1419 }
1420 
1421 /*
1422  * Tries to create new algo instance based on @fd data.
1423  * Returns true on success.
1424  */
1425 static bool
1426 rebuild_fd_flm(struct fib_data *fd, struct fib_lookup_module *flm_new)
1427 {
1428 	struct fib_data *fd_new, *fd_tmp = NULL;
1429 	bool result;
1430 
1431 	if (flm_new == fd->fd_flm)
1432 		fd_tmp = fd;
1433 	else
1434 		FD_PRINTF(LOG_INFO, fd, "switching algo to %s", flm_new->flm_name);
1435 
1436 	result = setup_fd_instance(flm_new, fd->fd_rh, fd_tmp, &fd_new, true);
1437 	if (result != FLM_SUCCESS) {
1438 		FD_PRINTF(LOG_NOTICE, fd, "table rebuild failed");
1439 		return (false);
1440 	}
1441 	FD_PRINTF(LOG_INFO, fd_new, "switched to new instance");
1442 
1443 	/* Remove old instance */
1444 	schedule_destroy_fd_instance(fd, true);
1445 
1446 	return (true);
1447 }
1448 
1449 static bool
1450 rebuild_fd(struct fib_data *fd, const char *reason)
1451 {
1452 	struct fib_lookup_module *flm_new = NULL;
1453 	bool result;
1454 
1455 	if (!is_algo_fixed(fd->fd_rh))
1456 		flm_new = fib_check_best_algo(fd->fd_rh, fd->fd_flm);
1457 
1458 	FD_PRINTF(LOG_INFO, fd, "running sync rebuild: %s", reason);
1459 	result = rebuild_fd_flm(fd, flm_new != NULL ? flm_new : fd->fd_flm);
1460 	if (flm_new != NULL)
1461 		fib_unref_algo(flm_new);
1462 
1463 	if (!result) {
1464 		FD_PRINTF(LOG_ERR, fd, "sync rebuild failed");
1465 		schedule_fd_rebuild(fd, "sync rebuild failed");
1466 	}
1467 
1468 	return (result);
1469 }
1470 
1471 /*
1472  * Finds algo by name/family.
1473  * Returns referenced algo or NULL.
1474  */
1475 static struct fib_lookup_module *
1476 fib_find_algo(const char *algo_name, int family)
1477 {
1478 	struct fib_lookup_module *flm;
1479 
1480 	FIB_MOD_LOCK();
1481 	TAILQ_FOREACH(flm, &all_algo_list, entries) {
1482 		if ((strcmp(flm->flm_name, algo_name) == 0) &&
1483 		    (family == flm->flm_family)) {
1484 			flm->flm_refcount++;
1485 			FIB_MOD_UNLOCK();
1486 			return (flm);
1487 		}
1488 	}
1489 	FIB_MOD_UNLOCK();
1490 
1491 	return (NULL);
1492 }
1493 
1494 static void
1495 fib_unref_algo(struct fib_lookup_module *flm)
1496 {
1497 
1498 	FIB_MOD_LOCK();
1499 	flm->flm_refcount--;
1500 	FIB_MOD_UNLOCK();
1501 }
1502 
1503 static int
1504 set_fib_algo(uint32_t fibnum, int family, struct sysctl_oid *oidp, struct sysctl_req *req)
1505 {
1506 	struct fib_lookup_module *flm = NULL;
1507 	struct fib_data *fd = NULL;
1508 	char old_algo_name[32], algo_name[32];
1509 	struct rib_head *rh = NULL;
1510 	enum flm_op_result result;
1511 	struct epoch_tracker et;
1512 	int error;
1513 
1514 	/* Fetch current algo/rib for af/family */
1515 	FIB_MOD_LOCK();
1516 	TAILQ_FOREACH(fd, &V_fib_data_list, entries) {
1517 		if ((fd->fd_family == family) && (fd->fd_fibnum == fibnum))
1518 			break;
1519 	}
1520 	if (fd == NULL) {
1521 		FIB_MOD_UNLOCK();
1522 		return (ENOENT);
1523 	}
1524 	rh = fd->fd_rh;
1525 	strlcpy(old_algo_name, fd->fd_flm->flm_name,
1526 	    sizeof(old_algo_name));
1527 	FIB_MOD_UNLOCK();
1528 
1529 	strlcpy(algo_name, old_algo_name, sizeof(algo_name));
1530 	error = sysctl_handle_string(oidp, algo_name, sizeof(algo_name), req);
1531 	if (error != 0 || req->newptr == NULL)
1532 		return (error);
1533 
1534 	if (strcmp(algo_name, old_algo_name) == 0)
1535 		return (0);
1536 
1537 	/* New algorithm name is different */
1538 	flm = fib_find_algo(algo_name, family);
1539 	if (flm == NULL) {
1540 		RH_PRINTF(LOG_INFO, rh, "unable to find algo %s", algo_name);
1541 		return (ESRCH);
1542 	}
1543 
1544 	fd = NULL;
1545 	NET_EPOCH_ENTER(et);
1546 	RIB_WLOCK(rh);
1547 	result = setup_fd_instance(flm, rh, NULL, &fd, true);
1548 	RIB_WUNLOCK(rh);
1549 	NET_EPOCH_EXIT(et);
1550 	fib_unref_algo(flm);
1551 	if (result != FLM_SUCCESS)
1552 		return (EINVAL);
1553 
1554 	/* Disable automated jumping between algos */
1555 	FIB_MOD_LOCK();
1556 	set_algo_fixed(rh);
1557 	FIB_MOD_UNLOCK();
1558 	/* Remove old instance(s) */
1559 	fib_cleanup_algo(rh, true, false);
1560 
1561 	/* Drain cb so user can unload the module after userret if so desired */
1562 	NET_EPOCH_DRAIN_CALLBACKS();
1563 
1564 	return (0);
1565 }
1566 
1567 #ifdef INET
1568 static int
1569 set_algo_inet_sysctl_handler(SYSCTL_HANDLER_ARGS)
1570 {
1571 
1572 	return (set_fib_algo(curthread->td_proc->p_fibnum, AF_INET, oidp, req));
1573 }
1574 SYSCTL_PROC(_net_route_algo_inet, OID_AUTO, algo,
1575     CTLFLAG_VNET | CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
1576     set_algo_inet_sysctl_handler, "A", "Set IPv4 lookup algo");
1577 #endif
1578 
1579 #ifdef INET6
1580 static int
1581 set_algo_inet6_sysctl_handler(SYSCTL_HANDLER_ARGS)
1582 {
1583 
1584 	return (set_fib_algo(curthread->td_proc->p_fibnum, AF_INET6, oidp, req));
1585 }
1586 SYSCTL_PROC(_net_route_algo_inet6, OID_AUTO, algo,
1587     CTLFLAG_VNET | CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
1588     set_algo_inet6_sysctl_handler, "A", "Set IPv6 lookup algo");
1589 #endif
1590 
1591 static struct nhop_object *
1592 dummy_lookup(void *algo_data, const struct flm_lookup_key key, uint32_t scopeid)
1593 {
1594 	return (NULL);
1595 }
1596 
1597 static void
1598 destroy_fdh_epoch(epoch_context_t ctx)
1599 {
1600 	struct fib_dp_header *fdh;
1601 
1602 	fdh = __containerof(ctx, struct fib_dp_header, fdh_epoch_ctx);
1603 	free(fdh, M_RTABLE);
1604 }
1605 
1606 static struct fib_dp_header *
1607 alloc_fib_dp_array(uint32_t num_tables, bool waitok)
1608 {
1609 	size_t sz;
1610 	struct fib_dp_header *fdh;
1611 
1612 	sz = sizeof(struct fib_dp_header);
1613 	sz += sizeof(struct fib_dp) * num_tables;
1614 	fdh = malloc(sz, M_RTABLE, (waitok ? M_WAITOK : M_NOWAIT) | M_ZERO);
1615 	if (fdh != NULL) {
1616 		fdh->fdh_num_tables = num_tables;
1617 		/*
1618 		 * Set dummy lookup function ptr always returning NULL, so
1619 		 * we can delay algo init.
1620 		 */
1621 		for (uint32_t i = 0; i < num_tables; i++)
1622 			fdh->fdh_idx[i].f = dummy_lookup;
1623 	}
1624 	return (fdh);
1625 }
1626 
1627 static struct fib_dp_header *
1628 get_fib_dp_header(struct fib_dp *dp)
1629 {
1630 
1631 	return (__containerof((void *)dp, struct fib_dp_header, fdh_idx));
1632 }
1633 
1634 /*
1635  * Replace per-family index pool @pdp with a new one which
1636  * contains updated callback/algo data from @fd.
1637  * Returns true on success.
1638  */
1639 static bool
1640 replace_rtables_family(struct fib_dp **pdp, struct fib_data *fd, struct fib_dp *dp)
1641 {
1642 	struct fib_dp_header *new_fdh, *old_fdh;
1643 
1644 	NET_EPOCH_ASSERT();
1645 
1646 	FD_PRINTF(LOG_DEBUG, fd, "[vnet %p] replace with f:%p arg:%p",
1647 	    curvnet, dp->f, dp->arg);
1648 
1649 	FIB_MOD_LOCK();
1650 	old_fdh = get_fib_dp_header(*pdp);
1651 
1652 	if (old_fdh->fdh_idx[fd->fd_fibnum].f == dp->f) {
1653 		/*
1654 		 * Function is the same, data pointer needs update.
1655 		 * Perform in-line replace without reallocation.
1656 		 */
1657 		old_fdh->fdh_idx[fd->fd_fibnum].arg = dp->arg;
1658 		FD_PRINTF(LOG_DEBUG, fd, "FDH %p inline update", old_fdh);
1659 		FIB_MOD_UNLOCK();
1660 		return (true);
1661 	}
1662 
1663 	new_fdh = alloc_fib_dp_array(old_fdh->fdh_num_tables, false);
1664 	FD_PRINTF(LOG_DEBUG, fd, "OLD FDH: %p NEW FDH: %p", old_fdh, new_fdh);
1665 	if (new_fdh == NULL) {
1666 		FIB_MOD_UNLOCK();
1667 		FD_PRINTF(LOG_WARNING, fd, "error attaching datapath");
1668 		return (false);
1669 	}
1670 
1671 	memcpy(&new_fdh->fdh_idx[0], &old_fdh->fdh_idx[0],
1672 	    old_fdh->fdh_num_tables * sizeof(struct fib_dp));
1673 	/* Update relevant data structure for @fd */
1674 	new_fdh->fdh_idx[fd->fd_fibnum] = *dp;
1675 
1676 	/* Ensure memcpy() writes have completed */
1677 	atomic_thread_fence_rel();
1678 	/* Set new datapath pointer */
1679 	*pdp = &new_fdh->fdh_idx[0];
1680 	FIB_MOD_UNLOCK();
1681 	FD_PRINTF(LOG_DEBUG, fd, "update %p -> %p", old_fdh, new_fdh);
1682 
1683 	fib_epoch_call(destroy_fdh_epoch, &old_fdh->fdh_epoch_ctx);
1684 
1685 	return (true);
1686 }
1687 
1688 static struct fib_dp **
1689 get_family_dp_ptr(int family)
1690 {
1691 	switch (family) {
1692 #ifdef INET
1693 	case AF_INET:
1694 		return (&V_inet_dp);
1695 #endif
1696 #ifdef INET6
1697 	case AF_INET6:
1698 		return (&V_inet6_dp);
1699 #endif
1700 	}
1701 	return (NULL);
1702 }
1703 
1704 /*
1705  * Make datapath use fib instance @fd
1706  */
1707 bool
1708 fib_set_datapath_ptr(struct fib_data *fd, struct fib_dp *dp)
1709 {
1710 	struct fib_dp **pdp;
1711 
1712 	pdp = get_family_dp_ptr(fd->fd_family);
1713 	return (replace_rtables_family(pdp, fd, dp));
1714 }
1715 
1716 /*
1717  * Grow datapath pointers array.
1718  * Called from sysctl handler on growing number of routing tables.
1719  */
1720 static void
1721 grow_rtables_family(struct fib_dp **pdp, uint32_t new_num_tables)
1722 {
1723 	struct fib_dp_header *new_fdh, *old_fdh = NULL;
1724 
1725 	new_fdh = alloc_fib_dp_array(new_num_tables, true);
1726 
1727 	FIB_MOD_LOCK();
1728 	if (*pdp != NULL) {
1729 		old_fdh = get_fib_dp_header(*pdp);
1730 		memcpy(&new_fdh->fdh_idx[0], &old_fdh->fdh_idx[0],
1731 		    old_fdh->fdh_num_tables * sizeof(struct fib_dp));
1732 	}
1733 
1734 	/* Wait till all writes completed */
1735 	atomic_thread_fence_rel();
1736 
1737 	*pdp = &new_fdh->fdh_idx[0];
1738 	FIB_MOD_UNLOCK();
1739 
1740 	if (old_fdh != NULL)
1741 		fib_epoch_call(destroy_fdh_epoch, &old_fdh->fdh_epoch_ctx);
1742 }
1743 
1744 /*
1745  * Grows per-AF arrays of datapath pointers for each supported family.
1746  * Called from fibs resize sysctl handler.
1747  */
1748 void
1749 fib_grow_rtables(uint32_t new_num_tables)
1750 {
1751 
1752 #ifdef INET
1753 	grow_rtables_family(get_family_dp_ptr(AF_INET), new_num_tables);
1754 #endif
1755 #ifdef INET6
1756 	grow_rtables_family(get_family_dp_ptr(AF_INET6), new_num_tables);
1757 #endif
1758 }
1759 
1760 void
1761 fib_get_rtable_info(struct rib_head *rh, struct rib_rtable_info *rinfo)
1762 {
1763 
1764 	bzero(rinfo, sizeof(struct rib_rtable_info));
1765 	rinfo->num_prefixes = rh->rnh_prefixes;
1766 	rinfo->num_nhops = nhops_get_count(rh);
1767 	rinfo->num_nhgrp = nhgrp_get_count(rh);
1768 }
1769 
1770 /*
1771  * Updates pointer to the algo data for the @fd.
1772  */
1773 void
1774 fib_set_algo_ptr(struct fib_data *fd, void *algo_data)
1775 {
1776 	RIB_WLOCK_ASSERT(fd->fd_rh);
1777 
1778 	fd->fd_algo_data = algo_data;
1779 }
1780 
1781 /*
1782  * Calls @callback with @ctx after the end of a current epoch.
1783  */
1784 void
1785 fib_epoch_call(epoch_callback_t callback, epoch_context_t ctx)
1786 {
1787 	NET_EPOCH_CALL(callback, ctx);
1788 }
1789 
1790 /*
1791  * Accessor to get rib instance @fd is attached to.
1792  */
1793 struct rib_head *
1794 fib_get_rh(struct fib_data *fd)
1795 {
1796 
1797 	return (fd->fd_rh);
1798 }
1799 
1800 /*
1801  * Accessor to export idx->nhop array
1802  */
1803 struct nhop_object **
1804 fib_get_nhop_array(struct fib_data *fd)
1805 {
1806 
1807 	return (fd->nh_idx);
1808 }
1809 
1810 static uint32_t
1811 get_nhop_idx(struct nhop_object *nh)
1812 {
1813 	if (NH_IS_NHGRP(nh))
1814 		return (nhgrp_get_idx((struct nhgrp_object *)nh));
1815 
1816 	return (nhop_get_idx(nh));
1817 }
1818 
1819 static uint8_t
1820 get_nhop_family(struct nhop_object *nh)
1821 {
1822 
1823 	if (NH_IS_NHGRP(nh))
1824 		return (nhgrp_get_neigh_family((struct nhgrp_object *)nh));
1825 
1826 	return (nhop_get_neigh_family(nh));
1827 }
1828 
1829 /*
1830  * Returns the index space of fd owning family, or NULL.
1831  */
1832 static struct nhop_af_table *
1833 find_af_table(struct fib_data *fd, uint8_t family)
1834 {
1835 
1836 	for (int i = 0; i < fd->fd_num_af; i++) {
1837 		if (fd->fd_af[i].nhaf_family == family)
1838 			return (&fd->fd_af[i]);
1839 	}
1840 
1841 	return (NULL);
1842 }
1843 
1844 /*
1845  * Maps nh to its offset within the flat idx->nhop array of fd.
1846  */
1847 static uint32_t
1848 get_nhop_off(struct fib_data *fd, struct nhop_object *nh)
1849 {
1850 	struct nhop_af_table *nt = find_af_table(fd, get_nhop_family(nh));
1851 	uint32_t idx = get_nhop_idx(nh);
1852 
1853 	KASSERT(nt != NULL, ("no index space for the nhop family"));
1854 	KASSERT(idx < nt->nhaf_count, ("invalid nhop index"));
1855 
1856 	return (nt->nhaf_base + idx);
1857 }
1858 
1859 uint32_t
1860 fib_get_nhop_idx(struct fib_data *fd, struct nhop_object *nh)
1861 {
1862 
1863 	return (get_nhop_off(fd, nh));
1864 }
1865 
1866 static bool
1867 is_idx_free(struct fib_data *fd, uint32_t index)
1868 {
1869 
1870 	return (fd->nh_ref_table->refcnt[index] == 0);
1871 }
1872 
1873 static uint32_t
1874 fib_ref_nhop(struct fib_data *fd, struct nhop_object *nh)
1875 {
1876 	struct nhop_af_table *nt;
1877 	uint32_t idx;
1878 	uint8_t family;
1879 
1880 	RIB_WLOCK_ASSERT(fd->fd_rh);
1881 
1882 	family = get_nhop_family(nh);
1883 	nt = find_af_table(fd, family);
1884 	if (nt == NULL) {
1885 		KASSERT(fd->fd_num_af < FD_MAX_NH_AF,
1886 		    ("out of nhop index spaces for %s", print_family(family)));
1887 		nt = &fd->fd_af[fd->fd_num_af++];
1888 		nt->nhaf_family = family;
1889 	}
1890 
1891 	idx = get_nhop_idx(nh);
1892 	if (idx >= nt->nhaf_count) {
1893 		nt->nhaf_hit = true;
1894 		fd->hit_nhops = 1;
1895 		return (0);
1896 	}
1897 	idx += nt->nhaf_base;
1898 
1899 	if (is_idx_free(fd, idx)) {
1900 		nhop_ref_any(nh);
1901 		fd->nh_idx[idx] = nh;
1902 		fd->nh_ref_table->count++;
1903 		FD_PRINTF(LOG_DEBUG2, fd, " REF nhop %u %p", idx, fd->nh_idx[idx]);
1904 	}
1905 	fd->nh_ref_table->refcnt[idx]++;
1906 
1907 	return (idx);
1908 }
1909 
1910 struct nhop_release_data {
1911 	struct nhop_object	*nh;
1912 	struct epoch_context	ctx;
1913 };
1914 
1915 static void
1916 release_nhop_epoch(epoch_context_t ctx)
1917 {
1918 	struct nhop_release_data *nrd;
1919 
1920 	nrd = __containerof(ctx, struct nhop_release_data, ctx);
1921 	nhop_free_any(nrd->nh);
1922 	free(nrd, M_TEMP);
1923 }
1924 
1925 /*
1926  * Delays nexthop refcount release.
1927  * Datapath may have the datastructures not updated yet, so the old
1928  *  nexthop may still be returned till the end of current epoch. Delay
1929  *  refcount removal, as we may be removing the last instance, which will
1930  *  trigger nexthop deletion, rendering returned nexthop invalid.
1931  */
1932 static void
1933 fib_schedule_release_nhop(struct fib_data *fd, struct nhop_object *nh)
1934 {
1935 	struct nhop_release_data *nrd;
1936 
1937 	nrd = malloc(sizeof(struct nhop_release_data), M_TEMP, M_NOWAIT | M_ZERO);
1938 	if (nrd != NULL) {
1939 		nrd->nh = nh;
1940 		fib_epoch_call(release_nhop_epoch, &nrd->ctx);
1941 	} else {
1942 		/*
1943 		 * Unable to allocate memory. Leak nexthop to maintain guarantee
1944 		 *  that each nhop can be referenced.
1945 		 */
1946 		FD_PRINTF(LOG_ERR, fd, "unable to schedule nhop %p deletion", nh);
1947 	}
1948 }
1949 
1950 static void
1951 fib_unref_nhop(struct fib_data *fd, struct nhop_object *nh)
1952 {
1953 	uint32_t idx = get_nhop_off(fd, nh);
1954 
1955 	KASSERT(idx < fd->number_nhops, ("invalid nhop index"));
1956 	KASSERT(nh == fd->nh_idx[idx], ("index table contains whong nh"));
1957 
1958 	fd->nh_ref_table->refcnt[idx]--;
1959 	if (fd->nh_ref_table->refcnt[idx] == 0) {
1960 		FD_PRINTF(LOG_DEBUG, fd, " FREE nhop %d %p", idx, fd->nh_idx[idx]);
1961 		fib_schedule_release_nhop(fd, fd->nh_idx[idx]);
1962 	}
1963 }
1964 
1965 static void
1966 set_algo_fixed(struct rib_head *rh)
1967 {
1968 	switch (rh->rib_family) {
1969 #ifdef INET
1970 	case AF_INET:
1971 		V_algo_fixed_inet = true;
1972 		break;
1973 #endif
1974 #ifdef INET6
1975 	case AF_INET6:
1976 		V_algo_fixed_inet6 = true;
1977 		break;
1978 #endif
1979 	}
1980 }
1981 
1982 static bool
1983 is_algo_fixed(struct rib_head *rh)
1984 {
1985 
1986 	switch (rh->rib_family) {
1987 #ifdef INET
1988 	case AF_INET:
1989 		return (V_algo_fixed_inet);
1990 #endif
1991 #ifdef INET6
1992 	case AF_INET6:
1993 		return (V_algo_fixed_inet6);
1994 #endif
1995 	}
1996 	return (false);
1997 }
1998 
1999 /*
2000  * Runs the check on what would be the best algo for rib @rh, assuming
2001  *  that the current algo is the one specified by @orig_flm. Note that
2002  *  it can be NULL for initial selection.
2003  *
2004  * Returns referenced new algo or NULL if the current one is the best.
2005  */
2006 static struct fib_lookup_module *
2007 fib_check_best_algo(struct rib_head *rh, struct fib_lookup_module *orig_flm)
2008 {
2009 	uint8_t preference, curr_preference = 0, best_preference = 0;
2010 	struct fib_lookup_module *flm, *best_flm = NULL;
2011 	struct rib_rtable_info rinfo;
2012 	int candidate_algos = 0;
2013 
2014 	fib_get_rtable_info(rh, &rinfo);
2015 
2016 	FIB_MOD_LOCK();
2017 	TAILQ_FOREACH(flm, &all_algo_list, entries) {
2018 		if (flm->flm_family != rh->rib_family)
2019 			continue;
2020 		candidate_algos++;
2021 		preference = flm->flm_get_pref(&rinfo);
2022 		if (preference > best_preference) {
2023 			if (!flm_error_check(flm, rh->rib_fibnum)) {
2024 				best_preference = preference;
2025 				best_flm = flm;
2026 			}
2027 		}
2028 		if (flm == orig_flm)
2029 			curr_preference = preference;
2030 	}
2031 	if ((best_flm != NULL) && (curr_preference + BEST_DIFF_PERCENT < best_preference))
2032 		best_flm->flm_refcount++;
2033 	else
2034 		best_flm = NULL;
2035 	FIB_MOD_UNLOCK();
2036 
2037 	RH_PRINTF(LOG_DEBUG, rh, "candidate_algos: %d, curr: %s(%d) result: %s(%d)",
2038 	    candidate_algos, orig_flm ? orig_flm->flm_name : "NULL", curr_preference,
2039 	    best_flm ? best_flm->flm_name : (orig_flm ? orig_flm->flm_name : "NULL"),
2040 	    best_preference);
2041 
2042 	return (best_flm);
2043 }
2044 
2045 /*
2046  * Called when new route table is created.
2047  * Selects, allocates and attaches fib algo for the table.
2048  */
2049 static bool
2050 fib_select_algo_initial(struct rib_head *rh, struct fib_dp *dp)
2051 {
2052 	struct fib_lookup_module *flm;
2053 	struct fib_data *fd = NULL;
2054 	enum flm_op_result result;
2055 	struct epoch_tracker et;
2056 
2057 	flm = fib_check_best_algo(rh, NULL);
2058 	if (flm == NULL) {
2059 		RH_PRINTF(LOG_CRIT, rh, "no algo selected");
2060 		return (false);
2061 	}
2062 	RH_PRINTF(LOG_INFO, rh, "selected algo %s", flm->flm_name);
2063 
2064 	NET_EPOCH_ENTER(et);
2065 	RIB_WLOCK(rh);
2066 	result = setup_fd_instance(flm, rh, NULL, &fd, false);
2067 	RIB_WUNLOCK(rh);
2068 	NET_EPOCH_EXIT(et);
2069 
2070 	RH_PRINTF(LOG_DEBUG, rh, "result=%d fd=%p", result, fd);
2071 	if (result == FLM_SUCCESS)
2072 		*dp = fd->fd_dp;
2073 	else
2074 		RH_PRINTF(LOG_CRIT, rh, "unable to setup algo %s", flm->flm_name);
2075 
2076 	fib_unref_algo(flm);
2077 
2078 	return (result == FLM_SUCCESS);
2079 }
2080 
2081 /*
2082  * Sets up fib algo instances for the non-initialized RIBs in the @family.
2083  * Allocates temporary datapath index to amortize datapaint index updates
2084  * with large @num_tables.
2085  */
2086 void
2087 fib_setup_family(int family, uint32_t num_tables)
2088 {
2089 	struct fib_dp_header *new_fdh = alloc_fib_dp_array(num_tables, false);
2090 	if (new_fdh == NULL) {
2091 		ALGO_PRINTF(LOG_CRIT, "Unable to setup framework for %s", print_family(family));
2092 		return;
2093 	}
2094 
2095 	for (int i = 0; i < num_tables; i++) {
2096 		struct rib_head *rh = rt_tables_get_rnh(i, family);
2097 		if (rh->rib_algo_init)
2098 			continue;
2099 		if (!fib_select_algo_initial(rh, &new_fdh->fdh_idx[i]))
2100 			continue;
2101 
2102 		rh->rib_algo_init = true;
2103 	}
2104 
2105 	FIB_MOD_LOCK();
2106 	struct fib_dp **pdp = get_family_dp_ptr(family);
2107 	struct fib_dp_header *old_fdh = get_fib_dp_header(*pdp);
2108 
2109 	/* Update the items not touched by the new init, from the old data pointer */
2110 	for (int i = 0; i < num_tables; i++) {
2111 		if (new_fdh->fdh_idx[i].f == dummy_lookup)
2112 			new_fdh->fdh_idx[i] = old_fdh->fdh_idx[i];
2113 	}
2114 
2115 	/* Ensure all index writes have completed */
2116 	atomic_thread_fence_rel();
2117 	/* Set new datapath pointer */
2118 	*pdp = &new_fdh->fdh_idx[0];
2119 
2120 	FIB_MOD_UNLOCK();
2121 
2122 	fib_epoch_call(destroy_fdh_epoch, &old_fdh->fdh_epoch_ctx);
2123 }
2124 
2125 /*
2126  * Registers fib lookup module within the subsystem.
2127  */
2128 int
2129 fib_module_register(struct fib_lookup_module *flm)
2130 {
2131 
2132 	FIB_MOD_LOCK();
2133 	ALGO_PRINTF(LOG_INFO, "attaching %s to %s", flm->flm_name,
2134 	    print_family(flm->flm_family));
2135 	TAILQ_INSERT_TAIL(&all_algo_list, flm, entries);
2136 	FIB_MOD_UNLOCK();
2137 
2138 	return (0);
2139 }
2140 
2141 /*
2142  * Tries to unregister fib lookup module.
2143  *
2144  * Returns 0 on success, EBUSY if module is still used
2145  *  by some of the tables.
2146  */
2147 int
2148 fib_module_unregister(struct fib_lookup_module *flm)
2149 {
2150 
2151 	FIB_MOD_LOCK();
2152 	if (flm->flm_refcount > 0) {
2153 		FIB_MOD_UNLOCK();
2154 		return (EBUSY);
2155 	}
2156 	fib_error_clear_flm(flm);
2157 	ALGO_PRINTF(LOG_INFO, "detaching %s from %s", flm->flm_name,
2158 	    print_family(flm->flm_family));
2159 	TAILQ_REMOVE(&all_algo_list, flm, entries);
2160 	FIB_MOD_UNLOCK();
2161 
2162 	return (0);
2163 }
2164 
2165 void
2166 vnet_fib_init(void)
2167 {
2168 
2169 	TAILQ_INIT(&V_fib_data_list);
2170 }
2171 
2172 void
2173 vnet_fib_destroy(void)
2174 {
2175 
2176 	FIB_MOD_LOCK();
2177 	fib_error_clear();
2178 	FIB_MOD_UNLOCK();
2179 }
2180