Skip to content

Commit

Permalink
Introduce and use a sysinit-based initialization scheme for virtual
Browse files Browse the repository at this point in the history
network stacks, VNET_SYSINIT:

- Add VNET_SYSINIT and VNET_SYSUNINIT macros to declare events that will
  occur each time a network stack is instantiated and destroyed.  In the
  !VIMAGE case, these are simply mapped into regular SYSINIT/SYSUNINIT.
  For the VIMAGE case, we instead use SYSINIT's to track their order and
  properties on registration, using them for each vnet when created/
  destroyed, or immediately on module load for already-started vnets.
- Remove vnet_modinfo mechanism that existed to serve this purpose
  previously, as well as its dependency scheme: we now just use the
  SYSINIT ordering scheme.
- Implement VNET_DOMAIN_SET() to allow protocol domains to declare that
  they want init functions to be called for each virtual network stack
  rather than just once at boot, compiling down to DOMAIN_SET() in the
  non-VIMAGE case.
- Walk all virtualized kernel subsystems and make use of these instead
  of modinfo or DOMAIN_SET() for init/uninit events.  In some cases,
  convert modular components from using modevent to using sysinit (where
  appropriate).  In some cases, do minor rejuggling of SYSINIT ordering
  to make room for or better manage events.

Portions submitted by:	jhb (VNET_SYSINIT), bz (cleanup)
Discussed with:		jhb, bz, julian, zec
Reviewed by:		bz
Approved by:		re (VIMAGE blanket)
  • Loading branch information
rwatson committed Jul 23, 2009
1 parent fc8defe commit b3be1c6
Show file tree
Hide file tree
Showing 28 changed files with 397 additions and 721 deletions.
212 changes: 7 additions & 205 deletions sys/kern/kern_vimage.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ __FBSDID("$FreeBSD$");

MALLOC_DEFINE(M_VNET, "vnet", "network stack control block");

static TAILQ_HEAD(vnet_modlink_head, vnet_modlink) vnet_modlink_head;
static TAILQ_HEAD(vnet_modpending_head, vnet_modlink) vnet_modpending_head;
static void vnet_mod_complete_registration(struct vnet_modlink *);
static int vnet_mod_constructor(struct vnet_modlink *);
static int vnet_mod_destructor(struct vnet_modlink *);

struct rwlock vnet_rwlock;
struct sx vnet_sxlock;

Expand Down Expand Up @@ -130,197 +124,23 @@ vi_if_move(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
return (error);
}


/*
* Kernel interfaces and handlers.
*/

void
vnet_mod_register(const struct vnet_modinfo *vmi)
{

vnet_mod_register_multi(vmi, NULL, NULL);
}

void
vnet_mod_register_multi(const struct vnet_modinfo *vmi, void *iarg,
char *iname)
{
struct vnet_modlink *vml, *vml_iter;

/* Do not register the same {module, iarg} pair more than once. */
TAILQ_FOREACH(vml_iter, &vnet_modlink_head, vml_mod_le)
if (vml_iter->vml_modinfo == vmi && vml_iter->vml_iarg == iarg)
break;
if (vml_iter != NULL)
panic("registering an already registered vnet module: %s",
vml_iter->vml_modinfo->vmi_name);
vml = malloc(sizeof(struct vnet_modlink), M_VNET, M_NOWAIT);

/*
* XXX we support only statically assigned module IDs at the time.
* In principle modules should be able to get a dynamically
* assigned ID at registration time.
*
* If a module is registered in multiple instances, then each
* instance must have both iarg and iname set.
*/
if (vmi->vmi_id >= VNET_MOD_MAX)
panic("invalid vnet module ID: %d", vmi->vmi_id);
if (vmi->vmi_name == NULL)
panic("vnet module with no name: %d", vmi->vmi_id);
if ((iarg == NULL) ^ (iname == NULL))
panic("invalid vnet module instance: %s", vmi->vmi_name);

vml->vml_modinfo = vmi;
vml->vml_iarg = iarg;
vml->vml_iname = iname;

/* Check whether the module we depend on is already registered. */
if (vmi->vmi_dependson != vmi->vmi_id) {
TAILQ_FOREACH(vml_iter, &vnet_modlink_head, vml_mod_le)
if (vml_iter->vml_modinfo->vmi_id ==
vmi->vmi_dependson)
break; /* Depencency found, we are done. */
if (vml_iter == NULL) {
#ifdef DEBUG_ORDERING
printf("dependency %d missing for vnet mod %s,"
"postponing registration\n",
vmi->vmi_dependson, vmi->vmi_name);
#endif /* DEBUG_ORDERING */
TAILQ_INSERT_TAIL(&vnet_modpending_head, vml,
vml_mod_le);
return;
}
}

vnet_mod_complete_registration(vml);
}

