summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--UPDATING5
-rw-r--r--sys/kern/kern_vimage.c73
-rw-r--r--sys/kern/uipc_domain.c28
-rw-r--r--sys/net/if.c26
-rw-r--r--sys/net/if_gif.c8
-rw-r--r--sys/net/if_loop.c35
-rw-r--r--sys/net/if_var.h4
-rw-r--r--sys/net/route.c41
-rw-r--r--sys/net/vnet.h2
-rw-r--r--sys/netgraph/ng_base.c45
-rw-r--r--sys/netinet/in_proto.c13
-rw-r--r--sys/netinet/in_rmx.c14
-rw-r--r--sys/netinet/ip_var.h3
-rw-r--r--sys/netinet/raw_ip.c13
-rw-r--r--sys/netinet/tcp_hostcache.c12
-rw-r--r--sys/netinet/tcp_subr.c19
-rw-r--r--sys/netinet/tcp_syncache.c13
-rw-r--r--sys/netinet/tcp_syncache.h3
-rw-r--r--sys/netinet/tcp_timewait.c14
-rw-r--r--sys/netinet/tcp_var.h9
-rw-r--r--sys/netinet/udp_usrreq.c14
-rw-r--r--sys/netinet/udp_var.h3
-rw-r--r--sys/netinet6/in6_proto.c9
-rw-r--r--sys/netinet6/in6_rmx.c15
-rw-r--r--sys/netinet6/ip6_input.c11
-rw-r--r--sys/netinet6/ip6_var.h3
-rw-r--r--sys/netinet6/ip6protosw.h2
-rw-r--r--sys/netinet6/nd6.c19
-rw-r--r--sys/netinet6/nd6.h3
-rw-r--r--sys/netipsec/ipsec.c20
-rw-r--r--sys/netipsec/key.c68
-rw-r--r--sys/netipsec/key.h3
-rw-r--r--sys/netipsec/keysock.c3
-rw-r--r--sys/sys/domain.h4
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/protosw.h2
-rw-r--r--sys/sys/vimage.h1
37 files changed, 526 insertions, 36 deletions
diff --git a/UPDATING b/UPDATING
index 2c43132..d5e05f9 100644
--- a/UPDATING
+++ b/UPDATING
@@ -22,6 +22,11 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.x IS SLOW:
to maximize performance. (To disable malloc debugging, run
ln -s aj /etc/malloc.conf.)
+20090608:
+ The layout of structs ifnet, domain, protosw and vnet_net has
+ changed. Kernel modules need to be rebuilt.
+ Bump __FreeBSD_version to 800097.
+
20090602:
window(1) has been removed from the base system. It can now be
installed from ports. The port is called misc/window.
diff --git a/sys/kern/kern_vimage.c b/sys/kern/kern_vimage.c
index c78217a..bb2c509 100644
--- a/sys/kern/kern_vimage.c
+++ b/sys/kern/kern_vimage.c
@@ -65,8 +65,8 @@ static int vnet_mod_constructor(struct vnet_modlink *);
static int vnet_mod_destructor(struct vnet_modlink *);
#ifdef VIMAGE
-static struct vimage *vimage_by_name(struct vimage *, char *);
static struct vimage *vi_alloc(struct vimage *, char *);
+static int vi_destroy(struct vimage *);
static struct vimage *vimage_get_next(struct vimage *, struct vimage *, int);
static void vimage_relative_name(struct vimage *, struct vimage *,
char *, int);
@@ -122,7 +122,7 @@ vi_if_move(struct vi_req *vi_req, struct ifnet *ifp, struct vimage *vip)
struct vnet *new_vnet = NULL;
/* Check for API / ABI version mismatch. */
- if (vi_req->vi_api_cookie != VI_API_COOKIE)
+ if (vi_req != NULL && vi_req->vi_api_cookie != VI_API_COOKIE)
return (EDOOFUS);
/* Find the target vnet. */
@@ -216,11 +216,7 @@ vi_td_ioctl(u_long cmd, struct vi_req *vi_req, struct thread *td)
case SIOCSPVIMAGE:
if (vi_req->vi_req_action == VI_DESTROY) {
-#ifdef NOTYET
error = vi_destroy(vip_r);
-#else
- error = EOPNOTSUPP;
-#endif
break;
}
@@ -283,7 +279,7 @@ vi_child_of(struct vimage *parent, struct vimage *child)
return (0);
}
-static struct vimage *
+struct vimage *
vimage_by_name(struct vimage *top, char *name)
{
struct vimage *vip;
@@ -541,7 +537,6 @@ vnet_mod_constructor(struct vnet_modlink *vml)
return (0);
}
-
static int
vnet_mod_destructor(struct vnet_modlink *vml)
{
@@ -663,6 +658,68 @@ vi_alloc(struct vimage *parent, char *name)
return (vip);
}
+
+/*
+ * Destroy a vnet - unlink all linked lists, hashtables etc., free all
+ * the memory, stop all the timers...
+ */
+static int
+vi_destroy(struct vimage *vip)
+{
+ struct vnet *vnet = vip->v_net;
+ struct vprocg *vprocg = vip->v_procg;
+ struct ifnet *ifp, *nifp;
+ struct vnet_modlink *vml;
+
+ /* XXX Beware of races -> more locking to be done... */
+ if (!LIST_EMPTY(&vip->vi_child_head))
+ return (EBUSY);
+
+ if (vprocg->nprocs != 0)
+ return (EBUSY);
+
+ if (vnet->sockcnt != 0)
+ return (EBUSY);
+
+#ifdef INVARIANTS
+ if (vip->vi_ucredrefc != 0)
+ printf("vi_destroy: %s ucredrefc %d\n",
+ vip->vi_name, vip->vi_ucredrefc);
+#endif
+
+ /* Point with no return - cleanup MUST succeed! */
+ LIST_REMOVE(vip, vi_le);
+ LIST_REMOVE(vip, vi_sibling);
+ LIST_REMOVE(vprocg, vprocg_le);
+
+ VNET_LIST_WLOCK();
+ LIST_REMOVE(vnet, vnet_le);
+ VNET_LIST_WUNLOCK();
+
+ CURVNET_SET_QUIET(vnet);
+ INIT_VNET_NET(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)
+ vi_if_move(NULL, ifp, vip);
+ }
+
+ /* Detach / free per-module state instances. */
+ TAILQ_FOREACH_REVERSE(vml, &vnet_modlink_head,
+ vnet_modlink_head, vml_mod_le)
+ vnet_mod_destructor(vml);
+
+ CURVNET_RESTORE();
+
+ /* Hopefully, we are OK to free the vnet container itself. */
+ vnet->vnet_magic_n = 0xdeadbeef;
+ free(vnet, M_VNET);
+ free(vprocg, M_VPROCG);
+ free(vip, M_VIMAGE);
+
+ return (0);
+}
#endif /* VIMAGE */
static void
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index df35bcb..9ee6047 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -66,6 +66,9 @@ 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;
@@ -107,7 +110,10 @@ struct pr_usrreqs nousrreqs = {
vnet_modinfo_t vnet_domain_modinfo = {
.vmi_id = VNET_MOD_DOMAIN,
.vmi_name = "domain",
- .vmi_iattach = net_init_domain
+ .vmi_iattach = net_init_domain,
+#ifdef VIMAGE
+ .vmi_idetach = net_detach_domain,
+#endif
};
#endif
@@ -190,6 +196,26 @@ net_init_domain(const void *arg)
return (0);
}
+#ifdef VIMAGE
+/*
+ * Detach / free a domain instance.
+ */
+static int
+net_detach_domain(const void *arg)
+{
+ const 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
+
/*
* Add a new protocol domain to the list of supported domains
* Note: you cant unload it again because a socket may be using it.
diff --git a/sys/net/if.c b/sys/net/if.c
index 1a5dcd2..35a5e0b 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -153,6 +153,9 @@ extern void nd6_setmtu(struct ifnet *);
#endif
static int vnet_net_iattach(const void *);
+#ifdef VIMAGE
+static int vnet_net_idetach(const void *);
+#endif
#ifdef VIMAGE_GLOBALS
struct ifnethead ifnet; /* depend on static init XXX */
@@ -189,7 +192,10 @@ static const vnet_modinfo_t vnet_net_modinfo = {
.vmi_name = "net",
.vmi_size = sizeof(struct vnet_net),
.vmi_symmap = vnet_net_symmap,
- .vmi_iattach = vnet_net_iattach
+ .vmi_iattach = vnet_net_iattach,
+#ifdef VIMAGE
+ .vmi_idetach = vnet_net_idetach
+#endif
};
#endif /* !VIMAGE_GLOBALS */
@@ -446,6 +452,22 @@ vnet_net_iattach(const void *unused __unused)
return (0);
}
+#ifdef VIMAGE
+static int
+vnet_net_idetach(const void *unused __unused)
+{
+ INIT_VNET_NET(curvnet);
+
+ VNET_ASSERT(TAILQ_EMPTY(&V_ifnet));
+ VNET_ASSERT(TAILQ_EMPTY(&V_ifg_head));
+ VNET_ASSERT(SLIST_EMPTY(&V_ifklist.kl_list));
+
+ free((caddr_t)V_ifindex_table, M_IFNET);
+
+ return (0);
+}
+#endif
+
void
if_grow(void)
{
@@ -688,6 +710,8 @@ if_attach_internal(struct ifnet *ifp, int vmove)
#ifdef VIMAGE
ifp->if_vnet = curvnet;
+ if (ifp->if_home_vnet == NULL)
+ ifp->if_home_vnet = curvnet;
#endif
if_addgroup(ifp, IFG_ALL);
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 69e14e9..c6f7285 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -303,12 +303,10 @@ gifmodevent(mod, type, data)
break;
case MOD_UNLOAD:
if_clone_detach(&gif_cloner);
- mtx_destroy(&gif_mtx);
-#ifdef INET6
-#ifndef VIMAGE
- V_ip6_gif_hlim = 0; /* XXX -> vnet_gif_idetach() */
-#endif
+#ifdef VIMAGE
+ vnet_mod_deregister(&vnet_gif_modinfo);
#endif
+ mtx_destroy(&gif_mtx);
break;
default:
return EOPNOTSUPP;
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index 2bbccac..b0f22c8 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -105,6 +105,9 @@ int looutput(struct ifnet *ifp, struct mbuf *m,
static int lo_clone_create(struct if_clone *, int, caddr_t);
static void lo_clone_destroy(struct ifnet *);
static int vnet_loif_iattach(const void *);
+#ifdef VIMAGE
+static int vnet_loif_idetach(const void *);
+#endif
#ifdef VIMAGE_GLOBALS
struct ifnet *loif; /* Used externally */
@@ -119,7 +122,10 @@ static const vnet_modinfo_t vnet_loif_modinfo = {
.vmi_id = VNET_MOD_LOIF,
.vmi_dependson = VNET_MOD_IF_CLONE,
.vmi_name = "loif",
- .vmi_iattach = vnet_loif_iattach
+ .vmi_iattach = vnet_loif_iattach,
+#ifdef VIMAGE
+ .vmi_idetach = vnet_loif_idetach
+#endif
};
#endif /* !VIMAGE_GLOBALS */
@@ -128,12 +134,11 @@ IFC_SIMPLE_DECLARE(lo, 1);
static void
lo_clone_destroy(struct ifnet *ifp)
{
-#ifdef INVARIANTS
- INIT_VNET_NET(ifp->if_vnet);
-#endif
+#ifndef VIMAGE
/* XXX: destroying lo0 will lead to panics. */
KASSERT(V_loif != ifp, ("%s: destroying lo0", __func__));
+#endif
bpfdetach(ifp);
if_detach(ifp);
@@ -166,7 +171,8 @@ lo_clone_create(struct if_clone *ifc, int unit, caddr_t params)
return (0);
}
-static int vnet_loif_iattach(const void *unused __unused)
+static int
+vnet_loif_iattach(const void *unused __unused)
{
INIT_VNET_NET(curvnet);
@@ -175,7 +181,11 @@ static int vnet_loif_iattach(const void *unused __unused)
#ifdef VIMAGE
V_lo_cloner = malloc(sizeof(*V_lo_cloner), M_LO_CLONER,
M_WAITOK | M_ZERO);
+ V_lo_cloner_data = malloc(sizeof(*V_lo_cloner_data), M_LO_CLONER,
+ M_WAITOK | M_ZERO);
bcopy(&lo_cloner, V_lo_cloner, sizeof(*V_lo_cloner));
+ bcopy(lo_cloner.ifc_data, V_lo_cloner_data, sizeof(*V_lo_cloner_data));
+ V_lo_cloner->ifc_data = V_lo_cloner_data;
if_clone_attach(V_lo_cloner);
#else
if_clone_attach(&lo_cloner);
@@ -183,6 +193,21 @@ static int vnet_loif_iattach(const void *unused __unused)
return (0);
}
+#ifdef VIMAGE
+static int
+vnet_loif_idetach(const void *unused __unused)
+{
+ INIT_VNET_NET(curvnet);
+
+ if_clone_detach(V_lo_cloner);
+ free(V_lo_cloner, M_LO_CLONER);
+ free(V_lo_cloner_data, M_LO_CLONER);
+ V_loif = NULL;
+
+ return (0);
+}
+#endif
+
static int
loop_modevent(module_t mod, int type, void *data)
{
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index d811f22..2d0a0ab 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -71,6 +71,7 @@ struct ether_header;
struct carp_if;
struct ifvlantrunk;
struct route;
+struct vnet;
#endif
#include <sys/queue.h> /* get TAILQ macros */
@@ -169,6 +170,9 @@ struct ifnet {
(struct ifnet *);
int (*if_transmit) /* initiate output routine */
(struct ifnet *, struct mbuf *);
+ void (*if_reassign) /* reassign to vnet routine */
+ (struct ifnet *, struct vnet *, char *);
+ struct vnet *if_home_vnet; /* where this ifnet originates from */
struct ifaddr *if_addr; /* pointer to link-level address */
void *if_llsoftc; /* link layer softc */
int if_drv_flags; /* driver-managed status flags */
diff --git a/sys/net/route.c b/sys/net/route.c
index 8705a54..aaa38d7 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -99,12 +99,18 @@ static int rttrash; /* routes not in table but not freed */
static void rt_maskedcopy(struct sockaddr *,
struct sockaddr *, struct sockaddr *);
static int vnet_route_iattach(const void *);
+#ifdef VIMAGE
+static int vnet_route_idetach(const void *);
+#endif
#ifndef VIMAGE_GLOBALS
static const vnet_modinfo_t vnet_rtable_modinfo = {
.vmi_id = VNET_MOD_RTABLE,
.vmi_name = "rtable",
- .vmi_iattach = vnet_route_iattach
+ .vmi_iattach = vnet_route_iattach,
+#ifdef VIMAGE
+ .vmi_idetach = vnet_route_idetach
+#endif
};
#endif /* !VIMAGE_GLOBALS */
@@ -194,7 +200,8 @@ route_init(void)
#endif
}
-static int vnet_route_iattach(const void *unused __unused)
+static int
+vnet_route_iattach(const void *unused __unused)
{
INIT_VNET_NET(curvnet);
struct domain *dom;
@@ -235,6 +242,36 @@ static int vnet_route_iattach(const void *unused __unused)
return (0);
}
+#ifdef VIMAGE
+static int
+vnet_route_idetach(const void *unused __unused)
+{
+ int table;
+ int fam;
+ struct domain *dom;
+ struct radix_node_head **rnh;
+
+ for (dom = domains; dom; dom = dom->dom_next) {
+ if (dom->dom_rtdetach) {
+ for (table = 0; table < rt_numfibs; table++) {
+ if ( (fam = dom->dom_family) == AF_INET ||
+ table == 0) {
+ /* For now only AF_INET has > 1 tbl. */
+ rnh = rt_tables_get_rnh_ptr(table, fam);
+ if (rnh == NULL)
+ panic("%s: rnh NULL", __func__);
+ dom->dom_rtdetach((void **)rnh,
+ dom->dom_rtoffset);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return (0);
+}
+#endif
+
#ifndef _SYS_SYSPROTO_H_
struct setfib_args {
int fibnum;
diff --git a/sys/net/vnet.h b/sys/net/vnet.h
index d36c303..696e472 100644
--- a/sys/net/vnet.h
+++ b/sys/net/vnet.h
@@ -51,6 +51,7 @@ struct vnet_net {
struct ifnet * _loif;
struct if_clone * _lo_cloner;
+ struct ifc_simple_data *_lo_cloner_data;
LIST_HEAD(, rawcb) _rawcb_list;
@@ -87,6 +88,7 @@ extern struct vnet_net vnet_net_0;
#define V_ifklist VNET_NET(ifklist)
#define V_ifnet VNET_NET(ifnet)
#define V_lo_cloner VNET_NET(lo_cloner)
+#define V_lo_cloner_data VNET_NET(lo_cloner_data)
#define V_loif VNET_NET(loif)
#define V_rawcb_list VNET_NET(rawcb_list)
#define V_rt_tables VNET_NET(rt_tables)
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index 2daf961..39084b5 100644
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -85,6 +85,9 @@ struct vnet_netgraph vnet_netgraph_0;
static struct mtx ng_topo_mtx;
static vnet_attach_fn vnet_netgraph_iattach;
+#ifdef VIMAGE
+static vnet_detach_fn vnet_netgraph_idetach;
+#endif
#ifdef NETGRAPH_DEBUG
static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */
@@ -647,6 +650,9 @@ ng_make_node_common(struct ng_type *type, node_p *nodepp)
return (ENOMEM);
}
node->nd_type = type;
+#ifdef VIMAGE
+ node->nd_vnet = curvnet;
+#endif
NG_NODE_REF(node); /* note reference */
type->refs++;
@@ -3074,15 +3080,17 @@ ng_mod_event(module_t mod, int event, void *data)
static const vnet_modinfo_t vnet_netgraph_modinfo = {
.vmi_id = VNET_MOD_NETGRAPH,
.vmi_name = "netgraph",
-#ifdef VIMAGE
.vmi_size = sizeof(struct vnet_netgraph),
+ .vmi_dependson = VNET_MOD_LOIF,
+ .vmi_iattach = vnet_netgraph_iattach,
+#ifdef VIMAGE
+ .vmi_idetach = vnet_netgraph_idetach
#endif
- .vmi_iattach = vnet_netgraph_iattach
};
#endif
static int
-vnet_netgraph_iattach(const void *arg __unused)
+vnet_netgraph_iattach(const void *unused __unused)
{
INIT_VNET_NETGRAPH(curvnet);
@@ -3091,6 +3099,33 @@ vnet_netgraph_iattach(const void *arg __unused)
return (0);
}
+#ifdef VIMAGE
+static int
+vnet_netgraph_idetach(const void *unused __unused)
+{
+ INIT_VNET_NETGRAPH(curvnet);
+ node_p node, last_killed = NULL;
+
+ while ((node = LIST_FIRST(&V_ng_nodelist)) != NULL) {
+ if (node == last_killed) {
+ /* This should never happen */
+ node->nd_flags |= NGF_REALLY_DIE;
+ printf("netgraph node %s needs NGF_REALLY_DIE\n",
+ node->nd_name);
+ ng_rmnode(node, NULL, NULL, 0);
+ /* This must never happen */
+ if (node == LIST_FIRST(&V_ng_nodelist))
+ panic("netgraph node %s won't die",
+ node->nd_name);
+ }
+ ng_rmnode(node, NULL, NULL, 0);
+ last_killed = node;
+ }
+
+ return (0);
+}
+#endif /* VIMAGE */
+
/*
* Handle loading and unloading for this code.
* The only thing we need to link into is the NETISR strucure.
@@ -3313,6 +3348,7 @@ ngthread(void *arg)
NG_WORKLIST_SLEEP();
STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work);
NG_WORKLIST_UNLOCK();
+ CURVNET_SET(node->nd_vnet);
CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist",
__func__, node->nd_ID, node);
/*
@@ -3342,6 +3378,7 @@ ngthread(void *arg)
}
}
NG_NODE_UNREF(node);
+ CURVNET_RESTORE();
}
}
@@ -3675,7 +3712,9 @@ ng_callout_trampoline(void *arg)
{
item_p item = arg;
+ CURVNET_SET(NGI_NODE(item)->nd_vnet);
ng_snd_item(item, 0);
+ CURVNET_RESTORE();
}
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index c25f6eb..7d811f7 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -127,6 +127,9 @@ struct protosw inetsw[] = {
.pr_ctlinput = udp_ctlinput,
.pr_ctloutput = ip_ctloutput,
.pr_init = udp_init,
+#ifdef VIMAGE
+ .pr_destroy = udp_destroy,
+#endif
.pr_usrreqs = &udp_usrreqs
},
{
@@ -138,6 +141,9 @@ struct protosw inetsw[] = {
.pr_ctlinput = tcp_ctlinput,
.pr_ctloutput = tcp_ctloutput,
.pr_init = tcp_init,
+#ifdef VIMAGE
+ .pr_destroy = tcp_destroy,
+#endif
.pr_slowtimo = tcp_slowtimo,
.pr_drain = tcp_drain,
.pr_usrreqs = &tcp_usrreqs
@@ -348,11 +354,15 @@ IPPROTOSPACER,
.pr_input = rip_input,
.pr_ctloutput = rip_ctloutput,
.pr_init = rip_init,
+#ifdef VIMAGE
+ .pr_destroy = rip_destroy,
+#endif
.pr_usrreqs = &rip_usrreqs
},
};
extern int in_inithead(void **, int);
+extern int in_detachhead(void **, int);
struct domain inetdomain = {
.dom_family = AF_INET,
@@ -364,6 +374,9 @@ struct domain inetdomain = {
#else
.dom_rtattach = in_inithead,
#endif
+#ifdef VIMAGE
+ .dom_rtdetach = in_detachhead,
+#endif
.dom_rtoffset = 32,
.dom_maxrtkey = sizeof(struct sockaddr_in),
.dom_ifattach = in_domifattach,
diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c
index 8fc60ae..f798f9c 100644
--- a/sys/netinet/in_rmx.c
+++ b/sys/netinet/in_rmx.c
@@ -65,6 +65,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/vinet.h>
extern int in_inithead(void **head, int off);
+#ifdef VIMAGE
+extern int in_detachhead(void **head, int off);
+#endif
#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
@@ -382,6 +385,17 @@ in_inithead(void **head, int off)
return 1;
}
+#ifdef VIMAGE
+int
+in_detachhead(void **head, int off)
+{
+ INIT_VNET_INET(curvnet);
+
+ callout_drain(&V_rtq_timer);
+ return (1);
+}
+#endif
+
/*
* This zaps old routes when the interface goes down or interface
* address is deleted. In the latter case, it deletes static routes
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index aa9beb1..1e5e693 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -210,6 +210,9 @@ u_int16_t ip_randomid(void);
int rip_ctloutput(struct socket *, struct sockopt *);
void rip_ctlinput(int, struct sockaddr *, void *);
void rip_init(void);
+#ifdef VIMAGE
+void rip_destroy(void);
+#endif
void rip_input(struct mbuf *, int);
int rip_output(struct mbuf *, struct socket *, u_long);
void ipip_input(struct mbuf *, int);
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 806fc1d..8063da1 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -205,6 +205,19 @@ rip_init(void)
EVENTHANDLER_PRI_ANY);
}
+#ifdef VIMAGE
+void
+rip_destroy(void)
+{
+ INIT_VNET_INET(curvnet);
+
+ hashdestroy(V_ripcbinfo.ipi_hashbase, M_PCB,
+ V_ripcbinfo.ipi_hashmask);
+ hashdestroy(V_ripcbinfo.ipi_porthashbase, M_PCB,
+ V_ripcbinfo.ipi_porthashmask);
+}
+#endif
+
static int
rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n,
struct sockaddr_in *ripsrc)
diff --git a/sys/netinet/tcp_hostcache.c b/sys/netinet/tcp_hostcache.c
index 93367c5..e04499d 100644
--- a/sys/netinet/tcp_hostcache.c
+++ b/sys/netinet/tcp_hostcache.c
@@ -230,6 +230,18 @@ tcp_hc_init(void)
tcp_hc_purge, curvnet);
}
+#ifdef VIMAGE
+void
+tcp_hc_destroy(void)
+{
+ INIT_VNET_INET(curvnet);
+
+ /* XXX TODO walk the hashtable and free all entries */
+
+ callout_drain(&V_tcp_hc_callout);
+}
+#endif
+
/*
* Internal function: look up an entry in the hostcache or return NULL.
*
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 489617b..fc49344 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -426,6 +426,25 @@ tcp_init(void)
EVENTHANDLER_PRI_ANY);
}
+#ifdef VIMAGE
+void
+tcp_destroy(void)
+{
+ INIT_VNET_INET(curvnet);
+
+ tcp_tw_destroy();
+ tcp_hc_destroy();
+ syncache_destroy();
+
+ /* XXX check that hashes are empty! */
+ hashdestroy(V_tcbinfo.ipi_hashbase, M_PCB,
+ V_tcbinfo.ipi_hashmask);
+ hashdestroy(V_tcbinfo.ipi_porthashbase, M_PCB,
+ V_tcbinfo.ipi_porthashmask);
+ INP_INFO_LOCK_DESTROY(&V_tcbinfo);
+}
+#endif
+
void
tcp_fini(void *xtp)
{
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 033e506..dc05f46 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -275,6 +275,19 @@ syncache_init(void)
uma_zone_set_max(V_tcp_syncache.zone, V_tcp_syncache.cache_limit);
}
+#ifdef VIMAGE
+void
+syncache_destroy(void)
+{
+ INIT_VNET_INET(curvnet);
+
+ /* XXX walk the cache, free remaining objects, stop timers */
+
+ uma_zdestroy(V_tcp_syncache.zone);
+ FREE(V_tcp_syncache.hashbase, M_SYNCACHE);
+}
+#endif
+
/*
* Inserts a syncache entry into the specified bucket row.
* Locks and unlocks the syncache_head autonomously.
diff --git a/sys/netinet/tcp_syncache.h b/sys/netinet/tcp_syncache.h
index e488039..5ed0c9e 100644
--- a/sys/netinet/tcp_syncache.h
+++ b/sys/netinet/tcp_syncache.h
@@ -35,6 +35,9 @@
#ifdef _KERNEL
void syncache_init(void);
+#ifdef VIMAGE
+void syncache_destroy(void);
+#endif
void syncache_unreach(struct in_conninfo *, struct tcphdr *);
int syncache_expand(struct in_conninfo *, struct tcpopt *,
struct tcphdr *, struct socket **, struct mbuf *);
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 4c0fe94..32108c7 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -179,6 +179,20 @@ tcp_tw_init(void)
TAILQ_INIT(&V_twq_2msl);
}
+#ifdef VIMAGE
+void
+tcp_tw_destroy(void)
+{
+ INIT_VNET_INET(curvnet);
+ struct tcptw *tw;
+
+ INP_INFO_WLOCK(&V_tcbinfo);
+ while((tw = TAILQ_FIRST(&V_twq_2msl)) != NULL)
+ tcp_twclose(tw, 0);
+ INP_INFO_WUNLOCK(&V_tcbinfo);
+}
+#endif
+
/*
* Move a TCP connection into TIME_WAIT state.
* tcbinfo is locked.
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 5dc840e..5568d4a 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -584,6 +584,9 @@ struct tcpcb *
void tcp_drain(void);
void tcp_fasttimo(void);
void tcp_init(void);
+#ifdef VIMAGE
+void tcp_destroy(void);
+#endif
void tcp_fini(void *);
char *tcp_log_addrs(struct in_conninfo *, struct tcphdr *, void *,
const void *);
@@ -605,6 +608,9 @@ int tcp_output(struct tcpcb *);
void tcp_respond(struct tcpcb *, void *,
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int);
void tcp_tw_init(void);
+#ifdef VIMAGE
+void tcp_tw_destroy(void);
+#endif
void tcp_tw_zone_change(void);
int tcp_twcheck(struct inpcb *, struct tcpopt *, struct tcphdr *,
struct mbuf *, int);
@@ -625,6 +631,9 @@ void tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq);
* All tcp_hc_* functions are IPv4 and IPv6 (via in_conninfo)
*/
void tcp_hc_init(void);
+#ifdef VIMAGE
+void tcp_hc_destroy(void);
+#endif
void tcp_hc_get(struct in_conninfo *, struct hc_metrics_lite *);
u_long tcp_hc_getmtu(struct in_conninfo *);
void tcp_hc_updatemtu(struct in_conninfo *, u_long);
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 33be911..fdc96f4 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -221,6 +221,20 @@ udp_discardcb(struct udpcb *up)
uma_zfree(V_udpcb_zone, up);
}
+#ifdef VIMAGE
+void
+udp_destroy(void)
+{
+ INIT_VNET_INET(curvnet);
+
+ hashdestroy(V_udbinfo.ipi_hashbase, M_PCB,
+ V_udbinfo.ipi_hashmask);
+ hashdestroy(V_udbinfo.ipi_porthashbase, M_PCB,
+ V_udbinfo.ipi_porthashmask);
+ INP_INFO_LOCK_DESTROY(&V_udbinfo);
+}
+#endif
+
/*
* Subroutine of udp_input(), which appends the provided mbuf chain to the
* passed pcb/socket. The caller must provide a sockaddr_in via udp_in that
diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h
index e429819..8b045ad 100644
--- a/sys/netinet/udp_var.h
+++ b/sys/netinet/udp_var.h
@@ -128,6 +128,9 @@ void udp_discardcb(struct udpcb *);
void udp_ctlinput(int, struct sockaddr *, void *);
void udp_init(void);
+#ifdef VIMAGE
+void udp_destroy(void);
+#endif
void udp_input(struct mbuf *, int);
struct inpcb *udp_notify(struct inpcb *inp, int errno);
int udp_shutdown(struct socket *so);
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index c0b0b25..e4d280d 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -148,6 +148,9 @@ struct ip6protosw inet6sw[] = {
.pr_domain = &inet6domain,
.pr_protocol = IPPROTO_IPV6,
.pr_init = ip6_init,
+#ifdef VIMAGE
+ .pr_destroy = ip6_destroy,
+#endif
.pr_slowtimo = frag6_slowtimo,
.pr_drain = frag6_drain,
.pr_usrreqs = &nousrreqs,
@@ -349,6 +352,9 @@ struct ip6protosw inet6sw[] = {
};
extern int in6_inithead(void **, int);
+#ifdef VIMAGE
+extern int in6_detachhead(void **, int);
+#endif
struct domain inet6domain = {
.dom_family = AF_INET6,
@@ -361,6 +367,9 @@ struct domain inet6domain = {
#else
.dom_rtattach = in6_inithead,
#endif
+#ifdef VIMAGE
+ .dom_rtdetach = in6_detachhead,
+#endif
.dom_rtoffset = offsetof(struct sockaddr_in6, sin6_addr) << 3,
.dom_maxrtkey = sizeof(struct sockaddr_in6),
.dom_ifattach = in6_domifattach,
diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c
index 3a423ed..4dbdad6 100644
--- a/sys/netinet6/in6_rmx.c
+++ b/sys/netinet6/in6_rmx.c
@@ -112,6 +112,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/tcp_var.h>
extern int in6_inithead(void **head, int off);
+#ifdef VIMAGE
+extern int in6_detachhead(void **head, int off);
+#endif
#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
@@ -464,3 +467,15 @@ in6_inithead(void **head, int off)
in6_mtutimo(curvnet); /* kick off timeout first time */
return 1;
}
+
+#ifdef VIMAGE
+int
+in6_detachhead(void **head, int off)
+{
+ INIT_VNET_INET6(curvnet);
+
+ callout_drain(&V_rtq_timer6);
+ callout_drain(&V_rtq_mtutimer);
+ return (1);
+}
+#endif
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index b9617bb..5166eb4 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -303,6 +303,17 @@ ip6_init(void)
netisr_register(&ip6_nh);
}
+#ifdef VIMAGE
+void
+ip6_destroy()
+{
+ INIT_VNET_INET6(curvnet);
+
+ nd6_destroy();
+ callout_drain(&V_in6_tmpaddrtimer_ch);
+}
+#endif
+
static int
ip6_init2_vnet(const void *unused __unused)
{
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 313b6ca..74749f6 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -339,6 +339,9 @@ int icmp6_ctloutput __P((struct socket *, struct sockopt *sopt));
struct in6_ifaddr;
void ip6_init __P((void));
+#ifdef VIMAGE
+void ip6_destroy __P((void));
+#endif
void ip6_input __P((struct mbuf *));
struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *));
void ip6_freepcbopts __P((struct ip6_pktopts *));
diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h
index 2a7cea4..1fae44c 100644
--- a/sys/netinet6/ip6protosw.h
+++ b/sys/netinet6/ip6protosw.h
@@ -129,6 +129,8 @@ struct ip6protosw {
/* utility hooks */
void (*pr_init) /* initialization hook */
__P((void));
+ void (*pr_destroy) /* cleanup hook */
+ __P((void));
void (*pr_fasttimo) /* fast timeout (200ms) */
__P((void));
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index ccfdb8f..96c6d01 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -134,14 +134,8 @@ void
nd6_init(void)
{
INIT_VNET_INET6(curvnet);
- static int nd6_init_done = 0;
int i;
- if (nd6_init_done) {
- log(LOG_NOTICE, "nd6_init called more than once(ignored)\n");
- return;
- }
-
V_nd6_prune = 1; /* walk list every 1 seconds */
V_nd6_delay = 5; /* delay first probe time 5 second */
V_nd6_umaxtries = 3; /* maximum unicast query */
@@ -180,6 +174,8 @@ nd6_init(void)
V_ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
V_ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
+ V_ip6_desync_factor = 0;
+
all1_sa.sin6_family = AF_INET6;
all1_sa.sin6_len = sizeof(struct sockaddr_in6);
for (i = 0; i < sizeof(all1_sa.sin6_addr); i++)
@@ -191,10 +187,19 @@ nd6_init(void)
callout_init(&V_nd6_slowtimo_ch, 0);
callout_reset(&V_nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
nd6_slowtimo, curvnet);
+}
- nd6_init_done = 1;
+#ifdef VIMAGE
+void
+nd6_destroy()
+{
+ INIT_VNET_INET6(curvnet);
+
+ callout_drain(&V_nd6_slowtimo_ch);
+ callout_drain(&V_nd6_timer_ch);
}
+#endif
struct nd_ifinfo *
nd6_ifattach(struct ifnet *ifp)
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index d4d2fd5..0730d84 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -371,6 +371,9 @@ union nd_opts {
/* XXX: need nd6_var.h?? */
/* nd6.c */
void nd6_init __P((void));
+#ifdef VIMAGE
+void nd6_destroy __P((void));
+#endif
struct nd_ifinfo *nd6_ifattach __P((struct ifnet *));
void nd6_ifdetach __P((struct nd_ifinfo *));
int nd6_is_addr_neighbor __P((struct sockaddr_in6 *, struct ifnet *));
diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c
index 6c42e32..4eef064 100644
--- a/sys/netipsec/ipsec.c
+++ b/sys/netipsec/ipsec.c
@@ -104,6 +104,9 @@ struct vnet_ipsec vnet_ipsec_0;
#endif
static int ipsec_iattach(const void *);
+#ifdef VIMAGE
+static int ipsec_idetach(const void *);
+#endif
#ifdef VIMAGE_GLOBALS
/* NB: name changed so netstat doesn't use it. */
@@ -256,7 +259,10 @@ static const vnet_modinfo_t vnet_ipsec_modinfo = {
.vmi_name = "ipsec",
.vmi_size = sizeof(struct vnet_ipsec),
.vmi_dependson = VNET_MOD_INET, /* XXX revisit - INET6 ? */
- .vmi_iattach = ipsec_iattach
+ .vmi_iattach = ipsec_iattach,
+#ifdef VIMAGE
+ .vmi_idetach = ipsec_idetach
+#endif
};
#endif /* !VIMAGE_GLOBALS */
@@ -1791,7 +1797,6 @@ ipsec_attach(void)
#else
ipsec_iattach(NULL);
#endif
-
}
static int
@@ -1804,6 +1809,17 @@ ipsec_iattach(const void *unused __unused)
return (0);
}
+
+#ifdef VIMAGE
+static int
+ipsec_idetach(const void *unused __unused)
+{
+
+ /* XXX revisit this! */
+
+ return (0);
+}
+#endif
SYSINIT(ipsec, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, ipsec_attach, NULL);
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c
index a38bb8d..e79179f 100644
--- a/sys/netipsec/key.c
+++ b/sys/netipsec/key.c
@@ -7223,9 +7223,75 @@ key_init(void)
keystat.getspi_count = 1;
printf("IPsec: Initialized Security Association Processing.\n");
+}
- return;
+#ifdef VIMAGE
+void
+key_destroy(void)
+{
+ INIT_VNET_IPSEC(curvnet);
+ struct secpolicy *sp, *nextsp;
+ struct secspacq *acq, *nextacq;
+ struct secashead *sah, *nextsah;
+ struct secreg *reg;
+ int i;
+
+ SPTREE_LOCK();
+ for (i = 0; i < IPSEC_DIR_MAX; i++) {
+ for (sp = LIST_FIRST(&V_sptree[i]);
+ sp != NULL; sp = nextsp) {
+ nextsp = LIST_NEXT(sp, chain);
+ if (__LIST_CHAINED(sp)) {
+ LIST_REMOVE(sp, chain);
+ free(sp, M_IPSEC_SP);
+ }
+ }
+ }
+ SPTREE_UNLOCK();
+
+ SAHTREE_LOCK();
+ for (sah = LIST_FIRST(&V_sahtree); sah != NULL; sah = nextsah) {
+ nextsah = LIST_NEXT(sah, chain);
+ if (__LIST_CHAINED(sah)) {
+ LIST_REMOVE(sah, chain);
+ free(sah, M_IPSEC_SAH);
+ }
+ }
+ SAHTREE_UNLOCK();
+
+ REGTREE_LOCK();
+ for (i = 0; i <= SADB_SATYPE_MAX; i++) {
+ LIST_FOREACH(reg, &V_regtree[i], chain) {
+ if (__LIST_CHAINED(reg)) {
+ LIST_REMOVE(reg, chain);
+ free(reg, M_IPSEC_SAR);
+ break;
+ }
+ }
+ }
+ REGTREE_UNLOCK();
+
+ ACQ_LOCK();
+ for (acq = LIST_FIRST(&V_spacqtree); acq != NULL; acq = nextacq) {
+ nextacq = LIST_NEXT(acq, chain);
+ if (__LIST_CHAINED(acq)) {
+ LIST_REMOVE(acq, chain);
+ free(acq, M_IPSEC_SAQ);
+ }
+ }
+ ACQ_UNLOCK();
+
+ SPACQ_LOCK();
+ for (acq = LIST_FIRST(&V_spacqtree); acq != NULL; acq = nextacq) {
+ nextacq = LIST_NEXT(acq, chain);
+ if (__LIST_CHAINED(acq)) {
+ LIST_REMOVE(acq, chain);
+ free(acq, M_IPSEC_SAQ);
+ }
+ }
+ SPACQ_UNLOCK();
}
+#endif
/*
* XXX: maybe This function is called after INBOUND IPsec processing.
diff --git a/sys/netipsec/key.h b/sys/netipsec/key.h
index 012b35c..fc38279 100644
--- a/sys/netipsec/key.h
+++ b/sys/netipsec/key.h
@@ -100,6 +100,9 @@ extern void key_randomfill __P((void *, size_t));
extern void key_freereg __P((struct socket *));
extern int key_parse __P((struct mbuf *, struct socket *));
extern void key_init __P((void));
+#ifdef VIMAGE
+extern void key_destroy(void);
+#endif
extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *));
extern void key_sa_routechange __P((struct sockaddr *));
extern void key_sa_stir_iv __P((struct secasvar *));
diff --git a/sys/netipsec/keysock.c b/sys/netipsec/keysock.c
index 6117f65..ec0fcf9 100644
--- a/sys/netipsec/keysock.c
+++ b/sys/netipsec/keysock.c
@@ -579,6 +579,9 @@ struct domain keydomain = {
.dom_family = PF_KEY,
.dom_name = "key",
.dom_init = key_init0,
+#ifdef VIMAGE
+ .dom_destroy = key_destroy,
+#endif
.dom_protosw = keysw,
.dom_protoswNPROTOSW = &keysw[sizeof(keysw)/sizeof(keysw[0])]
};
diff --git a/sys/sys/domain.h b/sys/sys/domain.h
index c78e50b..431429e 100644
--- a/sys/sys/domain.h
+++ b/sys/sys/domain.h
@@ -48,6 +48,8 @@ struct domain {
char *dom_name;
void (*dom_init) /* initialize domain data structures */
(void);
+ void (*dom_destroy) /* cleanup structures / state */
+ (void);
int (*dom_externalize) /* externalize access rights */
(struct mbuf *, struct mbuf **);
void (*dom_dispose) /* dispose of internalized rights */
@@ -56,6 +58,8 @@ struct domain {
struct domain *dom_next;
int (*dom_rtattach) /* initialize routing table */
(void **, int);
+ int (*dom_rtdetach) /* clean up routing table */
+ (void **, int);
int dom_rtoffset; /* an arg to rtattach, in bits */
/* XXX MRT.
* rtoffset May be 0 if the domain supplies its own rtattach(),
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 764a5a0..cf29f4a 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -57,7 +57,7 @@
* is created, otherwise 1.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 800096 /* Master, propagated to newvers */
+#define __FreeBSD_version 800097 /* Master, propagated to newvers */
#ifndef LOCORE
#include <sys/types.h>
diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h
index 9f064c5..b55af4b 100644
--- a/sys/sys/protosw.h
+++ b/sys/sys/protosw.h
@@ -70,6 +70,7 @@ typedef int pr_output_t (struct mbuf *, struct socket *);
typedef void pr_ctlinput_t (int, struct sockaddr *, void *);
typedef int pr_ctloutput_t (struct socket *, struct sockopt *);
typedef void pr_init_t (void);
+typedef void pr_destroy_t (void);
typedef void pr_fasttimo_t (void);
typedef void pr_slowtimo_t (void);
typedef void pr_drain_t (void);
@@ -86,6 +87,7 @@ struct protosw {
pr_ctloutput_t *pr_ctloutput; /* control output (from above) */
/* utility hooks */
pr_init_t *pr_init;
+ pr_destroy_t *pr_destroy;
pr_fasttimo_t *pr_fasttimo; /* fast timeout (200ms) */
pr_slowtimo_t *pr_slowtimo; /* slow timeout (500ms) */
pr_drain_t *pr_drain; /* flush any excess space possible */
diff --git a/sys/sys/vimage.h b/sys/sys/vimage.h
index 5c8b564..67a78f0 100644
--- a/sys/sys/vimage.h
+++ b/sys/sys/vimage.h
@@ -159,6 +159,7 @@ int vi_symlookup(struct kld_sym_lookup *, char *);
int vi_td_ioctl(u_long, struct vi_req *, struct thread *);
int vi_if_move(struct vi_req *, struct ifnet *, struct vimage *);
int vi_child_of(struct vimage *, struct vimage *);
+struct vimage *vimage_by_name(struct vimage *, char *);
void vnet_mod_register(const struct vnet_modinfo *);
void vnet_mod_register_multi(const struct vnet_modinfo *, void *, char *);
void vnet_mod_deregister(const struct vnet_modinfo *);
OpenPOWER on IntegriCloud