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