The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/vnet.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2004-2009 University of Zagreb
    3  * Copyright (c) 2006-2009 FreeBSD Foundation
    4  * All rights reserved.
    5  *
    6  * This software was developed by the University of Zagreb and the
    7  * FreeBSD Foundation under sponsorship by the Stichting NLnet and the
    8  * FreeBSD Foundation.
    9  *
   10  * Copyright (c) 2009 Jeffrey Roberson <jeff@freebsd.org>
   11  * Copyright (c) 2009 Robert N. M. Watson
   12  * All rights reserved.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include "opt_ddb.h"
   40 #include "opt_kdb.h"
   41 #include "opt_kdtrace.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/kdb.h>
   45 #include <sys/kernel.h>
   46 #include <sys/jail.h>
   47 #include <sys/sdt.h>
   48 #include <sys/systm.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/eventhandler.h>
   51 #include <sys/lock.h>
   52 #include <sys/malloc.h>
   53 #include <sys/proc.h>
   54 #include <sys/socket.h>
   55 #include <sys/sx.h>
   56 #include <sys/sysctl.h>
   57 
   58 #include <machine/stdarg.h>
   59 
   60 #ifdef DDB
   61 #include <ddb/ddb.h>
   62 #include <ddb/db_sym.h>
   63 #endif
   64 
   65 #include <net/if.h>
   66 #include <net/if_var.h>
   67 #include <net/vnet.h>
   68 
   69 /*-
   70  * This file implements core functions for virtual network stacks:
   71  *
   72  * - Virtual network stack management functions.
   73  *
   74  * - Virtual network stack memory allocator, which virtualizes global
   75  *   variables in the network stack
   76  *
   77  * - Virtualized SYSINIT's/SYSUNINIT's, which allow network stack subsystems
   78  *   to register startup/shutdown events to be run for each virtual network
   79  *   stack instance.
   80  */
   81 
   82 FEATURE(vimage, "VIMAGE kernel virtualization");
   83 
   84 static MALLOC_DEFINE(M_VNET, "vnet", "network stack control block");
   85 
   86 /*
   87  * The virtual network stack list has two read-write locks, one sleepable and
   88  * the other not, so that the list can be stablized and walked in a variety
   89  * of network stack contexts.  Both must be acquired exclusively to modify
   90  * the list, but a read lock of either lock is sufficient to walk the list.
   91  */
   92 struct rwlock           vnet_rwlock;
   93 struct sx               vnet_sxlock;
   94 
   95 #define VNET_LIST_WLOCK() do {                                          \
   96         sx_xlock(&vnet_sxlock);                                         \
   97         rw_wlock(&vnet_rwlock);                                         \
   98 } while (0)
   99 
  100 #define VNET_LIST_WUNLOCK() do {                                        \
  101         rw_wunlock(&vnet_rwlock);                                       \
  102         sx_xunlock(&vnet_sxlock);                                       \
  103 } while (0)
  104 
  105 struct vnet_list_head vnet_head;
  106 struct vnet *vnet0;
  107 
  108 /*
  109  * The virtual network stack allocator provides storage for virtualized
  110  * global variables.  These variables are defined/declared using the
  111  * VNET_DEFINE()/VNET_DECLARE() macros, which place them in the 'set_vnet'
  112  * linker set.  The details of the implementation are somewhat subtle, but
  113  * allow the majority of most network subsystems to maintain
  114  * virtualization-agnostic.
  115  *
  116  * The virtual network stack allocator handles variables in the base kernel
  117  * vs. modules in similar but different ways.  In both cases, virtualized
  118  * global variables are marked as such by being declared to be part of the
  119  * vnet linker set.  These "master" copies of global variables serve two
  120  * functions:
  121  *
  122  * (1) They contain static initialization or "default" values for global
  123  *     variables which will be propagated to each virtual network stack
  124  *     instance when created.  As with normal global variables, they default
  125  *     to zero-filled.
  126  *
  127  * (2) They act as unique global names by which the variable can be referred
  128  *     to, regardless of network stack instance.  The single global symbol
  129  *     will be used to calculate the location of a per-virtual instance
  130  *     variable at run-time.
  131  *
  132  * Each virtual network stack instance has a complete copy of each
  133  * virtualized global variable, stored in a malloc'd block of memory
  134  * referred to by vnet->vnet_data_mem.  Critical to the design is that each
  135  * per-instance memory block is laid out identically to the master block so
  136  * that the offset of each global variable is the same across all blocks.  To
  137  * optimize run-time access, a precalculated 'base' address,
  138  * vnet->vnet_data_base, is stored in each vnet, and is the amount that can
  139  * be added to the address of a 'master' instance of a variable to get to the
  140  * per-vnet instance.
  141  *
  142  * Virtualized global variables are handled in a similar manner, but as each
  143  * module has its own 'set_vnet' linker set, and we want to keep all
  144  * virtualized globals togther, we reserve space in the kernel's linker set
  145  * for potential module variables using a per-vnet character array,
  146  * 'modspace'.  The virtual network stack allocator maintains a free list to
  147  * track what space in the array is free (all, initially) and as modules are
  148  * linked, allocates portions of the space to specific globals.  The kernel
  149  * module linker queries the virtual network stack allocator and will
  150  * bind references of the global to the location during linking.  It also
  151  * calls into the virtual network stack allocator, once the memory is
  152  * initialized, in order to propagate the new static initializations to all
  153  * existing virtual network stack instances so that the soon-to-be executing
  154  * module will find every network stack instance with proper default values.
  155  */
  156 
  157 /*
  158  * Number of bytes of data in the 'set_vnet' linker set, and hence the total
  159  * size of all kernel virtualized global variables, and the malloc(9) type
  160  * that will be used to allocate it.
  161  */
  162 #define VNET_BYTES      (VNET_STOP - VNET_START)
  163 
  164 static MALLOC_DEFINE(M_VNET_DATA, "vnet_data", "VNET data");
  165 
  166 /*
  167  * VNET_MODMIN is the minimum number of bytes we will reserve for the sum of
  168  * global variables across all loaded modules.  As this actually sizes an
  169  * array declared as a virtualized global variable in the kernel itself, and
  170  * we want the virtualized global variable space to be page-sized, we may
  171  * have more space than that in practice.
  172  */
  173 #define VNET_MODMIN     8192
  174 #define VNET_SIZE       roundup2(VNET_BYTES, PAGE_SIZE)
  175 #define VNET_MODSIZE    (VNET_SIZE - (VNET_BYTES - VNET_MODMIN))
  176 
  177 /*
  178  * Space to store virtualized global variables from loadable kernel modules,
  179  * and the free list to manage it.
  180  */
  181 static VNET_DEFINE(char, modspace[VNET_MODMIN]);
  182 
  183 /*
  184  * Global lists of subsystem constructor and destructors for vnets.  They are
  185  * registered via VNET_SYSINIT() and VNET_SYSUNINIT().  Both lists are
  186  * protected by the vnet_sysinit_sxlock global lock.
  187  */
  188 static TAILQ_HEAD(vnet_sysinit_head, vnet_sysinit) vnet_constructors =
  189         TAILQ_HEAD_INITIALIZER(vnet_constructors);
  190 static TAILQ_HEAD(vnet_sysuninit_head, vnet_sysinit) vnet_destructors =
  191         TAILQ_HEAD_INITIALIZER(vnet_destructors);
  192 
  193 struct sx               vnet_sysinit_sxlock;
  194 
  195 #define VNET_SYSINIT_WLOCK()    sx_xlock(&vnet_sysinit_sxlock);
  196 #define VNET_SYSINIT_WUNLOCK()  sx_xunlock(&vnet_sysinit_sxlock);
  197 #define VNET_SYSINIT_RLOCK()    sx_slock(&vnet_sysinit_sxlock);
  198 #define VNET_SYSINIT_RUNLOCK()  sx_sunlock(&vnet_sysinit_sxlock);
  199 
  200 struct vnet_data_free {
  201         uintptr_t       vnd_start;
  202         int             vnd_len;
  203         TAILQ_ENTRY(vnet_data_free) vnd_link;
  204 };
  205 
  206 static MALLOC_DEFINE(M_VNET_DATA_FREE, "vnet_data_free",
  207     "VNET resource accounting");
  208 static TAILQ_HEAD(, vnet_data_free) vnet_data_free_head =
  209             TAILQ_HEAD_INITIALIZER(vnet_data_free_head);
  210 static struct sx vnet_data_free_lock;
  211 
  212 SDT_PROVIDER_DEFINE(vnet);
  213 SDT_PROBE_DEFINE1(vnet, functions, vnet_alloc, entry, "int");
  214 SDT_PROBE_DEFINE2(vnet, functions, vnet_alloc, alloc, "int",
  215     "struct vnet *");
  216 SDT_PROBE_DEFINE2(vnet, functions, vnet_alloc, return,
  217     "int", "struct vnet *");
  218 SDT_PROBE_DEFINE2(vnet, functions, vnet_destroy, entry,
  219     "int", "struct vnet *");
  220 SDT_PROBE_DEFINE1(vnet, functions, vnet_destroy, return,
  221     "int");
  222 
  223 #ifdef DDB
  224 static void db_show_vnet_print_vs(struct vnet_sysinit *, int);
  225 #endif
  226 
  227 /*
  228  * Allocate a virtual network stack.
  229  */
  230 struct vnet *
  231 vnet_alloc(void)
  232 {
  233         struct vnet *vnet;
  234 
  235         SDT_PROBE1(vnet, functions, vnet_alloc, entry, __LINE__);
  236         vnet = malloc(sizeof(struct vnet), M_VNET, M_WAITOK | M_ZERO);
  237         vnet->vnet_magic_n = VNET_MAGIC_N;
  238         SDT_PROBE2(vnet, functions, vnet_alloc, alloc, __LINE__, vnet);
  239 
  240         /*
  241          * Allocate storage for virtualized global variables and copy in
  242          * initial values form our 'master' copy.
  243          */
  244         vnet->vnet_data_mem = malloc(VNET_SIZE, M_VNET_DATA, M_WAITOK);
  245         memcpy(vnet->vnet_data_mem, (void *)VNET_START, VNET_BYTES);
  246 
  247         /*
  248          * All use of vnet-specific data will immediately subtract VNET_START
  249          * from the base memory pointer, so pre-calculate that now to avoid
  250          * it on each use.
  251          */
  252         vnet->vnet_data_base = (uintptr_t)vnet->vnet_data_mem - VNET_START;
  253 
  254         /* Initialize / attach vnet module instances. */
  255         CURVNET_SET_QUIET(vnet);
  256         vnet_sysinit();
  257         CURVNET_RESTORE();
  258 
  259         VNET_LIST_WLOCK();
  260         LIST_INSERT_HEAD(&vnet_head, vnet, vnet_le);
  261         VNET_LIST_WUNLOCK();
  262 
  263         SDT_PROBE2(vnet, functions, vnet_alloc, return, __LINE__, vnet);
  264         return (vnet);
  265 }
  266 
  267 /*
  268  * Destroy a virtual network stack.
  269  */
  270 void
  271 vnet_destroy(struct vnet *vnet)
  272 {
  273         struct ifnet *ifp, *nifp;
  274 
  275         SDT_PROBE2(vnet, functions, vnet_destroy, entry, __LINE__, vnet);
  276         KASSERT(vnet->vnet_sockcnt == 0,
  277             ("%s: vnet still has sockets", __func__));
  278 
  279         VNET_LIST_WLOCK();
  280         LIST_REMOVE(vnet, vnet_le);
  281         VNET_LIST_WUNLOCK();
  282 
  283         CURVNET_SET_QUIET(vnet);
  284 
  285         /* Return all inherited interfaces to their parent vnets. */
  286         TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
  287                 if (ifp->if_home_vnet != ifp->if_vnet)
  288                         if_vmove(ifp, ifp->if_home_vnet);
  289         }
  290 
  291         vnet_sysuninit();
  292         CURVNET_RESTORE();
  293 
  294         /*
  295          * Release storage for the virtual network stack instance.
  296          */
  297         free(vnet->vnet_data_mem, M_VNET_DATA);
  298         vnet->vnet_data_mem = NULL;
  299         vnet->vnet_data_base = 0;
  300         vnet->vnet_magic_n = 0xdeadbeef;
  301         free(vnet, M_VNET);
  302         SDT_PROBE1(vnet, functions, vnet_destroy, return, __LINE__);
  303 }
  304 
  305 /*
  306  * Boot time initialization and allocation of virtual network stacks.
  307  */
  308 static void
  309 vnet_init_prelink(void *arg)
  310 {
  311 
  312         rw_init(&vnet_rwlock, "vnet_rwlock");
  313         sx_init(&vnet_sxlock, "vnet_sxlock");
  314         sx_init(&vnet_sysinit_sxlock, "vnet_sysinit_sxlock");
  315         LIST_INIT(&vnet_head);
  316 }
  317 SYSINIT(vnet_init_prelink, SI_SUB_VNET_PRELINK, SI_ORDER_FIRST,
  318     vnet_init_prelink, NULL);
  319 
  320 static void
  321 vnet0_init(void *arg)
  322 {
  323 
  324         /* Warn people before take off - in case we crash early. */
  325         printf("WARNING: VIMAGE (virtualized network stack) is a highly "
  326             "experimental feature.\n");
  327 
  328         /*
  329          * We MUST clear curvnet in vi_init_done() before going SMP,
  330          * otherwise CURVNET_SET() macros would scream about unnecessary
  331          * curvnet recursions.
  332          */
  333         curvnet = prison0.pr_vnet = vnet0 = vnet_alloc();
  334 }
  335 SYSINIT(vnet0_init, SI_SUB_VNET, SI_ORDER_FIRST, vnet0_init, NULL);
  336 
  337 static void
  338 vnet_init_done(void *unused)
  339 {
  340 
  341         curvnet = NULL;
  342 }
  343 
  344 SYSINIT(vnet_init_done, SI_SUB_VNET_DONE, SI_ORDER_FIRST, vnet_init_done,
  345     NULL);
  346 
  347 /*
  348  * Once on boot, initialize the modspace freelist to entirely cover modspace.
  349  */
  350 static void
  351 vnet_data_startup(void *dummy __unused)
  352 {
  353         struct vnet_data_free *df;
  354 
  355         df = malloc(sizeof(*df), M_VNET_DATA_FREE, M_WAITOK | M_ZERO);
  356         df->vnd_start = (uintptr_t)&VNET_NAME(modspace);
  357         df->vnd_len = VNET_MODMIN;
  358         TAILQ_INSERT_HEAD(&vnet_data_free_head, df, vnd_link);
  359         sx_init(&vnet_data_free_lock, "vnet_data alloc lock");
  360 }
  361 SYSINIT(vnet_data, SI_SUB_KLD, SI_ORDER_FIRST, vnet_data_startup, 0);
  362 
  363 /*
  364  * When a module is loaded and requires storage for a virtualized global
  365  * variable, allocate space from the modspace free list.  This interface
  366  * should be used only by the kernel linker.
  367  */
  368 void *
  369 vnet_data_alloc(int size)
  370 {
  371         struct vnet_data_free *df;
  372         void *s;
  373 
  374         s = NULL;
  375         size = roundup2(size, sizeof(void *));
  376         sx_xlock(&vnet_data_free_lock);
  377         TAILQ_FOREACH(df, &vnet_data_free_head, vnd_link) {
  378                 if (df->vnd_len < size)
  379                         continue;
  380                 if (df->vnd_len == size) {
  381                         s = (void *)df->vnd_start;
  382                         TAILQ_REMOVE(&vnet_data_free_head, df, vnd_link);
  383                         free(df, M_VNET_DATA_FREE);
  384                         break;
  385                 }
  386                 s = (void *)df->vnd_start;
  387                 df->vnd_len -= size;
  388                 df->vnd_start = df->vnd_start + size;
  389                 break;
  390         }
  391         sx_xunlock(&vnet_data_free_lock);
  392 
  393         return (s);
  394 }
  395 
  396 /*
  397  * Free space for a virtualized global variable on module unload.
  398  */
  399 void
  400 vnet_data_free(void *start_arg, int size)
  401 {
  402         struct vnet_data_free *df;
  403         struct vnet_data_free *dn;
  404         uintptr_t start;
  405         uintptr_t end;
  406 
  407         size = roundup2(size, sizeof(void *));
  408         start = (uintptr_t)start_arg;
  409         end = start + size;
  410         /*
  411          * Free a region of space and merge it with as many neighbors as
  412          * possible.  Keeping the list sorted simplifies this operation.
  413          */
  414         sx_xlock(&vnet_data_free_lock);
  415         TAILQ_FOREACH(df, &vnet_data_free_head, vnd_link) {
  416                 if (df->vnd_start > end)
  417                         break;
  418                 /*
  419                  * If we expand at the end of an entry we may have to merge
  420                  * it with the one following it as well.
  421                  */
  422                 if (df->vnd_start + df->vnd_len == start) {
  423                         df->vnd_len += size;
  424                         dn = TAILQ_NEXT(df, vnd_link);
  425                         if (df->vnd_start + df->vnd_len == dn->vnd_start) {
  426                                 df->vnd_len += dn->vnd_len;
  427                                 TAILQ_REMOVE(&vnet_data_free_head, dn,
  428                                     vnd_link);
  429                                 free(dn, M_VNET_DATA_FREE);
  430                         }
  431                         sx_xunlock(&vnet_data_free_lock);
  432                         return;
  433                 }
  434                 if (df->vnd_start == end) {
  435                         df->vnd_start = start;
  436                         df->vnd_len += size;
  437                         sx_xunlock(&vnet_data_free_lock);
  438                         return;
  439                 }
  440         }
  441         dn = malloc(sizeof(*df), M_VNET_DATA_FREE, M_WAITOK | M_ZERO);
  442         dn->vnd_start = start;
  443         dn->vnd_len = size;
  444         if (df)
  445                 TAILQ_INSERT_BEFORE(df, dn, vnd_link);
  446         else
  447                 TAILQ_INSERT_TAIL(&vnet_data_free_head, dn, vnd_link);
  448         sx_xunlock(&vnet_data_free_lock);
  449 }
  450 
  451 /*
  452  * When a new virtualized global variable has been allocated, propagate its
  453  * initial value to each already-allocated virtual network stack instance.
  454  */
  455 void
  456 vnet_data_copy(void *start, int size)
  457 {
  458         struct vnet *vnet;
  459 
  460         VNET_LIST_RLOCK();
  461         LIST_FOREACH(vnet, &vnet_head, vnet_le)
  462                 memcpy((void *)((uintptr_t)vnet->vnet_data_base +
  463                     (uintptr_t)start), start, size);
  464         VNET_LIST_RUNLOCK();
  465 }
  466 
  467 /*
  468  * Variants on sysctl_handle_foo that know how to handle virtualized global
  469  * variables: if 'arg1' is a pointer, then we transform it to the local vnet
  470  * offset.
  471  */
  472 int
  473 vnet_sysctl_handle_int(SYSCTL_HANDLER_ARGS)
  474 {
  475 
  476         if (arg1 != NULL)
  477                 arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
  478         return (sysctl_handle_int(oidp, arg1, arg2, req));
  479 }
  480 
  481 int
  482 vnet_sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
  483 {
  484 
  485         if (arg1 != NULL)
  486                 arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
  487         return (sysctl_handle_opaque(oidp, arg1, arg2, req));
  488 }
  489 
  490 int
  491 vnet_sysctl_handle_string(SYSCTL_HANDLER_ARGS)
  492 {
  493 
  494         if (arg1 != NULL)
  495                 arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
  496         return (sysctl_handle_string(oidp, arg1, arg2, req));
  497 }
  498 
  499 int
  500 vnet_sysctl_handle_uint(SYSCTL_HANDLER_ARGS)
  501 {
  502 
  503         if (arg1 != NULL)
  504                 arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
  505         return (sysctl_handle_int(oidp, arg1, arg2, req));
  506 }
  507 
  508 /*
  509  * Support for special SYSINIT handlers registered via VNET_SYSINIT()
  510  * and VNET_SYSUNINIT().
  511  */
  512 void
  513 vnet_register_sysinit(void *arg)
  514 {
  515         struct vnet_sysinit *vs, *vs2;  
  516         struct vnet *vnet;
  517 
  518         vs = arg;
  519         KASSERT(vs->subsystem > SI_SUB_VNET, ("vnet sysinit too early"));
  520 
  521         /* Add the constructor to the global list of vnet constructors. */
  522         VNET_SYSINIT_WLOCK();
  523         TAILQ_FOREACH(vs2, &vnet_constructors, link) {
  524                 if (vs2->subsystem > vs->subsystem)
  525                         break;
  526                 if (vs2->subsystem == vs->subsystem && vs2->order > vs->order)
  527                         break;
  528         }
  529         if (vs2 != NULL)
  530                 TAILQ_INSERT_BEFORE(vs2, vs, link);
  531         else
  532                 TAILQ_INSERT_TAIL(&vnet_constructors, vs, link);
  533 
  534         /*
  535          * Invoke the constructor on all the existing vnets when it is
  536          * registered.
  537          */
  538         VNET_FOREACH(vnet) {
  539                 CURVNET_SET_QUIET(vnet);
  540                 vs->func(vs->arg);
  541                 CURVNET_RESTORE();
  542         }
  543         VNET_SYSINIT_WUNLOCK();
  544 }
  545 
  546 void
  547 vnet_deregister_sysinit(void *arg)
  548 {
  549         struct vnet_sysinit *vs;
  550 
  551         vs = arg;
  552 
  553         /* Remove the constructor from the global list of vnet constructors. */
  554         VNET_SYSINIT_WLOCK();
  555         TAILQ_REMOVE(&vnet_constructors, vs, link);
  556         VNET_SYSINIT_WUNLOCK();
  557 }
  558 
  559 void
  560 vnet_register_sysuninit(void *arg)
  561 {
  562         struct vnet_sysinit *vs, *vs2;
  563 
  564         vs = arg;
  565 
  566         /* Add the destructor to the global list of vnet destructors. */
  567         VNET_SYSINIT_WLOCK();
  568         TAILQ_FOREACH(vs2, &vnet_destructors, link) {
  569                 if (vs2->subsystem > vs->subsystem)
  570                         break;
  571                 if (vs2->subsystem == vs->subsystem && vs2->order > vs->order)
  572                         break;
  573         }
  574         if (vs2 != NULL)
  575                 TAILQ_INSERT_BEFORE(vs2, vs, link);
  576         else
  577                 TAILQ_INSERT_TAIL(&vnet_destructors, vs, link);
  578         VNET_SYSINIT_WUNLOCK();
  579 }
  580 
  581 void
  582 vnet_deregister_sysuninit(void *arg)
  583 {
  584         struct vnet_sysinit *vs;
  585         struct vnet *vnet;
  586 
  587         vs = arg;
  588 
  589         /*
  590          * Invoke the destructor on all the existing vnets when it is
  591          * deregistered.
  592          */
  593         VNET_SYSINIT_WLOCK();
  594         VNET_FOREACH(vnet) {
  595                 CURVNET_SET_QUIET(vnet);
  596                 vs->func(vs->arg);
  597                 CURVNET_RESTORE();
  598         }
  599 
  600         /* Remove the destructor from the global list of vnet destructors. */
  601         TAILQ_REMOVE(&vnet_destructors, vs, link);
  602         VNET_SYSINIT_WUNLOCK();
  603 }
  604 
  605 /*
  606  * Invoke all registered vnet constructors on the current vnet.  Used during
  607  * vnet construction.  The caller is responsible for ensuring the new vnet is
  608  * the current vnet and that the vnet_sysinit_sxlock lock is locked.
  609  */
  610 void
  611 vnet_sysinit(void)
  612 {
  613         struct vnet_sysinit *vs;
  614 
  615         VNET_SYSINIT_RLOCK();
  616         TAILQ_FOREACH(vs, &vnet_constructors, link) {
  617                 vs->func(vs->arg);
  618         }
  619         VNET_SYSINIT_RUNLOCK();
  620 }
  621 
  622 /*
  623  * Invoke all registered vnet destructors on the current vnet.  Used during
  624  * vnet destruction.  The caller is responsible for ensuring the dying vnet
  625  * the current vnet and that the vnet_sysinit_sxlock lock is locked.
  626  */
  627 void
  628 vnet_sysuninit(void)
  629 {
  630         struct vnet_sysinit *vs;
  631 
  632         VNET_SYSINIT_RLOCK();
  633         TAILQ_FOREACH_REVERSE(vs, &vnet_destructors, vnet_sysuninit_head,
  634             link) {
  635                 vs->func(vs->arg);
  636         }
  637         VNET_SYSINIT_RUNLOCK();
  638 }
  639 
  640 /*
  641  * EVENTHANDLER(9) extensions.
  642  */
  643 /*
  644  * Invoke the eventhandler function originally registered with the possibly
  645  * registered argument for all virtual network stack instances.
  646  *
  647  * This iterator can only be used for eventhandlers that do not take any
  648  * additional arguments, as we do ignore the variadic arguments from the
  649  * EVENTHANDLER_INVOKE() call.
  650  */
  651 void
  652 vnet_global_eventhandler_iterator_func(void *arg, ...)
  653 {
  654         VNET_ITERATOR_DECL(vnet_iter);
  655         struct eventhandler_entry_vimage *v_ee;
  656 
  657         /*
  658          * There is a bug here in that we should actually cast things to
  659          * (struct eventhandler_entry_ ## name *)  but that's not easily
  660          * possible in here so just re-using the variadic version we
  661          * defined for the generic vimage case.
  662          */
  663         v_ee = arg;
  664         VNET_LIST_RLOCK();
  665         VNET_FOREACH(vnet_iter) {
  666                 CURVNET_SET(vnet_iter);
  667                 ((vimage_iterator_func_t)v_ee->func)(v_ee->ee_arg);
  668                 CURVNET_RESTORE();
  669         }
  670         VNET_LIST_RUNLOCK();
  671 }
  672 
  673 #ifdef VNET_DEBUG
  674 struct vnet_recursion {
  675         SLIST_ENTRY(vnet_recursion)      vnr_le;
  676         const char                      *prev_fn;
  677         const char                      *where_fn;
  678         int                              where_line;
  679         struct vnet                     *old_vnet;
  680         struct vnet                     *new_vnet;
  681 };
  682 
  683 static SLIST_HEAD(, vnet_recursion) vnet_recursions =
  684     SLIST_HEAD_INITIALIZER(vnet_recursions);
  685 
  686 static void
  687 vnet_print_recursion(struct vnet_recursion *vnr, int brief)
  688 {
  689 
  690         if (!brief)
  691                 printf("CURVNET_SET() recursion in ");
  692         printf("%s() line %d, prev in %s()", vnr->where_fn, vnr->where_line,
  693             vnr->prev_fn);
  694         if (brief)
  695                 printf(", ");
  696         else
  697                 printf("\n    ");
  698         printf("%p -> %p\n", vnr->old_vnet, vnr->new_vnet);
  699 }
  700 
  701 void
  702 vnet_log_recursion(struct vnet *old_vnet, const char *old_fn, int line)
  703 {
  704         struct vnet_recursion *vnr;
  705 
  706         /* Skip already logged recursion events. */
  707         SLIST_FOREACH(vnr, &vnet_recursions, vnr_le)
  708                 if (vnr->prev_fn == old_fn &&
  709                     vnr->where_fn == curthread->td_vnet_lpush &&
  710                     vnr->where_line == line &&
  711                     (vnr->old_vnet == vnr->new_vnet) == (curvnet == old_vnet))
  712                         return;
  713 
  714         vnr = malloc(sizeof(*vnr), M_VNET, M_NOWAIT | M_ZERO);
  715         if (vnr == NULL)
  716                 panic("%s: malloc failed", __func__);
  717         vnr->prev_fn = old_fn;
  718         vnr->where_fn = curthread->td_vnet_lpush;
  719         vnr->where_line = line;
  720         vnr->old_vnet = old_vnet;
  721         vnr->new_vnet = curvnet;
  722 
  723         SLIST_INSERT_HEAD(&vnet_recursions, vnr, vnr_le);
  724 
  725         vnet_print_recursion(vnr, 0);
  726 #ifdef KDB
  727         kdb_backtrace();
  728 #endif
  729 }
  730 #endif /* VNET_DEBUG */
  731 
  732 /*
  733  * DDB(4).
  734  */
  735 #ifdef DDB
  736 DB_SHOW_COMMAND(vnets, db_show_vnets)
  737 {
  738         VNET_ITERATOR_DECL(vnet_iter);
  739 
  740         VNET_FOREACH(vnet_iter) {
  741                 db_printf("vnet            = %p\n", vnet_iter);
  742                 db_printf(" vnet_magic_n   = 0x%x (%s, orig 0x%x)\n",
  743                     vnet_iter->vnet_magic_n,
  744                     (vnet_iter->vnet_magic_n == VNET_MAGIC_N) ?
  745                         "ok" : "mismatch", VNET_MAGIC_N);
  746                 db_printf(" vnet_ifcnt     = %u\n", vnet_iter->vnet_ifcnt);
  747                 db_printf(" vnet_sockcnt   = %u\n", vnet_iter->vnet_sockcnt);
  748                 db_printf(" vnet_data_mem  = %p\n", vnet_iter->vnet_data_mem);
  749                 db_printf(" vnet_data_base = 0x%jx\n",
  750                     (uintmax_t)vnet_iter->vnet_data_base);
  751                 db_printf("\n");
  752                 if (db_pager_quit)
  753                         break;
  754         }
  755 }
  756 
  757 static void
  758 db_show_vnet_print_vs(struct vnet_sysinit *vs, int ddb)
  759 {
  760         const char *vsname, *funcname;
  761         c_db_sym_t sym;
  762         db_expr_t  offset;
  763 
  764 #define xprint(...)                                                     \
  765         if (ddb)                                                        \
  766                 db_printf(__VA_ARGS__);                                 \
  767         else                                                            \
  768                 printf(__VA_ARGS__)
  769 
  770         if (vs == NULL) {
  771                 xprint("%s: no vnet_sysinit * given\n", __func__);
  772                 return;
  773         }
  774 
  775         sym = db_search_symbol((vm_offset_t)vs, DB_STGY_ANY, &offset);
  776         db_symbol_values(sym, &vsname, NULL);
  777         sym = db_search_symbol((vm_offset_t)vs->func, DB_STGY_PROC, &offset);
  778         db_symbol_values(sym, &funcname, NULL);
  779         xprint("%s(%p)\n", (vsname != NULL) ? vsname : "", vs);
  780         xprint("  0x%08x 0x%08x\n", vs->subsystem, vs->order);
  781         xprint("  %p(%s)(%p)\n",
  782             vs->func, (funcname != NULL) ? funcname : "", vs->arg);
  783 #undef xprint
  784 }
  785 
  786 DB_SHOW_COMMAND(vnet_sysinit, db_show_vnet_sysinit)
  787 {
  788         struct vnet_sysinit *vs;
  789 
  790         db_printf("VNET_SYSINIT vs Name(Ptr)\n");
  791         db_printf("  Subsystem  Order\n");
  792         db_printf("  Function(Name)(Arg)\n");
  793         TAILQ_FOREACH(vs, &vnet_constructors, link) {
  794                 db_show_vnet_print_vs(vs, 1);
  795                 if (db_pager_quit)
  796                         break;
  797         }
  798 }
  799 
  800 DB_SHOW_COMMAND(vnet_sysuninit, db_show_vnet_sysuninit)
  801 {
  802         struct vnet_sysinit *vs;
  803 
  804         db_printf("VNET_SYSUNINIT vs Name(Ptr)\n");
  805         db_printf("  Subsystem  Order\n");
  806         db_printf("  Function(Name)(Arg)\n");
  807         TAILQ_FOREACH_REVERSE(vs, &vnet_destructors, vnet_sysuninit_head,
  808             link) {
  809                 db_show_vnet_print_vs(vs, 1);
  810                 if (db_pager_quit)
  811                         break;
  812         }
  813 }
  814 
  815 #ifdef VNET_DEBUG
  816 DB_SHOW_COMMAND(vnetrcrs, db_show_vnetrcrs)
  817 {
  818         struct vnet_recursion *vnr;
  819 
  820         SLIST_FOREACH(vnr, &vnet_recursions, vnr_le)
  821                 vnet_print_recursion(vnr, 1);
  822 }
  823 #endif
  824 #endif /* DDB */

Cache object: 5fec752da496d60efef9ec9cb813b0b5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.