void
vnet_mod_complete_registration(struct vnet_modlink *vml)
{
VNET_ITERATOR_DECL(vnet_iter);
struct vnet_modlink *vml_iter;

TAILQ_INSERT_TAIL(&vnet_modlink_head, vml, vml_mod_le);

VNET_FOREACH(vnet_iter) {
CURVNET_SET_QUIET(vnet_iter);
vnet_mod_constructor(vml);
CURVNET_RESTORE();
}

/* Check for pending modules depending on us. */
do {
TAILQ_FOREACH(vml_iter, &vnet_modpending_head, vml_mod_le)
if (vml_iter->vml_modinfo->vmi_dependson ==
vml->vml_modinfo->vmi_id)
break;
if (vml_iter != NULL) {
#ifdef DEBUG_ORDERING
printf("vnet mod %s now registering,"
"dependency %d loaded\n",
vml_iter->vml_modinfo->vmi_name,
vml->vml_modinfo->vmi_id);
#endif /* DEBUG_ORDERING */
TAILQ_REMOVE(&vnet_modpending_head, vml_iter,
vml_mod_le);
vnet_mod_complete_registration(vml_iter);
}
} while (vml_iter != NULL);
}

void
vnet_mod_deregister(const struct vnet_modinfo *vmi)
{

vnet_mod_deregister_multi(vmi, NULL, NULL);
}

void
vnet_mod_deregister_multi(const struct vnet_modinfo *vmi, void *iarg,
char *iname)
{
VNET_ITERATOR_DECL(vnet_iter);
struct vnet_modlink *vml;

TAILQ_FOREACH(vml, &vnet_modlink_head, vml_mod_le)
if (vml->vml_modinfo == vmi && vml->vml_iarg == iarg)
break;
if (vml == NULL)
panic("cannot deregister unregistered vnet module %s",
vmi->vmi_name);

VNET_FOREACH(vnet_iter) {
CURVNET_SET_QUIET(vnet_iter);
vnet_mod_destructor(vml);
CURVNET_RESTORE();
}

TAILQ_REMOVE(&vnet_modlink_head, vml, vml_mod_le);
free(vml, M_VNET);
}

static int
vnet_mod_constructor(struct vnet_modlink *vml)
{
const struct vnet_modinfo *vmi = vml->vml_modinfo;

#ifdef DEBUG_ORDERING
printf("instantiating vnet_%s", vmi->vmi_name);
if (vml->vml_iarg)
printf("/%s", vml->vml_iname);
printf(": ");
if (vmi->vmi_iattach != NULL)
printf("iattach()");
printf("\n");
#endif

if (vmi->vmi_iattach != NULL)
vmi->vmi_iattach(vml->vml_iarg);

return (0);
}

static int
vnet_mod_destructor(struct vnet_modlink *vml)
{
const struct vnet_modinfo *vmi = vml->vml_modinfo;

#ifdef DEBUG_ORDERING
printf("destroying vnet_%s", vmi->vmi_name);
if (vml->vml_iarg)
printf("/%s", vml->vml_iname);
printf(": ");
if (vmi->vmi_idetach != NULL)
printf("idetach(); ");
printf("\n");
#endif

if (vmi->vmi_idetach)
vmi->vmi_idetach(vml->vml_iarg);

return (0);
}

struct vnet *
vnet_alloc(void)
{
struct vnet *vnet;
struct vnet_modlink *vml;

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);
TAILQ_FOREACH(vml, &vnet_modlink_head, vml_mod_le)
vnet_mod_constructor(vml);

sx_xlock(&vnet_sxlock);
vnet_sysinit();
CURVNET_RESTORE();

VNET_LIST_WLOCK();
rw_wlock(&vnet_rwlock);
LIST_INSERT_HEAD(&vnet_head, vnet, vnet_le);
VNET_LIST_WUNLOCK();

Expand All @@ -331,14 +151,13 @@ void
vnet_destroy(struct vnet *vnet)
{
struct ifnet *ifp, *nifp;
struct vnet_modlink *vml;

KASSERT(vnet->vnet_sockcnt == 0,
("%s: vnet still has sockets", __func__));

VNET_LIST_WLOCK();
LIST_REMOVE(vnet, vnet_le);
VNET_LIST_WUNLOCK();
rw_wunlock(&vnet_rwlock);

CURVNET_SET_QUIET(vnet);

Expand All @@ -348,10 +167,8 @@ vnet_destroy(struct vnet *vnet)
if_vmove(ifp, ifp->if_home_vnet);
}

/* Detach / free per-module state instances. */
TAILQ_FOREACH_REVERSE(vml, &vnet_modlink_head,
vnet_modlink_head, vml_mod_le)
vnet_mod_destructor(vml);
vnet_sysuninit();
sx_xunlock(&vnet_sxlock);

CURVNET_RESTORE();

