diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-08-01 19:26:27 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-08-01 19:26:27 +0000 |
commit | fb9ffed6504601ed9da2c6b9a620b133c838964c (patch) | |
tree | 6dc533c8b591922258259a32957fdee2632a29ac /sys/net/vnet.c | |
parent | 2d4b24984c5d2ea2556ae2b1ef1df7f0833dc1b5 (diff) | |
download | FreeBSD-src-fb9ffed6504601ed9da2c6b9a620b133c838964c.zip FreeBSD-src-fb9ffed6504601ed9da2c6b9a620b133c838964c.tar.gz |
Merge the remainder of kern_vimage.c and vimage.h into vnet.c and
vnet.h, we now use jails (rather than vimages) as the abstraction
for virtualization management, and what remained was specific to
virtual network stacks. Minor cleanups are done in the process,
and comments updated to reflect these changes.
Reviewed by: bz
Approved by: re (vimage blanket)
Diffstat (limited to 'sys/net/vnet.c')
-rw-r--r-- | sys/net/vnet.c | 174 |
1 files changed, 172 insertions, 2 deletions
diff --git a/sys/net/vnet.c b/sys/net/vnet.c index eed353e..a34270a 100644 --- a/sys/net/vnet.c +++ b/sys/net/vnet.c @@ -1,4 +1,12 @@ /*- + * Copyright (c) 2004-2009 University of Zagreb + * Copyright (c) 2006-2009 FreeBSD Foundation + * All rights reserved. + * + * This software was developed by the University of Zagreb and the + * FreeBSD Foundation under sponsorship by the Stichting NLnet and the + * FreeBSD Foundation. + * * Copyright (c) 2009 Jeffrey Roberson <jeff@freebsd.org> * Copyright (c) 2009 Robert N. M. Watson * All rights reserved. @@ -28,30 +36,67 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" + #include <sys/param.h> #include <sys/kernel.h> +#include <sys/jail.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/linker_set.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/proc.h> +#include <sys/socket.h> #include <sys/sx.h> #include <sys/sysctl.h> -#include <sys/vimage.h> +#ifdef DDB +#include <ddb/ddb.h> +#endif + +#include <net/if.h> +#include <net/if_var.h> #include <net/vnet.h> /*- * This file implements core functions for virtual network stacks: * + * - Core virtual network stack management functions. + * * - Virtual network stack memory allocator, which virtualized global * variables in the network stack * * - Virtualized SYSINIT's/SYSUNINIT's, which allow network stack subsystems * to register startup/shutdown events to be run for each virtual network * stack instance. - * + */ + +MALLOC_DEFINE(M_VNET, "vnet", "network stack control block"); + +/* + * The virtual network stack list has two read-write locks, one sleepable and + * the other not, so that the list can be stablized and walked in a variety + * of network stack contexts. Both must be acquired exclusively to modify + * the list. + */ +struct rwlock vnet_rwlock; +struct sx vnet_sxlock; + +#define VNET_LIST_WLOCK() do { \ + sx_xlock(&vnet_sxlock); \ + rw_wlock(&vnet_rwlock); \ +} while (0) + +#define VNET_LIST_WUNLOCK() do { \ + rw_wunlock(&vnet_rwlock); \ + sx_xunlock(&vnet_sxlock); \ +} while (0) + +struct vnet_list_head vnet_head; +struct vnet *vnet0; + +/* * The virtual network stack allocator provides storage for virtualized * global variables. These variables are defined/declared using the * VNET_DEFINE()/VNET_DECLARE() macros, which place them in the 'set_vnet' @@ -157,6 +202,114 @@ static TAILQ_HEAD(, vnet_data_free) vnet_data_free_head = static struct sx vnet_data_free_lock; /* + * Allocate a virtual network stack. + */ +struct vnet * +vnet_alloc(void) +{ + struct vnet *vnet; + + vnet = malloc(sizeof(struct vnet), M_VNET, M_WAITOK | M_ZERO); + vnet->vnet_magic_n = VNET_MAGIC_N; + vnet_data_init(vnet); + + /* Initialize / attach vnet module instances. */ + CURVNET_SET_QUIET(vnet); + + sx_xlock(&vnet_sxlock); + vnet_sysinit(); + CURVNET_RESTORE(); + + rw_wlock(&vnet_rwlock); + LIST_INSERT_HEAD(&vnet_head, vnet, vnet_le); + VNET_LIST_WUNLOCK(); + + return (vnet); +} + +/* + * Destroy a virtual network stack. + */ +void +vnet_destroy(struct vnet *vnet) +{ + struct ifnet *ifp, *nifp; + + KASSERT(vnet->vnet_sockcnt == 0, + ("%s: vnet still has sockets", __func__)); + + VNET_LIST_WLOCK(); + LIST_REMOVE(vnet, vnet_le); + rw_wunlock(&vnet_rwlock); + + CURVNET_SET_QUIET(vnet); + + /* Return all inherited interfaces to their parent vnets. */ + TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) { + if (ifp->if_home_vnet != ifp->if_vnet) + if_vmove(ifp, ifp->if_home_vnet); + } + + vnet_sysuninit(); + sx_xunlock(&vnet_sxlock); + + CURVNET_RESTORE(); + + /* Hopefully, we are OK to free the vnet container itself. */ + vnet_data_destroy(vnet); + vnet->vnet_magic_n = 0xdeadbeef; + free(vnet, M_VNET); +} + +static void +vnet_foreach(void (*vnet_foreach_fn)(struct vnet *, void *), void *arg) +{ + struct vnet *vnet; + + VNET_LIST_RLOCK(); + LIST_FOREACH(vnet, &vnet_head, vnet_le) + vnet_foreach_fn(vnet, arg); + VNET_LIST_RUNLOCK(); +} + +/* + * Boot time initialization and allocation of virtual network stacks. + */ +static void +vnet_init_prelink(void *arg) +{ + + rw_init(&vnet_rwlock, "vnet_rwlock"); + sx_init(&vnet_sxlock, "vnet_sxlock"); + LIST_INIT(&vnet_head); +} +SYSINIT(vnet_init_prelink, SI_SUB_VNET_PRELINK, SI_ORDER_FIRST, + vnet_init_prelink, NULL); + +static void +vnet0_init(void *arg) +{ + + /* + * We MUST clear curvnet in vi_init_done() before going SMP, + * otherwise CURVNET_SET() macros would scream about unnecessary + * curvnet recursions. + */ + curvnet = prison0.pr_vnet = vnet0 = vnet_alloc(); +} +SYSINIT(vnet0_init, SI_SUB_VNET, SI_ORDER_FIRST, vnet0_init, NULL); + +static void +vnet_init_done(void *unused) +{ + + curvnet = NULL; +} + +SYSINIT(vnet_init_done, SI_SUB_VNET_DONE, SI_ORDER_FIRST, vnet_init_done, + NULL); + +/* * Allocate storage for virtualized global variables in a new virtual network * stack instance, and copy in initial values from our 'master' copy. */ @@ -490,3 +643,20 @@ vnet_sysuninit(void) vs->func(vs->arg); } } + +#ifdef DDB +DB_SHOW_COMMAND(vnets, db_show_vnets) +{ + VNET_ITERATOR_DECL(vnet_iter); + +#if SIZE_MAX == UINT32_MAX /* 32-bit arch */ + db_printf(" vnet ifs socks\n"); +#else /* 64-bit arch, most probaly... */ + db_printf(" vnet ifs socks\n"); +#endif + VNET_FOREACH(vnet_iter) { + db_printf("%p %3d %5d\n", vnet_iter, vnet_iter->vnet_ifcnt, + vnet_iter->vnet_sockcnt); + } +} +#endif |