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