Expand Down Expand Up @@ -387,9 +204,6 @@ static void
vnet0_init(void *arg)
{

TAILQ_INIT(&vnet_modlink_head);
TAILQ_INIT(&vnet_modpending_head);

/*
* We MUST clear curvnet in vi_init_done() before going SMP,
* otherwise CURVNET_SET() macros would scream about unnecessary
Expand All @@ -402,20 +216,8 @@ SYSINIT(vnet0_init, SI_SUB_VNET, SI_ORDER_FIRST, vnet0_init, NULL);
static void
vnet_init_done(void *unused)
{
struct vnet_modlink *vml_iter;

curvnet = NULL;

if (TAILQ_EMPTY(&vnet_modpending_head))
return;

printf("vnet modules with unresolved dependencies:\n");
TAILQ_FOREACH(vml_iter, &vnet_modpending_head, vml_mod_le)
printf(" %d:%s depending on %d\n",
vml_iter->vml_modinfo->vmi_id,
vml_iter->vml_modinfo->vmi_name,
vml_iter->vml_modinfo->vmi_dependson);
panic("going nowhere without my vnet modules!");
}

SYSINIT(vnet_init_done, SI_SUB_VNET_DONE, SI_ORDER_FIRST, vnet_init_done,
Expand Down
55 changes: 19 additions & 36 deletions sys/kern/uipc_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,12 @@ __FBSDID("$FreeBSD$");
*/

static void domaininit(void *);
SYSINIT(domain, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, domaininit, NULL);
SYSINIT(domain, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, domaininit, NULL);

static void domainfinalize(void *);
SYSINIT(domainfin, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST, domainfinalize,
NULL);

static vnet_attach_fn net_init_domain;
#ifdef VIMAGE
static vnet_detach_fn net_detach_domain;
#endif

static struct callout pffast_callout;
static struct callout pfslow_callout;

Expand Down Expand Up @@ -106,15 +101,6 @@ struct pr_usrreqs nousrreqs = {
.pru_sopoll = pru_sopoll_notsupp,
};

#ifdef VIMAGE
vnet_modinfo_t vnet_domain_modinfo = {
.vmi_id = VNET_MOD_DOMAIN,
.vmi_name = "domain",
.vmi_iattach = net_init_domain,
.vmi_idetach = net_detach_domain,
};
#endif

static void
protosw_init(struct protosw *pr)
{
Expand Down Expand Up @@ -174,10 +160,10 @@ protosw_init(struct protosw *pr)
* Note: you cant unload it again because a socket may be using it.
* XXX can't fail at this time.
*/
static int
net_init_domain(const void *arg)
void
domain_init(void *arg)
{
const struct domain *dp = arg;
struct domain *dp = arg;
struct protosw *pr;

if (dp->dom_init)
Expand All @@ -191,26 +177,28 @@ net_init_domain(const void *arg)
max_datalen = MHLEN - max_hdr;
if (max_datalen < 1)
panic("%s: max_datalen < 1", __func__);
return (0);
}

#ifdef VIMAGE
/*
* Detach / free a domain instance.
*/
static int
net_detach_domain(const void *arg)
void
vnet_domain_init(void *arg)
{

/* Virtualized case is no different -- call init functions. */
domain_init(arg);
}

void
vnet_domain_uninit(void *arg)
{
const struct domain *dp = arg;
struct domain *dp = arg;
struct protosw *pr;

for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_destroy)
(*pr->pr_destroy)();
if (dp->dom_destroy)
(*dp->dom_destroy)();

return (0);
}
#endif

Expand All @@ -220,7 +208,7 @@ net_detach_domain(const void *arg)
* XXX can't fail at this time.
*/
void
net_add_domain(void *data)
domain_add(void *data)
{
struct domain *dp;

Expand All @@ -234,24 +222,19 @@ net_add_domain(void *data)
dp->dom_name));
#ifndef INVARIANTS
if (domain_init_status < 1)
printf("WARNING: attempt to net_add_domain(%s) before "
printf("WARNING: attempt to domain_add(%s) before "
"domaininit()\n", dp->dom_name);
#endif
#ifdef notyet
KASSERT(domain_init_status < 2,
("attempt to net_add_domain(%s) after domainfinalize()",
("attempt to domain_add(%s) after domainfinalize()",
dp->dom_name));
#else
if (domain_init_status >= 2)
printf("WARNING: attempt to net_add_domain(%s) after "
printf("WARNING: attempt to domain_add(%s) after "
"domainfinalize()\n", dp->dom_name);
#endif
mtx_unlock(&dom_mtx);
#ifdef VIMAGE
vnet_mod_register_multi(&vnet_domain_modinfo, dp, dp->dom_name);
#else
net_init_domain(dp);
#endif
}

static void
Expand Down
Loading

0 comments on commit b3be1c6

Please sign in to comment.