PERFORCE change 161749 for review
Marko Zec
zec at FreeBSD.org
Thu May 7 21:39:42 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=161749
Change 161749 by zec at zec_tpx32 on 2009/05/07 21:39:21
Glue in the interim management API and make it compile.
Affected files ...
.. //depot/projects/vimage-commit2/src/sys/kern/kern_vimage.c#30 edit
.. //depot/projects/vimage-commit2/src/sys/net/if.c#54 edit
.. //depot/projects/vimage-commit2/src/sys/net/if_var.h#22 edit
.. //depot/projects/vimage-commit2/src/sys/sys/sockio.h#3 edit
.. //depot/projects/vimage-commit2/src/sys/sys/vimage.h#55 edit
Differences ...
==== //depot/projects/vimage-commit2/src/sys/kern/kern_vimage.c#30 (text+ko) ====
@@ -34,16 +34,23 @@
#include "opt_ddb.h"
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/linker.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sx.h>
+#include <sys/refcount.h>
#include <sys/vimage.h>
#ifdef DDB
#include <ddb/ddb.h>
#endif
+#include <net/if.h>
+#include <net/route.h>
+#include <net/vnet.h>
+
#ifndef VIMAGE_GLOBALS
MALLOC_DEFINE(M_VIMAGE, "vimage", "vimage resource container");
@@ -56,17 +63,375 @@
static int vnet_mod_constructor(struct vnet_modlink *);
static int vnet_mod_destructor(struct vnet_modlink *);
+static struct vimage *vimage_by_name(struct vimage *, char *);
+static struct vimage *vi_alloc(struct vimage *, char *);
+
+#define VNET_LIST_LOCK() \
+ mtx_lock(&vnet_list_refc_mtx); \
+ while (vnet_list_refc != 0) \
+ cv_wait(&vnet_list_condvar, &vnet_list_refc_mtx);
+
+#define VNET_LIST_UNLOCK() \
+ mtx_unlock(&vnet_list_refc_mtx);
+
#ifdef VIMAGE
struct vimage_list_head vimage_head;
struct vnet_list_head vnet_head;
struct vprocg_list_head vprocg_head;
+
+struct cv vnet_list_condvar;
+struct mtx vnet_list_refc_mtx;
+int vnet_list_refc = 0;
+
+static u_int last_vi_id = 0;
+static u_int last_vnet_id = 0;
+static u_int last_vprocg_id = 0;
#else
#ifndef VIMAGE_GLOBALS
struct vprocg vprocg_0;
#endif
#endif
+/*
+ * Userspace interfaces.
+ */
+
+static int
+vi_child_of(struct vimage *parent, struct vimage *child)
+{
+ if (child == parent)
+ return (0);
+ for (; child; child = child->vi_parent)
+ if (child == parent)
+ return (1);
+ return (0);
+}
+
+/*
+ * if_reassign_common() should be called by all device specific
+ * ifnet reassignment routines after the interface is detached from
+ * current vnet and before the interface gets attached to the target
+ * vnet. This routine attempts to shrink if_index in current vnet,
+ * find an unused if_index in target vnet and calls if_grow() if
+ * necessary, and finally finds an unused if_xname for the target
+ * vnet.
+ *
+ * XXX this routine should hold a lock over if_index and return with
+ * such a lock held, and the caller should release that lock
+ * after ifattach completes!
+ */
void
+if_reassign_common(struct ifnet *ifp, struct vnet *new_vnet, const char *dname)
+{
+ /* do/while construct needed to confine scope of INIT_VNET_NET() */
+ do {
+ INIT_VNET_NET(curvnet);
+
+ IFNET_WLOCK();
+ ifnet_setbyindex(ifp->if_index, NULL);
+ while (V_if_index > 0 && ifnet_byindex(V_if_index) == NULL)
+ V_if_index--;
+ IFNET_WUNLOCK();
+ } while (0);
+
+ CURVNET_SET_QUIET(new_vnet);
+ INIT_VNET_NET(new_vnet);
+ /*
+ * Try to find an empty slot below if_index. If we fail, take
+ * the next slot.
+ */
+ IFNET_WLOCK();
+ for (ifp->if_index = 1; ifp->if_index <= V_if_index; ifp->if_index++) {
+ if (ifnet_byindex(ifp->if_index) == NULL)
+ break;
+ }
+ /* Catch if_index overflow. */
+ if (ifp->if_index < 1)
+ panic("vi_if_move: if_index overflow");
+
+ if (ifp->if_index > V_if_index)
+ V_if_index = ifp->if_index;
+ if (V_if_index >= V_if_indexlim)
+ if_grow();
+ ifnet_setbyindex(ifp->if_index, ifp);
+ IFNET_WUNLOCK();
+
+ /* Rename the ifnet */
+ if (new_vnet == ifp->if_home_vnet) {
+ /* always restore the original name on return to home vnet */
+ snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ifp->if_dname,
+ ifp->if_dunit);
+ } else {
+ int unit = 0;
+ struct ifnet *iter;
+
+ do {
+ snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", dname, unit);
+ TAILQ_FOREACH(iter, &V_ifnet, if_link)
+ if (strcmp(ifp->if_xname, iter->if_xname) == 0)
+ break;
+ unit++;
+ } while (iter);
+ }
+ CURVNET_RESTORE();
+}
+
+/*
+ * Move the interface to another vnet. The interface can be specified either
+ * by ifp argument, or by name contained in vi_req->vi_if_xname if NULL is
+ * passed as ifp. The interface will be renamed to vi_req->vi_parent_name
+ * if vi_req->vi_parent_name is not an empty string (uff ugly ugly)...
+ * Similary, the target vnet can be specified either by vnet argument or
+ * by name. If vnet name equals to ".." or vi_req is set to NULL the
+ * interface is moved to the parent vnet.
+ */
+int
+vi_if_move(struct vi_req *vi_req, struct ifnet *ifp, struct vimage *vip)
+{
+ struct vimage *new_vip;
+ struct vnet *new_vnet = NULL;
+
+ if (vi_req == NULL || strcmp(vi_req->vi_name, "..") == 0) {
+ if (IS_DEFAULT_VIMAGE(vip))
+ return (ENXIO);
+ new_vnet = vip->vi_parent->v_net;
+ } else {
+ new_vip = vimage_by_name(vip, vi_req->vi_name);
+ if (new_vip == NULL)
+ return (ENXIO);
+ new_vnet = new_vip->v_net;
+ }
+
+ if (ifp == NULL)
+ ifp = ifunit(vi_req->vi_if_xname);
+ if (ifp == NULL)
+ return (ENXIO);
+
+ /* Abort if driver did not provide a if_reassign() method */
+ if (ifp->if_reassign == NULL)
+ return (ENODEV);
+
+ if (vi_req != NULL) {
+ struct ifnet *t_ifp;
+
+ CURVNET_SET_QUIET(new_vnet);
+ t_ifp = ifunit(vi_req->vi_if_xname);
+ CURVNET_RESTORE();
+ if (t_ifp != NULL)
+ return (EEXIST);
+ }
+
+ if (vi_req && strlen(vi_req->vi_if_xname) > 0)
+ ifp->if_reassign(ifp, new_vnet, vi_req->vi_if_xname);
+ else
+ ifp->if_reassign(ifp, new_vnet, NULL);
+ getmicrotime(&ifp->if_lastchange);
+
+ /* Report the new if_xname back to the userland */
+ if (vi_req != NULL)
+ sprintf(vi_req->vi_if_xname, "%s", ifp->if_xname);
+
+ return (0);
+}
+
+static struct vimage *
+vimage_by_name(struct vimage *top, char *name)
+{
+ struct vimage *vip;
+ char *next_name;
+ int namelen;
+
+ next_name = strchr(name, '.');
+ if (next_name != NULL) {
+ namelen = next_name - name;
+ next_name++;
+ if (namelen == 0) {
+ if (strlen(next_name) == 0)
+ return(top); /* '.' == this vimage */
+ else
+ return(NULL);
+ }
+ } else
+ namelen = strlen(name);
+ if (namelen == 0)
+ return(NULL);
+ LIST_FOREACH(vip, &top->vi_child_head, vi_sibling)
+ if (strlen(vip->vi_name) == namelen &&
+ strncmp(name, vip->vi_name, namelen) == 0) {
+ if (next_name != NULL)
+ return(vimage_by_name(vip, next_name));
+ else
+ return(vip);
+ }
+ return(NULL);
+}
+
+static void
+vimage_relative_name(struct vimage *top, struct vimage *where,
+ char *buffer, int bufflen)
+{
+ int used = 1;
+
+ if (where == top) {
+ sprintf(buffer, ".");
+ return;
+ } else
+ *buffer = 0;
+
+ do {
+ int namelen = strlen(where->vi_name);
+
+ if (namelen + used + 1 >= bufflen)
+ panic("buffer overflow");
+
+ if (used > 1) {
+ bcopy(buffer, &buffer[namelen + 1], used);
+ buffer[namelen] = '.';
+ used++;
+ } else
+ bcopy(buffer, &buffer[namelen], used);
+ bcopy(where->vi_name, buffer, namelen);
+ used += namelen;
+ where = where->vi_parent;
+ } while (where != top);
+}
+
+static struct vimage *
+vimage_get_next(struct vimage *top, struct vimage *where, int recurse)
+{
+ struct vimage *next;
+
+ if (recurse) {
+ /* Try to go deeper in the hierarchy */
+ next = LIST_FIRST(&where->vi_child_head);
+ if (next != NULL)
+ return(next);
+ }
+
+ do {
+ /* Try to find next sibling */
+ next = LIST_NEXT(where, vi_sibling);
+ if (!recurse || next != NULL)
+ return(next);
+
+ /* Nothing left on this level, go one level up */
+ where = where->vi_parent;
+ } while (where != top->vi_parent);
+
+ /* Nothing left to be visited, we are done */
+ return(NULL);
+}
+
+int
+vi_td_ioctl(u_long cmd, struct vi_req *vi_req, struct thread *td)
+{
+ int error = 0;
+ struct vimage *vip = TD_TO_VIMAGE(td);
+ struct vimage *vip_r = NULL;
+
+#if 0
+ error = priv_check(td, PRIV_ROOT);
+ if (error)
+ return (error);
+#endif
+
+ vip_r = vimage_by_name(vip, vi_req->vi_name);
+ if (vip_r == NULL && !(vi_req->vi_req_action & VI_CREATE))
+ return (ESRCH);
+ if (vip_r != NULL && vi_req->vi_req_action & VI_CREATE)
+ return (EADDRINUSE);
+ if (vi_req->vi_req_action == VI_GETNEXT) {
+ vip_r = vimage_get_next(vip, vip_r, 0);
+ if (vip_r == NULL)
+ return (ESRCH);
+ }
+ if (vi_req->vi_req_action == VI_GETNEXT_RECURSE) {
+ vip_r = vimage_get_next(vip, vip_r, 1);
+ if (vip_r == NULL)
+ return (ESRCH);
+ }
+
+ if (vip_r && !vi_child_of(vip, vip_r) && /* XXX delete the rest? */
+ vi_req->vi_req_action != VI_GET &&
+ vi_req->vi_req_action != VI_GETNEXT)
+ return (EPERM);
+
+ switch (cmd) {
+
+ case SIOCGPVIMAGE:
+ vimage_relative_name(vip, vip_r, vi_req->vi_name,
+ sizeof (vi_req->vi_name));
+ vi_req->vi_proc_count = vip_r->v_procg->nprocs;
+ vi_req->vi_if_count = vip_r->v_net->ifcnt;
+ vi_req->vi_sock_count = vip_r->v_net->sockcnt;
+ break;
+
+ case SIOCSPVIMAGE:
+ if (vi_req->vi_req_action == VI_DESTROY) {
+#ifdef NOTYET
+ error = vi_destroy(vip_r);
+#endif
+ break;
+ }
+
+ if (vi_req->vi_req_action == VI_SWITCHTO) {
+ struct proc *p = td->td_proc;
+ struct ucred *oldcred, *newcred;
+
+ /*
+ * XXX priv_check()?
+ * XXX allow only a single td per proc here?
+ */
+ newcred = crget();
+ PROC_LOCK(p);
+ oldcred = p->p_ucred;
+ setsugid(p);
+ crcopy(newcred, oldcred);
+ refcount_release(&newcred->cr_vimage->vi_ucredrefc);
+ newcred->cr_vimage = vip_r;
+ refcount_acquire(&newcred->cr_vimage->vi_ucredrefc);
+ p->p_ucred = newcred;
+ PROC_UNLOCK(p);
+ sx_xlock(&allproc_lock);
+ oldcred->cr_vimage->v_procg->nprocs--;
+ refcount_release(&oldcred->cr_vimage->vi_ucredrefc);
+ P_TO_VPROCG(p)->nprocs++;
+ sx_xunlock(&allproc_lock);
+ crfree(oldcred);
+ break;
+ }
+
+ if (vi_req->vi_req_action & VI_CREATE) {
+ char *dotpos;
+
+ dotpos = strrchr(vi_req->vi_name, '.');
+ if (dotpos != NULL) {
+ *dotpos = 0;
+ vip = vimage_by_name(vip, vi_req->vi_name);
+ if (vip == NULL)
+ return (ESRCH);
+ dotpos++;
+ vip_r = vi_alloc(vip, dotpos);
+ } else
+ vip_r = vi_alloc(vip, vi_req->vi_name);
+ if (vip_r == NULL)
+ return (ENOMEM);
+ }
+
+ /* XXX What the hell is this doing here? */
+ if (vip == vip_r && !IS_DEFAULT_VIMAGE(vip))
+ return (EPERM);
+ }
+
+ return (error);
+}
+
+
+/*
+ * Kernel interfaces and handlers.
+ */
+
+void
vnet_mod_register(const struct vnet_modinfo *vmi)
{
@@ -297,6 +662,68 @@
return (ENOENT);
}
+static struct vimage *
+vi_alloc(struct vimage *parent, char *name)
+{
+ struct vimage *vip;
+ struct vnet *vnet;
+ struct vprocg *vprocg;
+ struct vnet_modlink *vml;
+
+ /*
+ * XXX don't forget the locking
+ */
+
+ /* A brute force check whether there's enough mem for a new vimage */
+ vip = malloc(512*1024, M_VIMAGE, M_NOWAIT); /* XXX aaaargh... */
+ if (vip == NULL)
+ goto vi_alloc_done;
+ free(vip, M_VIMAGE);
+
+ vip = malloc(sizeof(struct vimage), M_VIMAGE, M_NOWAIT | M_ZERO);
+ if (vip == NULL)
+ panic("vi_alloc: malloc failed for vimage \"%s\"\n", name);
+ vip->vi_id = last_vi_id++;
+ LIST_INIT(&vip->vi_child_head);
+ sprintf(vip->vi_name, "%s", name);
+ vip->vi_parent = parent;
+ /* XXX locking */
+ if (parent != NULL)
+ LIST_INSERT_HEAD(&parent->vi_child_head, vip, vi_sibling);
+ else if (!LIST_EMPTY(&vimage_head))
+ panic("there can be only one default vimage!");
+ LIST_INSERT_HEAD(&vimage_head, vip, vi_le);
+
+ vnet = malloc(sizeof(struct vnet), M_VNET, M_NOWAIT | M_ZERO);
+ if (vnet == NULL)
+ panic("vi_alloc: malloc failed for vnet \"%s\"\n", name);
+ vip->v_net = vnet;
+ vnet->vnet_id = last_vnet_id++;
+ vnet->vnet_magic_n = VNET_MAGIC_N;
+
+ vprocg = malloc(sizeof(struct vprocg), M_VPROCG, M_NOWAIT | M_ZERO);
+ if (vprocg == NULL)
+ panic("vi_alloc: malloc failed for vprocg \"%s\"\n", name);
+ vip->v_procg = vprocg;
+ vprocg->vprocg_id = last_vprocg_id++;
+
+ /* Initialize / attach vnet module instances. */
+ CURVNET_SET_QUIET(vnet);
+ TAILQ_FOREACH(vml, &vnet_modlink_head, vml_mod_le)
+ vnet_mod_constructor(vml);
+ CURVNET_RESTORE();
+
+ VNET_LIST_LOCK();
+ LIST_INSERT_HEAD(&vnet_head, vnet, vnet_le);
+ VNET_LIST_UNLOCK();
+
+ /* XXX locking */
+ LIST_INSERT_HEAD(&vprocg_head, vprocg, vprocg_le);
+
+vi_alloc_done:
+ return (vip);
+}
+
static void
vi_init(void *unused)
{
==== //depot/projects/vimage-commit2/src/sys/net/if.c#54 (text+ko) ====
@@ -2187,6 +2187,20 @@
ifr = (struct ifreq *)data;
switch (cmd) {
+#ifdef VIMAGE
+ /*
+ * XXX Should be implemented as separate system calls. This is
+ * just a temporary hack!
+ */
+ case SIOCSIFVIMAGE:
+ error = vi_if_move((struct vi_req *) data, NULL,
+ TD_TO_VIMAGE(td));
+ return (error);
+ case SIOCSPVIMAGE:
+ case SIOCGPVIMAGE:
+ error = vi_td_ioctl(cmd, (struct vi_req *) data, td);
+ return (error);
+#endif
case SIOCIFCREATE:
case SIOCIFCREATE2:
error = priv_check(td, PRIV_NET_IFCREATE);
==== //depot/projects/vimage-commit2/src/sys/net/if_var.h#22 (text+ko) ====
@@ -169,6 +169,8 @@
(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 ifaddr *if_addr; /* pointer to link-level address */
void *if_llsoftc; /* link layer softc */
int if_drv_flags; /* driver-managed status flags */
@@ -194,6 +196,8 @@
void *if_lagg; /* lagg glue */
u_char if_alloctype; /* if_type at time of allocation */
+ struct vnet *if_home_vnet; /* where this ifnet originates from */
+
/*
* Spare fields are added so that we can modify sensitive data
* structures without changing the kernel binary interface, and must
==== //depot/projects/vimage-commit2/src/sys/sys/sockio.h#3 (text+ko) ====
@@ -108,6 +108,10 @@
#define SIOCGPRIVATE_0 _IOWR('i', 80, struct ifreq) /* device private 0 */
#define SIOCGPRIVATE_1 _IOWR('i', 81, struct ifreq) /* device private 1 */
+#define SIOCSPVIMAGE _IOW('i', 101, struct vi_req) /* set proc vimage */
+#define SIOCGPVIMAGE _IOWR('i', 102, struct vi_req) /* get proc vimage */
+#define SIOCSIFVIMAGE _IOWR('i', 103, struct vi_req) /* set ifc vi/net */
+
#define SIOCSDRVSPEC _IOW('i', 123, struct ifdrv) /* set driver-specific
parameters */
#define SIOCGDRVSPEC _IOWR('i', 123, struct ifdrv) /* get driver-specific
==== //depot/projects/vimage-commit2/src/sys/sys/vimage.h#55 (text+ko) ====
@@ -36,6 +36,33 @@
#include <sys/proc.h>
#include <sys/queue.h>
+/* Interim userspace API. */
+struct vi_req {
+ int vi_api_cookie; /* Catch API mismatch. */
+ int vi_req_action; /* What to do with this reqest? */
+ u_short vi_proc_count; /* Current number of processes. */
+ u_short vi_child_count; /* Current number of child vimages. */
+ int vi_if_count; /* Current number network interfaces. */
+ int vi_sock_count;
+ char vi_name[MAXPATHLEN];
+ char vi_if_xname[MAXPATHLEN]; /* XXX should be IFNAMSIZ */
+};
+
+#define VI_CREATE 0x00000001
+#define VI_DESTROY 0x00000002
+#define VI_SWITCHTO 0x00000008
+#define VI_IFACE 0x00000010
+#define VI_GET 0x00000100
+#define VI_GETNEXT 0x00000200
+#define VI_GETNEXT_RECURSE 0x00000300
+#define VI_SET_NAME 0x00100000
+
+#define VI_API_VERSION 1 /* Bump on struct changes. */
+
+#define VI_API_COOKIE ((sizeof(struct vi_req) << 16) | VI_API_VERSION)
+
+#ifdef _KERNEL
+
#if defined(VIMAGE) && defined(VIMAGE_GLOBALS)
#error "You cannot have both option VIMAGE and option VIMAGE_GLOBALS!"
#endif
@@ -46,13 +73,14 @@
struct vprocg;
struct vnet;
+struct vi_req;
+struct ifnet;
struct kld_sym_lookup;
typedef int vnet_attach_fn(const void *);
typedef int vnet_detach_fn(const void *);
#ifndef VIMAGE_GLOBALS
-
struct vnet_symmap {
char *name;
size_t offset;
@@ -128,6 +156,9 @@
#define V_MOD_vprocg 0 /* no minor module ids like in vnet */
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 *);
+void if_reassign_common(struct ifnet *, struct vnet *, const 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 *);
@@ -460,4 +491,6 @@
#define VIMAGE_CTASSERT(x, y) struct __hack
#endif
+#endif /* _KERNEL */
+
#endif /* !_SYS_VIMAGE_H_ */
More information about the p4-projects
mailing list