Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -4107,6 +4107,7 @@ netgraph_sppp net/toeplitz.c optional inet rss | inet6 rss net/vnet.c optional vimage +net/vnet_support.c standard net80211/ieee80211.c optional wlan net80211/ieee80211_acl.c optional wlan wlan_acl net80211/ieee80211_action.c optional wlan Index: sys/net/vnet.h =================================================================== --- sys/net/vnet.h +++ sys/net/vnet.h @@ -88,6 +88,13 @@ #ifdef _KERNEL +/* + * Indicates whether this kernel was configured with vnet support or not. + * This will generally be used so that untied modules can do the right thing + * based on the linked-in kernel. + */ +extern const int vimage_configured; + #define VNET_PCPUSTAT_DECLARE(type, name) \ VNET_DECLARE(counter_u64_t, name[sizeof(type) / sizeof(uint64_t)]) @@ -145,6 +152,50 @@ NULL, 0, array ## _sysctl, "I", desc) #endif /* SYSCTL_OID */ +/* + * Virtual sysinit mechanism, allowing network stack components to declare + * startup and shutdown methods to be run when virtual network stack + * instances are created and destroyed. + */ +#include + +/* + * SYSINIT/SYSUNINIT variants that provide per-vnet constructors and + * destructors. + */ +struct vnet_sysinit { + enum sysinit_sub_id subsystem; + enum sysinit_elem_order order; + sysinit_cfunc_t func; + const void *arg; + TAILQ_ENTRY(vnet_sysinit) link; +}; + + +/* vnet_support shims */ +void vnet_dynamic_register_sysinit(void *arg); +void vnet_dynamic_register_sysuninit(void *arg); +void vnet_dynamic_deregister_sysinit(void *arg); +void vnet_dynamic_deregister_sysuninit(void *arg); + +/* + * Virtual network stack allocator interfaces from the kernel linker. + */ +void *vnet_data_alloc(int size); +void vnet_data_copy(void *start, int size); +void vnet_data_free(void *start_arg, int size); + +#define VNET_NAME(n) vnet_entry_##n + +#if defined(KLD_MODULE) && !defined(KLD_TIED) && !defined(VIMAGE) +/* + * For independent module builds, we trigger a version of VIMAGE macros that + * resolve safely (but slowly) based on vimage_configured. + */ +#define VIMAGE 1 +#define VIMAGE_RUNTIME 1 +#endif + #ifdef VIMAGE #include #include /* for struct thread */ @@ -188,40 +239,88 @@ } while (0) #endif +#ifdef VIMAGE_RUNTIME +/* + * This should be used for things that need VNET_ASSERT that shouldn't panic + * if the underlying kernel wasn't compiled with VIMAGE. If we're not dealing + * with a kmod, or if we're unconditionally compiled with VIMAGE, this is a + * direct VNET_ASSERT. + */ +#define VNET_RUNTIME_ASSERT(exp, msg) do { \ + if (vimage_configured) \ + VNET_ASSERT(exp, msg); \ +} while (0) + +#define _CURVNET_SET_LPUSH(arg) \ + if (vimage_configured) { \ + curvnet = arg; \ + curthread->td_vnet_lpush = __func__; \ + } + +#define _CURVNET_SET(arg) \ + if (vimage_configured) \ + curvnet = arg; +#define _CURVNET_RESTORE_LPUSH() \ + if (vimage_configured) { \ + curvnet = saved_vnet; \ + curthread->td_vnet_lpush = saved_vnet_lpush; \ + } +#define _CURVNET_RESTORE() \ + if (vimage_configured) \ + curvnet = saved_vnet; +#else +#define VNET_RUNTIME_ASSERT(exp, msg) VNET_ASSERT(exp, msg) + +#define _CURVNET_SET_LPUSH(arg) \ + curvnet = arg; \ + curthread->td_vnet_lpush = __func__; +#define _CURVNET_SET(arg) \ + curvnet = arg; +#define _CURVNET_RESTORE_LPUSH() \ + curvnet = saved_vnet; \ + curthread->td_vnet_lpush = saved_vnet_lpush; +#define _CURVNET_RESTORE() \ + curvnet = saved_vnet; +#endif + #ifdef VNET_DEBUG void vnet_log_recursion(struct vnet *, const char *, int); #define CURVNET_SET_QUIET(arg) \ - VNET_ASSERT((arg) != NULL && (arg)->vnet_magic_n == VNET_MAGIC_N, \ + VNET_RUNTIME_ASSERT((arg) != NULL && \ + (arg)->vnet_magic_n == VNET_MAGIC_N, \ ("CURVNET_SET at %s:%d %s() curvnet=%p vnet=%p", \ __FILE__, __LINE__, __func__, curvnet, (arg))); \ struct vnet *saved_vnet = curvnet; \ const char *saved_vnet_lpush = curthread->td_vnet_lpush; \ - curvnet = arg; \ - curthread->td_vnet_lpush = __func__; + _CURVNET_SET_LPUSH(arg); #define CURVNET_SET_VERBOSE(arg) \ CURVNET_SET_QUIET(arg) \ - if (saved_vnet) \ + if (saved_vnet && vimage_configured) \ vnet_log_recursion(saved_vnet, saved_vnet_lpush, __LINE__); #define CURVNET_SET(arg) CURVNET_SET_VERBOSE(arg) #define CURVNET_RESTORE() \ - VNET_ASSERT(curvnet != NULL && (saved_vnet == NULL || \ + VNET_RUNTIME_ASSERT(curvnet != NULL && (saved_vnet == NULL || \ saved_vnet->vnet_magic_n == VNET_MAGIC_N), \ ("CURVNET_RESTORE at %s:%d %s() curvnet=%p saved_vnet=%p", \ __FILE__, __LINE__, __func__, curvnet, saved_vnet)); \ - curvnet = saved_vnet; \ - curthread->td_vnet_lpush = saved_vnet_lpush; + _CURVNET_RESTORE_LPUSH(); + if (vimage_configured) { \ + curvnet = saved_vnet; \ + curthread->td_vnet_lpush = saved_vnet_lpush; \ + } #else /* !VNET_DEBUG */ #define CURVNET_SET_QUIET(arg) \ - VNET_ASSERT((arg) != NULL && (arg)->vnet_magic_n == VNET_MAGIC_N, \ + VNET_RUNTIME_ASSERT((arg) != NULL && \ + (arg)->vnet_magic_n == VNET_MAGIC_N, \ ("CURVNET_SET at %s:%d %s() curvnet=%p vnet=%p", \ __FILE__, __LINE__, __func__, curvnet, (arg))); \ struct vnet *saved_vnet = curvnet; \ - curvnet = arg; + _CURVNET_SET(arg); #define CURVNET_SET_VERBOSE(arg) \ CURVNET_SET_QUIET(arg) @@ -229,15 +328,19 @@ #define CURVNET_SET(arg) CURVNET_SET_VERBOSE(arg) #define CURVNET_RESTORE() \ - VNET_ASSERT(curvnet != NULL && (saved_vnet == NULL || \ + VNET_RUNTIME_ASSERT(curvnet != NULL && (saved_vnet == NULL || \ saved_vnet->vnet_magic_n == VNET_MAGIC_N), \ ("CURVNET_RESTORE at %s:%d %s() curvnet=%p saved_vnet=%p", \ __FILE__, __LINE__, __func__, curvnet, saved_vnet)); \ - curvnet = saved_vnet; + _CURVNET_RESTORE(); #endif /* VNET_DEBUG */ extern struct vnet *vnet0; +#ifdef VIMAGE_RUNTIME +#define IS_DEFAULT_VNET(arg) (vimage_configured && (arg) == vnet0) +#else #define IS_DEFAULT_VNET(arg) ((arg) == vnet0) +#endif #define CRED_TO_VNET(cr) (cr)->cr_prison->pr_vnet #define TD_TO_VNET(td) CRED_TO_VNET((td)->td_ucred) @@ -253,22 +356,45 @@ extern struct rwlock vnet_rwlock; extern struct sx vnet_sxlock; +#ifdef VIMAGE_RUNTIME +#define VNET_LIST_RLOCK() do { \ + if (vimage_configured) \ + sx_slock(&vnet_sxlock) \ +} while(0); +#define VNET_LIST_RLOCK_NOSLEEP() do { \ + if (vimage_configured) \ + rw_rlock(&vnet_rwlock) \ +} while(0); +#define VNET_LIST_RUNLOCK() do { \ + if (vimage_configured) \ + sx_sunlock(&vnet_sxlock) \ +} while(0); +#define VNET_LIST_RUNLOCK_NOSLEEP() do { \ + if (vimage_configured) \ + rw_runlock(&vnet_rwlock) \ +} while(0); +#else #define VNET_LIST_RLOCK() sx_slock(&vnet_sxlock) #define VNET_LIST_RLOCK_NOSLEEP() rw_rlock(&vnet_rwlock) #define VNET_LIST_RUNLOCK() sx_sunlock(&vnet_sxlock) #define VNET_LIST_RUNLOCK_NOSLEEP() rw_runlock(&vnet_rwlock) +#endif /* * Iteration macros to walk the global list of virtual network stacks. */ #define VNET_ITERATOR_DECL(arg) struct vnet *arg +#ifdef VIMAGE_RUNTIME +#define VNET_FOREACH(arg) if (vimage_configured) \ + LIST_FOREACH((arg), &vnet_head, vnet_le) +#else #define VNET_FOREACH(arg) LIST_FOREACH((arg), &vnet_head, vnet_le) +#endif /* * Virtual network stack memory allocator, which allows global variables to * be automatically instantiated for each network stack instance. */ -#define VNET_NAME(n) vnet_entry_##n #define VNET_DECLARE(t, n) extern t VNET_NAME(n) /* struct _hack is to stop this from being used with static data */ #define VNET_DEFINE(t, n) \ @@ -295,34 +421,32 @@ #define VNET_VNET_PTR(vnet, n) _VNET_PTR((vnet)->vnet_data_base, n) #define VNET_VNET(vnet, n) (*VNET_VNET_PTR((vnet), n)) +#ifdef VIMAGE_RUNTIME +#define VNET_PTR(n) \ + *(vimage_configured ? &VNET_VNET_PTR(curvnet, n) : &&(VNET_NAME(n))) +#define VNET(n) \ + *(vimage_configured ? &VNET_VNET(curvnet, n) : &(VNET_NAME(n))) +#else #define VNET_PTR(n) VNET_VNET_PTR(curvnet, n) #define VNET(n) VNET_VNET(curvnet, n) +#endif +#ifdef VIMAGE_RUNTIME /* - * Virtual network stack allocator interfaces from the kernel linker. - */ -void *vnet_data_alloc(int size); -void vnet_data_copy(void *start, int size); -void vnet_data_free(void *start_arg, int size); - -/* - * Virtual sysinit mechanism, allowing network stack components to declare - * startup and shutdown methods to be run when virtual network stack - * instances are created and destroyed. - */ -#include - -/* - * SYSINIT/SYSUNINIT variants that provide per-vnet constructors and - * destructors. + * These are provided by vnet_support.c and determine if they should invoke + * the SYSINIT/SYSUNINIT callbacks directly or instead dispatch the request + * through to the underlying vnet_{,de}register_* versions. */ -struct vnet_sysinit { - enum sysinit_sub_id subsystem; - enum sysinit_elem_order order; - sysinit_cfunc_t func; - const void *arg; - TAILQ_ENTRY(vnet_sysinit) link; -}; +#define _vnet_register_sysinit vnet_dynamic_register_sysinit +#define _vnet_deregister_sysinit vnet_dynamic_deregister_sysinit +#define _vnet_register_sysuninit vnet_dynamic_register_sysuninit +#define _vnet_deregister_sysuninit vnet_dynamic_deregister_sysuninit +#else +#define _vnet_register_sysinit vnet_register_sysinit +#define _vnet_deregister_sysinit vnet_deregister_sysinit +#define _vnet_register_sysuninit vnet_register_sysuninit +#define _vnet_deregister_sysuninit vnet_deregister_sysuninit +#endif #define VNET_SYSINIT(ident, subsystem, order, func, arg) \ static struct vnet_sysinit ident ## _vnet_init = { \ @@ -332,9 +456,9 @@ (arg) \ }; \ SYSINIT(vnet_init_ ## ident, subsystem, order, \ - vnet_register_sysinit, &ident ## _vnet_init); \ + _vnet_register_sysinit, &ident ## _vnet_init); \ SYSUNINIT(vnet_init_ ## ident, subsystem, order, \ - vnet_deregister_sysinit, &ident ## _vnet_init) + _vnet_deregister_sysinit, &ident ## _vnet_init) #define VNET_SYSUNINIT(ident, subsystem, order, func, arg) \ static struct vnet_sysinit ident ## _vnet_uninit = { \ @@ -344,9 +468,9 @@ (arg) \ }; \ SYSINIT(vnet_uninit_ ## ident, subsystem, order, \ - vnet_register_sysuninit, &ident ## _vnet_uninit); \ + _vnet_register_sysuninit, &ident ## _vnet_uninit); \ SYSUNINIT(vnet_uninit_ ## ident, subsystem, order, \ - vnet_deregister_sysuninit, &ident ## _vnet_uninit) + _vnet_deregister_sysuninit, &ident ## _vnet_uninit) /* * Run per-vnet sysinits or sysuninits during vnet creation/destruction. @@ -370,18 +494,24 @@ void vnet_global_eventhandler_iterator_func(void *, ...); #define VNET_GLOBAL_EVENTHANDLER_REGISTER_TAG(tag, name, func, arg, priority) \ do { \ - if (IS_DEFAULT_VNET(curvnet)) { \ + if (vimage_configured && IS_DEFAULT_VNET(curvnet)) { \ (tag) = vimage_eventhandler_register(NULL, #name, func, \ arg, priority, \ vnet_global_eventhandler_iterator_func); \ + } else if (!vimage_configured) { \ + (tag) = eventhandler_register(NULL, #name, func, arg, \ + priority); \ } \ } while(0) + #define VNET_GLOBAL_EVENTHANDLER_REGISTER(name, func, arg, priority) \ do { \ - if (IS_DEFAULT_VNET(curvnet)) { \ + if (vimage_configured && IS_DEFAULT_VNET(curvnet)) { \ vimage_eventhandler_register(NULL, #name, func, \ arg, priority, \ vnet_global_eventhandler_iterator_func); \ + } else if (!vimage_configured) { \ + eventhandler_register(NULL, #name, func, arg, priority); \ } \ } while(0) @@ -411,22 +541,23 @@ /* * Versions of the VNET macros that compile to normal global variables and - * standard sysctl definitions. + * standard sysctl definitions. To ease the pain for kmods that determine at + * runtime if they are operating in VIMAGE mode or not, we name the globals + * with VNET_NAME so that modules can consistently reference VNET_NAME(n). */ -#define VNET_NAME(n) n -#define VNET_DECLARE(t, n) extern t n -#define VNET_DEFINE(t, n) struct _hack; t n -#define VNET_DEFINE_STATIC(t, n) static t n +#define VNET_DECLARE(t, n) extern t VNET_NAME(n) +#define VNET_DEFINE(t, n) struct _hack; t VNET_NAME(n) +#define VNET_DEFINE_STATIC(t, n) static t VNET_NAME(n) #define _VNET_PTR(b, n) &VNET_NAME(n) /* * Virtualized global variable accessor macros. */ -#define VNET_VNET_PTR(vnet, n) (&(n)) -#define VNET_VNET(vnet, n) (n) +#define VNET_VNET_PTR(vnet, n) (&(VNET_NAME(n))) +#define VNET_VNET(vnet, n) (VNET_NAME(n)) -#define VNET_PTR(n) (&(n)) -#define VNET(n) (n) +#define VNET_PTR(n) (&(VNET_NAME(n))) +#define VNET(n) (VNET_NAME(n)) /* * When VIMAGE isn't compiled into the kernel, VNET_SYSINIT/VNET_SYSUNINIT Index: sys/net/vnet_support.c =================================================================== --- /dev/null +++ sys/net/vnet_support.c @@ -0,0 +1,105 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Kyle Evans + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#ifdef KLD_MODULE +#error vnet_support.c may not be compiled into a module. +#endif + +/* + * vimage_configured is compiled into the kernel. Untied modules will inspect + * it in various vnet-related macros as well as in invocations of the below + * vnet_dynamic_* functions that only get invoked from untied modules. + */ +#ifdef VIMAGE +const int vimage_configured = 1; +#else +const int vimage_configured = 0; +#endif + +/* + * Handlers for VNET_SYSINIT/VNET_SYSUNINIT in untied kmods that determine at + * runtime if they are working with a VIMAGE kernel or not. These either proxy + * through to the non-dynamic version as necessary, or they invoke the + * underlying callback at the correct time (as if directly specified + * SYSINIT/SYSUNINIT). + */ +void +vnet_dynamic_register_sysinit(void *arg) +{ + struct vnet_sysinit *vs; + + vs = arg; + KASSERT(vs->subsystem > SI_SUB_VNET, ("vnet sysinit too early")); +#ifdef VIMAGE + if (vimage_configured) + vnet_register_sysinit(arg); + else +#endif + vs->func(vs->arg); +} + +void +vnet_dynamic_deregister_sysinit(void *arg) +{ + +#ifdef VIMAGE + if (vimage_configured) + vnet_deregister_sysinit(arg); +#endif +} + +void +vnet_dynamic_register_sysuninit(void *arg) +{ + +#ifdef VIMAGE + if (vimage_configured) + vnet_register_sysuninit(arg); +#endif +} + +void +vnet_dynamic_deregister_sysuninit(void *arg) +{ + struct vnet_sysinit *vs; + + vs = arg; +#ifdef VIMAGE + if (vimage_configured) + vnet_deregister_sysuninit(arg); + else +#endif + vs->func(vs->arg); +} Index: sys/sys/param.h =================================================================== --- sys/sys/param.h +++ sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300027 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300028 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,