xref: /freebsd-src/sys/net/route/route_tables.c (revision 12b2d68bed37e379929cd9b5e0afe34c387be360)
1f5247a23SAlexander V. Chernikov /*-
2f5247a23SAlexander V. Chernikov  * SPDX-License-Identifier: BSD-3-Clause
3f5247a23SAlexander V. Chernikov  *
4f5247a23SAlexander V. Chernikov  * Copyright (c) 1980, 1986, 1991, 1993
5f5247a23SAlexander V. Chernikov  *	The Regents of the University of California.  All rights reserved.
6f5247a23SAlexander V. Chernikov  *
7f5247a23SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
8f5247a23SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
9f5247a23SAlexander V. Chernikov  * are met:
10f5247a23SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
11f5247a23SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
12f5247a23SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
13f5247a23SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
14f5247a23SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
15f5247a23SAlexander V. Chernikov  * 3. Neither the name of the University nor the names of its contributors
16f5247a23SAlexander V. Chernikov  *    may be used to endorse or promote products derived from this software
17f5247a23SAlexander V. Chernikov  *    without specific prior written permission.
18f5247a23SAlexander V. Chernikov  *
19f5247a23SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20f5247a23SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21f5247a23SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22f5247a23SAlexander V. Chernikov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23f5247a23SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24f5247a23SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25f5247a23SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26f5247a23SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27f5247a23SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28f5247a23SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f5247a23SAlexander V. Chernikov  * SUCH DAMAGE.
30f5247a23SAlexander V. Chernikov  */
31f5247a23SAlexander V. Chernikov /************************************************************************
32f5247a23SAlexander V. Chernikov  * Note: In this file a 'fib' is a "forwarding information base"	*
33f5247a23SAlexander V. Chernikov  * Which is the new name for an in kernel routing (next hop) table.	*
34f5247a23SAlexander V. Chernikov  ***********************************************************************/
35f5247a23SAlexander V. Chernikov 
36f5247a23SAlexander V. Chernikov #include <sys/cdefs.h>
37f5247a23SAlexander V. Chernikov #include "opt_route.h"
38f5247a23SAlexander V. Chernikov 
39f5247a23SAlexander V. Chernikov #include <sys/param.h>
40f5247a23SAlexander V. Chernikov #include <sys/socket.h>
41f5247a23SAlexander V. Chernikov #include <sys/systm.h>
42f5247a23SAlexander V. Chernikov #include <sys/malloc.h>
43f5247a23SAlexander V. Chernikov #include <sys/jail.h>
4469e7d9b7SAlexander V. Chernikov #include <sys/osd.h>
45c93d310fSMateusz Guzik #include <sys/proc.h>
46f5247a23SAlexander V. Chernikov #include <sys/sysctl.h>
47f5247a23SAlexander V. Chernikov #include <sys/syslog.h>
48f5247a23SAlexander V. Chernikov #include <sys/kernel.h>
49f5247a23SAlexander V. Chernikov #include <sys/lock.h>
50f5247a23SAlexander V. Chernikov #include <sys/sx.h>
51f5247a23SAlexander V. Chernikov #include <sys/domain.h>
52f5247a23SAlexander V. Chernikov #include <sys/sysproto.h>
53f5247a23SAlexander V. Chernikov 
54f5247a23SAlexander V. Chernikov #include <net/vnet.h>
55f5247a23SAlexander V. Chernikov #include <net/route.h>
56fd1aa866SAlexander V. Chernikov #include <net/route/route_ctl.h>
57f5247a23SAlexander V. Chernikov #include <net/route/route_var.h>
58f5247a23SAlexander V. Chernikov 
59f5247a23SAlexander V. Chernikov /* Kernel config default option. */
60f5247a23SAlexander V. Chernikov #ifdef ROUTETABLES
61f5247a23SAlexander V. Chernikov #if ROUTETABLES <= 0
62f5247a23SAlexander V. Chernikov #error "ROUTETABLES defined too low"
63f5247a23SAlexander V. Chernikov #endif
64f5247a23SAlexander V. Chernikov #if ROUTETABLES > RT_MAXFIBS
65f5247a23SAlexander V. Chernikov #error "ROUTETABLES defined too big"
66f5247a23SAlexander V. Chernikov #endif
67f5247a23SAlexander V. Chernikov #define	RT_NUMFIBS	ROUTETABLES
68f5247a23SAlexander V. Chernikov #endif /* ROUTETABLES */
69f5247a23SAlexander V. Chernikov /* Initialize to default if not otherwise set. */
70f5247a23SAlexander V. Chernikov #ifndef	RT_NUMFIBS
71f5247a23SAlexander V. Chernikov #define	RT_NUMFIBS	1
72f5247a23SAlexander V. Chernikov #endif
73f5247a23SAlexander V. Chernikov 
74f5247a23SAlexander V. Chernikov static void grow_rtables(uint32_t num_fibs);
75f5247a23SAlexander V. Chernikov 
76f5247a23SAlexander V. Chernikov VNET_DEFINE_STATIC(struct sx, rtables_lock);
77f5247a23SAlexander V. Chernikov #define	V_rtables_lock		VNET(rtables_lock)
78f5247a23SAlexander V. Chernikov #define	RTABLES_LOCK()		sx_xlock(&V_rtables_lock)
79f5247a23SAlexander V. Chernikov #define	RTABLES_UNLOCK()	sx_xunlock(&V_rtables_lock)
80f5247a23SAlexander V. Chernikov #define	RTABLES_LOCK_INIT()	sx_init(&V_rtables_lock, "rtables lock")
81f5247a23SAlexander V. Chernikov #define	RTABLES_LOCK_ASSERT()	sx_assert(&V_rtables_lock, SA_LOCKED)
82f5247a23SAlexander V. Chernikov 
83f5247a23SAlexander V. Chernikov VNET_DEFINE_STATIC(struct rib_head **, rt_tables);
84f5247a23SAlexander V. Chernikov #define	V_rt_tables	VNET(rt_tables)
85f5247a23SAlexander V. Chernikov 
86f5247a23SAlexander V. Chernikov VNET_DEFINE(uint32_t, _rt_numfibs) = RT_NUMFIBS;
87f5247a23SAlexander V. Chernikov 
88f5247a23SAlexander V. Chernikov /*
89f5247a23SAlexander V. Chernikov  * Handler for net.my_fibnum.
90f5247a23SAlexander V. Chernikov  * Returns current fib of the process.
91f5247a23SAlexander V. Chernikov  */
92f5247a23SAlexander V. Chernikov static int
93f5247a23SAlexander V. Chernikov sysctl_my_fibnum(SYSCTL_HANDLER_ARGS)
94f5247a23SAlexander V. Chernikov {
95f5247a23SAlexander V. Chernikov         int fibnum;
96f5247a23SAlexander V. Chernikov         int error;
97f5247a23SAlexander V. Chernikov 
98f5247a23SAlexander V. Chernikov         fibnum = curthread->td_proc->p_fibnum;
99f5247a23SAlexander V. Chernikov         error = sysctl_handle_int(oidp, &fibnum, 0, req);
100f5247a23SAlexander V. Chernikov         return (error);
101f5247a23SAlexander V. Chernikov }
102f5247a23SAlexander V. Chernikov SYSCTL_PROC(_net, OID_AUTO, my_fibnum,
103f5247a23SAlexander V. Chernikov     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
104f5247a23SAlexander V. Chernikov     &sysctl_my_fibnum, "I",
105f5247a23SAlexander V. Chernikov     "default FIB of caller");
106f5247a23SAlexander V. Chernikov 
107f5247a23SAlexander V. Chernikov static uint32_t
108f5247a23SAlexander V. Chernikov normalize_num_rtables(uint32_t num_rtables)
109f5247a23SAlexander V. Chernikov {
110f5247a23SAlexander V. Chernikov 
111f5247a23SAlexander V. Chernikov 	if (num_rtables > RT_MAXFIBS)
112f5247a23SAlexander V. Chernikov 		num_rtables = RT_MAXFIBS;
113f5247a23SAlexander V. Chernikov 	else if (num_rtables == 0)
114f5247a23SAlexander V. Chernikov 		num_rtables = 1;
115f5247a23SAlexander V. Chernikov 	return (num_rtables);
116f5247a23SAlexander V. Chernikov }
117f5247a23SAlexander V. Chernikov 
118f5247a23SAlexander V. Chernikov /*
119f5247a23SAlexander V. Chernikov  * Sets the number of fibs in the current vnet.
120f5247a23SAlexander V. Chernikov  * Function does not allow shrinking number of rtables.
121f5247a23SAlexander V. Chernikov  */
122f5247a23SAlexander V. Chernikov static int
123f5247a23SAlexander V. Chernikov sysctl_fibs(SYSCTL_HANDLER_ARGS)
124f5247a23SAlexander V. Chernikov {
125f5247a23SAlexander V. Chernikov 	uint32_t new_fibs;
126f5247a23SAlexander V. Chernikov 	int error;
127f5247a23SAlexander V. Chernikov 
128f5247a23SAlexander V. Chernikov 	RTABLES_LOCK();
129f5247a23SAlexander V. Chernikov 	new_fibs = V_rt_numfibs;
130f5247a23SAlexander V. Chernikov 	error = sysctl_handle_32(oidp, &new_fibs, 0, req);
131f5247a23SAlexander V. Chernikov 	if (error == 0) {
132f5247a23SAlexander V. Chernikov 		new_fibs = normalize_num_rtables(new_fibs);
133f5247a23SAlexander V. Chernikov 
134f5247a23SAlexander V. Chernikov 		if (new_fibs < V_rt_numfibs)
135f5247a23SAlexander V. Chernikov 			error = ENOTCAPABLE;
136f5247a23SAlexander V. Chernikov 		if (new_fibs > V_rt_numfibs)
137f5247a23SAlexander V. Chernikov 			grow_rtables(new_fibs);
138f5247a23SAlexander V. Chernikov 	}
139f5247a23SAlexander V. Chernikov 	RTABLES_UNLOCK();
140f5247a23SAlexander V. Chernikov 
141f5247a23SAlexander V. Chernikov 	return (error);
142f5247a23SAlexander V. Chernikov }
143f5247a23SAlexander V. Chernikov SYSCTL_PROC(_net, OID_AUTO, fibs,
144cd6298d5SAlexander V. Chernikov     CTLFLAG_VNET | CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE,
145cd6298d5SAlexander V. Chernikov     NULL, 0, &sysctl_fibs, "IU",
146f5247a23SAlexander V. Chernikov     "set number of fibs");
147f5247a23SAlexander V. Chernikov 
148f5247a23SAlexander V. Chernikov /*
149f5247a23SAlexander V. Chernikov  * Sets fib of a current process.
150f5247a23SAlexander V. Chernikov  */
151f5247a23SAlexander V. Chernikov int
152f5247a23SAlexander V. Chernikov sys_setfib(struct thread *td, struct setfib_args *uap)
153f5247a23SAlexander V. Chernikov {
154f5247a23SAlexander V. Chernikov 	int error = 0;
155f5247a23SAlexander V. Chernikov 
156f5247a23SAlexander V. Chernikov 	CURVNET_SET(TD_TO_VNET(td));
157f5247a23SAlexander V. Chernikov 	if (uap->fibnum >= 0 && uap->fibnum < V_rt_numfibs)
158f5247a23SAlexander V. Chernikov 		td->td_proc->p_fibnum = uap->fibnum;
159f5247a23SAlexander V. Chernikov 	else
160f5247a23SAlexander V. Chernikov 		error = EINVAL;
161f5247a23SAlexander V. Chernikov 	CURVNET_RESTORE();
162f5247a23SAlexander V. Chernikov 
163f5247a23SAlexander V. Chernikov 	return (error);
164f5247a23SAlexander V. Chernikov }
165f5247a23SAlexander V. Chernikov 
16669e7d9b7SAlexander V. Chernikov static int
16769e7d9b7SAlexander V. Chernikov rtables_check_proc_fib(void *obj, void *data)
16869e7d9b7SAlexander V. Chernikov {
16969e7d9b7SAlexander V. Chernikov 	struct prison *pr = obj;
17069e7d9b7SAlexander V. Chernikov 	struct thread *td = data;
17169e7d9b7SAlexander V. Chernikov 	int error = 0;
17269e7d9b7SAlexander V. Chernikov 
17369e7d9b7SAlexander V. Chernikov 	if (TD_TO_VNET(td) != pr->pr_vnet) {
17469e7d9b7SAlexander V. Chernikov 		/* number of fibs may be lower in a new vnet */
17569e7d9b7SAlexander V. Chernikov 		CURVNET_SET(pr->pr_vnet);
17669e7d9b7SAlexander V. Chernikov 		if (td->td_proc->p_fibnum >= V_rt_numfibs)
17769e7d9b7SAlexander V. Chernikov 			error = EINVAL;
17869e7d9b7SAlexander V. Chernikov 		CURVNET_RESTORE();
17969e7d9b7SAlexander V. Chernikov 	}
18069e7d9b7SAlexander V. Chernikov 	return (error);
18169e7d9b7SAlexander V. Chernikov }
18269e7d9b7SAlexander V. Chernikov 
18369e7d9b7SAlexander V. Chernikov static void
18469e7d9b7SAlexander V. Chernikov rtables_prison_destructor(void *data)
18569e7d9b7SAlexander V. Chernikov {
18669e7d9b7SAlexander V. Chernikov }
18769e7d9b7SAlexander V. Chernikov 
18869e7d9b7SAlexander V. Chernikov static void
18969e7d9b7SAlexander V. Chernikov rtables_init(void)
19069e7d9b7SAlexander V. Chernikov {
19169e7d9b7SAlexander V. Chernikov 	osd_method_t methods[PR_MAXMETHOD] = {
19269e7d9b7SAlexander V. Chernikov 	    [PR_METHOD_ATTACH] =	rtables_check_proc_fib,
19369e7d9b7SAlexander V. Chernikov 	};
19469e7d9b7SAlexander V. Chernikov 	osd_jail_register(rtables_prison_destructor, methods);
19569e7d9b7SAlexander V. Chernikov }
19669e7d9b7SAlexander V. Chernikov SYSINIT(rtables_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rtables_init, NULL);
19769e7d9b7SAlexander V. Chernikov 
19869e7d9b7SAlexander V. Chernikov 
199f5247a23SAlexander V. Chernikov /*
20040503b79SAlexander V. Chernikov  * If required, copy interface routes from existing tables to the
20140503b79SAlexander V. Chernikov  * newly-created routing table.
20240503b79SAlexander V. Chernikov  */
20340503b79SAlexander V. Chernikov static void
20440503b79SAlexander V. Chernikov populate_kernel_routes(struct rib_head **new_rt_tables, struct rib_head *rh)
20540503b79SAlexander V. Chernikov {
20640503b79SAlexander V. Chernikov 	for (int i = 0; i < V_rt_numfibs; i++) {
20740503b79SAlexander V. Chernikov 		struct rib_head *rh_src = new_rt_tables[i * (AF_MAX + 1) + rh->rib_family];
20840503b79SAlexander V. Chernikov 		if ((rh_src != NULL) && (rh_src != rh))
20940503b79SAlexander V. Chernikov 			rib_copy_kernel_routes(rh_src, rh);
21040503b79SAlexander V. Chernikov 	}
21140503b79SAlexander V. Chernikov }
21240503b79SAlexander V. Chernikov 
21340503b79SAlexander V. Chernikov /*
214f5247a23SAlexander V. Chernikov  * Grows up the number of routing tables in the current fib.
215f5247a23SAlexander V. Chernikov  * Function creates new index array for all rtables and allocates
216f5247a23SAlexander V. Chernikov  *  remaining routing tables.
217f5247a23SAlexander V. Chernikov  */
218f5247a23SAlexander V. Chernikov static void
219f5247a23SAlexander V. Chernikov grow_rtables(uint32_t num_tables)
220f5247a23SAlexander V. Chernikov {
221f5247a23SAlexander V. Chernikov 	struct domain *dom;
222f5baf8bbSAlexander V. Chernikov 	struct rib_head **prnh, *rh;
223f5247a23SAlexander V. Chernikov 	struct rib_head **new_rt_tables, **old_rt_tables;
224f5247a23SAlexander V. Chernikov 	int family;
225f5247a23SAlexander V. Chernikov 
226f5247a23SAlexander V. Chernikov 	RTABLES_LOCK_ASSERT();
227f5247a23SAlexander V. Chernikov 
228f5247a23SAlexander V. Chernikov 	KASSERT(num_tables >= V_rt_numfibs, ("num_tables(%u) < rt_numfibs(%u)\n",
229f5247a23SAlexander V. Chernikov 				num_tables, V_rt_numfibs));
230f5247a23SAlexander V. Chernikov 
231f5247a23SAlexander V. Chernikov 	new_rt_tables = mallocarray(num_tables * (AF_MAX + 1), sizeof(void *),
232f5247a23SAlexander V. Chernikov 	    M_RTABLE, M_WAITOK | M_ZERO);
233f5247a23SAlexander V. Chernikov 
234f5baf8bbSAlexander V. Chernikov #ifdef FIB_ALGO
235f5baf8bbSAlexander V. Chernikov 	fib_grow_rtables(num_tables);
236f5baf8bbSAlexander V. Chernikov #endif
237f5baf8bbSAlexander V. Chernikov 
238f5247a23SAlexander V. Chernikov 	/*
239f5247a23SAlexander V. Chernikov 	 * Current rt_tables layout:
240f5247a23SAlexander V. Chernikov 	 * fib0[af0, af1, af2, .., AF_MAX]fib1[af0, af1, af2, .., Af_MAX]..
241f5247a23SAlexander V. Chernikov 	 * this allows to copy existing tables data by using memcpy()
242f5247a23SAlexander V. Chernikov 	 */
243f5247a23SAlexander V. Chernikov 	if (V_rt_tables != NULL)
244f5247a23SAlexander V. Chernikov 		memcpy(new_rt_tables, V_rt_tables,
245f5247a23SAlexander V. Chernikov 		    V_rt_numfibs * (AF_MAX + 1) * sizeof(void *));
246f5247a23SAlexander V. Chernikov 
247f5247a23SAlexander V. Chernikov 	/* Populate the remainders */
248e18c5816SGleb Smirnoff 	SLIST_FOREACH(dom, &domains, dom_next) {
249f5247a23SAlexander V. Chernikov 		if (dom->dom_rtattach == NULL)
250f5247a23SAlexander V. Chernikov 			continue;
251f5247a23SAlexander V. Chernikov 		family = dom->dom_family;
252f5247a23SAlexander V. Chernikov 		for (int i = 0; i < num_tables; i++) {
253f5247a23SAlexander V. Chernikov 			prnh = &new_rt_tables[i * (AF_MAX + 1) + family];
254f5247a23SAlexander V. Chernikov 			if (*prnh != NULL)
255f5247a23SAlexander V. Chernikov 				continue;
256f5baf8bbSAlexander V. Chernikov 			rh = dom->dom_rtattach(i);
257f5baf8bbSAlexander V. Chernikov 			if (rh == NULL)
258f5baf8bbSAlexander V. Chernikov 				log(LOG_ERR, "unable to create routing table for %d.%d\n",
259f5baf8bbSAlexander V. Chernikov 				    dom->dom_family, i);
26040503b79SAlexander V. Chernikov 			else
26140503b79SAlexander V. Chernikov 				populate_kernel_routes(new_rt_tables, rh);
262f5baf8bbSAlexander V. Chernikov 			*prnh = rh;
263f5247a23SAlexander V. Chernikov 		}
264f5247a23SAlexander V. Chernikov 	}
265f5247a23SAlexander V. Chernikov 
266f5247a23SAlexander V. Chernikov 	/*
267f5247a23SAlexander V. Chernikov 	 * Update rtables pointer.
268f5247a23SAlexander V. Chernikov 	 * Ensure all writes to new_rt_tables has been completed before
269f5247a23SAlexander V. Chernikov 	 *  switching pointer.
270f5247a23SAlexander V. Chernikov 	 */
271f5247a23SAlexander V. Chernikov 	atomic_thread_fence_rel();
272f5247a23SAlexander V. Chernikov 	old_rt_tables = V_rt_tables;
273f5247a23SAlexander V. Chernikov 	V_rt_tables = new_rt_tables;
274f5247a23SAlexander V. Chernikov 
275f5247a23SAlexander V. Chernikov 	/* Wait till all cpus see new pointers */
276f5247a23SAlexander V. Chernikov 	atomic_thread_fence_rel();
27773336a6fSZhenlei Huang 	NET_EPOCH_WAIT();
278f5247a23SAlexander V. Chernikov 
2798a0d57baSAlexander V. Chernikov 	/* Set number of fibs to a new value */
280f5247a23SAlexander V. Chernikov 	V_rt_numfibs = num_tables;
281f5247a23SAlexander V. Chernikov 
2828a0d57baSAlexander V. Chernikov #ifdef FIB_ALGO
2838a0d57baSAlexander V. Chernikov 	/* Attach fib algo to the new rtables */
284e18c5816SGleb Smirnoff 	SLIST_FOREACH(dom, &domains, dom_next) {
2858a0d57baSAlexander V. Chernikov 		if (dom->dom_rtattach != NULL)
2868a0d57baSAlexander V. Chernikov 			fib_setup_family(dom->dom_family, num_tables);
2878a0d57baSAlexander V. Chernikov 	}
2888a0d57baSAlexander V. Chernikov #endif
2898a0d57baSAlexander V. Chernikov 
290f5247a23SAlexander V. Chernikov 	if (old_rt_tables != NULL)
291f5247a23SAlexander V. Chernikov 		free(old_rt_tables, M_RTABLE);
292f5247a23SAlexander V. Chernikov }
293f5247a23SAlexander V. Chernikov 
294f5247a23SAlexander V. Chernikov static void
295f5247a23SAlexander V. Chernikov vnet_rtables_init(const void *unused __unused)
296f5247a23SAlexander V. Chernikov {
297f5247a23SAlexander V. Chernikov 	int num_rtables_base;
298f5247a23SAlexander V. Chernikov 
299f5247a23SAlexander V. Chernikov 	if (IS_DEFAULT_VNET(curvnet)) {
300f5247a23SAlexander V. Chernikov 		num_rtables_base = RT_NUMFIBS;
301f5247a23SAlexander V. Chernikov 		TUNABLE_INT_FETCH("net.fibs", &num_rtables_base);
302f5247a23SAlexander V. Chernikov 		V_rt_numfibs = normalize_num_rtables(num_rtables_base);
303f5247a23SAlexander V. Chernikov 	} else
304f5247a23SAlexander V. Chernikov 		V_rt_numfibs = 1;
305f5247a23SAlexander V. Chernikov 
306f5247a23SAlexander V. Chernikov 	vnet_rtzone_init();
307f5baf8bbSAlexander V. Chernikov #ifdef FIB_ALGO
308f5baf8bbSAlexander V. Chernikov 	vnet_fib_init();
309f5baf8bbSAlexander V. Chernikov #endif
310f5247a23SAlexander V. Chernikov 	RTABLES_LOCK_INIT();
311f5247a23SAlexander V. Chernikov 
312f5247a23SAlexander V. Chernikov 	RTABLES_LOCK();
313f5247a23SAlexander V. Chernikov 	grow_rtables(V_rt_numfibs);
314f5247a23SAlexander V. Chernikov 	RTABLES_UNLOCK();
315f5247a23SAlexander V. Chernikov }
316f5247a23SAlexander V. Chernikov VNET_SYSINIT(vnet_rtables_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH,
317*12b2d68bSZhenlei Huang     vnet_rtables_init, NULL);
318f5247a23SAlexander V. Chernikov 
319f5247a23SAlexander V. Chernikov #ifdef VIMAGE
320f5247a23SAlexander V. Chernikov static void
321f5247a23SAlexander V. Chernikov rtables_destroy(const void *unused __unused)
322f5247a23SAlexander V. Chernikov {
323f5247a23SAlexander V. Chernikov 	struct rib_head *rnh;
324f5247a23SAlexander V. Chernikov 	struct domain *dom;
325f5247a23SAlexander V. Chernikov 	int family;
326f5247a23SAlexander V. Chernikov 
327f5247a23SAlexander V. Chernikov 	RTABLES_LOCK();
328e18c5816SGleb Smirnoff 	SLIST_FOREACH(dom, &domains, dom_next) {
329f5247a23SAlexander V. Chernikov 		if (dom->dom_rtdetach == NULL)
330f5247a23SAlexander V. Chernikov 			continue;
331f5247a23SAlexander V. Chernikov 		family = dom->dom_family;
332f5247a23SAlexander V. Chernikov 		for (int i = 0; i < V_rt_numfibs; i++) {
333f5247a23SAlexander V. Chernikov 			rnh = rt_tables_get_rnh(i, family);
334f5247a23SAlexander V. Chernikov 			dom->dom_rtdetach(rnh);
335f5247a23SAlexander V. Chernikov 		}
336f5247a23SAlexander V. Chernikov 	}
337f5247a23SAlexander V. Chernikov 	RTABLES_UNLOCK();
338f5247a23SAlexander V. Chernikov 
339f5247a23SAlexander V. Chernikov 	/*
340f5247a23SAlexander V. Chernikov 	 * dom_rtdetach calls rt_table_destroy(), which
341f5247a23SAlexander V. Chernikov 	 *  schedules deletion for all rtentries, nexthops and control
342f5247a23SAlexander V. Chernikov 	 *  structures. Wait for the destruction callbacks to fire.
343f5247a23SAlexander V. Chernikov 	 * Note that this should result in freeing all rtentries, but
344f5247a23SAlexander V. Chernikov 	 *  nexthops deletions will be scheduled for the next epoch run
345f5247a23SAlexander V. Chernikov 	 *  and will be completed after vnet teardown.
346f5247a23SAlexander V. Chernikov 	 */
347150486f6SZhenlei Huang 	NET_EPOCH_DRAIN_CALLBACKS();
348f5247a23SAlexander V. Chernikov 
349f5247a23SAlexander V. Chernikov 	free(V_rt_tables, M_RTABLE);
350f5247a23SAlexander V. Chernikov 	vnet_rtzone_destroy();
351f5baf8bbSAlexander V. Chernikov #ifdef FIB_ALGO
352f5baf8bbSAlexander V. Chernikov 	vnet_fib_destroy();
353f5baf8bbSAlexander V. Chernikov #endif
354f5247a23SAlexander V. Chernikov }
355f5247a23SAlexander V. Chernikov VNET_SYSUNINIT(rtables_destroy, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
356*12b2d68bSZhenlei Huang     rtables_destroy, NULL);
357f5247a23SAlexander V. Chernikov #endif
358f5247a23SAlexander V. Chernikov 
359f5247a23SAlexander V. Chernikov static inline struct rib_head *
360f5247a23SAlexander V. Chernikov rt_tables_get_rnh_ptr(uint32_t table, sa_family_t family)
361f5247a23SAlexander V. Chernikov {
362f5247a23SAlexander V. Chernikov 	struct rib_head **prnh;
363f5247a23SAlexander V. Chernikov 
364f5247a23SAlexander V. Chernikov 	KASSERT(table < V_rt_numfibs,
365f5247a23SAlexander V. Chernikov 	    ("%s: table out of bounds (%d < %d)", __func__, table,
366f5247a23SAlexander V. Chernikov 	     V_rt_numfibs));
367f5247a23SAlexander V. Chernikov 	KASSERT(family < (AF_MAX + 1),
368f5247a23SAlexander V. Chernikov 	    ("%s: fam out of bounds (%d < %d)", __func__, family, AF_MAX + 1));
369f5247a23SAlexander V. Chernikov 
370f5247a23SAlexander V. Chernikov 	/* rnh is [fib=0][af=0]. */
371f5247a23SAlexander V. Chernikov 	prnh = V_rt_tables;
372f5247a23SAlexander V. Chernikov 	/* Get the offset to the requested table and fam. */
373f5247a23SAlexander V. Chernikov 	prnh += table * (AF_MAX + 1) + family;
374f5247a23SAlexander V. Chernikov 
375f5247a23SAlexander V. Chernikov 	return (*prnh);
376f5247a23SAlexander V. Chernikov }
377f5247a23SAlexander V. Chernikov 
378f5247a23SAlexander V. Chernikov struct rib_head *
379f5247a23SAlexander V. Chernikov rt_tables_get_rnh(uint32_t table, sa_family_t family)
380f5247a23SAlexander V. Chernikov {
381f5247a23SAlexander V. Chernikov 
382f5247a23SAlexander V. Chernikov 	return (rt_tables_get_rnh_ptr(table, family));
383f5247a23SAlexander V. Chernikov }
384f5247a23SAlexander V. Chernikov 
385fd1aa866SAlexander V. Chernikov struct rib_head *
386fd1aa866SAlexander V. Chernikov rt_tables_get_rnh_safe(uint32_t table, sa_family_t family)
387fd1aa866SAlexander V. Chernikov {
388fd1aa866SAlexander V. Chernikov 	if (__predict_false(table >= V_rt_numfibs))
389fd1aa866SAlexander V. Chernikov 		return (NULL);
390fd1aa866SAlexander V. Chernikov 	if (__predict_false(family >= (AF_MAX + 1)))
391fd1aa866SAlexander V. Chernikov 		return (NULL);
392fd1aa866SAlexander V. Chernikov 	return (rt_tables_get_rnh_ptr(table, family));
393fd1aa866SAlexander V. Chernikov }
394fd1aa866SAlexander V. Chernikov 
395f5247a23SAlexander V. Chernikov u_int
396f5247a23SAlexander V. Chernikov rt_tables_get_gen(uint32_t table, sa_family_t family)
397f5247a23SAlexander V. Chernikov {
398f5247a23SAlexander V. Chernikov 	struct rib_head *rnh;
399f5247a23SAlexander V. Chernikov 
400f5247a23SAlexander V. Chernikov 	rnh = rt_tables_get_rnh_ptr(table, family);
401f5247a23SAlexander V. Chernikov 	KASSERT(rnh != NULL, ("%s: NULL rib_head pointer table %d family %d",
402f5247a23SAlexander V. Chernikov 	    __func__, table, family));
403f5247a23SAlexander V. Chernikov 	return (rnh->rnh_gen);
404f5247a23SAlexander V. Chernikov }
405