svn commit: r195891 - in head/sys: kern net sys

Bjoern A. Zeeb bz at FreeBSD.org
Sun Jul 26 11:29:27 UTC 2009


Author: bz
Date: Sun Jul 26 11:29:26 2009
New Revision: 195891
URL: http://svn.freebsd.org/changeset/base/195891

Log:
  Make the in-kernel logic for the SIOCSIFVNET, SIOCSIFRVNET ioctls
  (ifconfig ifN (-)vnet <jname|jid>) work correctly.
  
  Move vi_if_move to if.c and split it up into two functions(*),
  one for each ioctl.
  
  In the reclaim case, correctly set the vnet before calling if_vmove.
  
  Instead of silently allowing a move of an interface from the current
  vnet to the current vnet, return an error. (*)
  
  There is some duplicate interface name checking before actually moving
  the interface between network stacks without locking and thus race
  prone. Ideally if_vmove will correctly and automagically handle these
  in the future.
  
  Suggested by:	rwatson (*)
  Approved by:	re (kib)

Modified:
  head/sys/kern/kern_vimage.c
  head/sys/net/if.c
  head/sys/sys/vimage.h

Modified: head/sys/kern/kern_vimage.c
==============================================================================
--- head/sys/kern/kern_vimage.c	Sun Jul 26 11:25:57 2009	(r195890)
+++ head/sys/kern/kern_vimage.c	Sun Jul 26 11:29:26 2009	(r195891)
@@ -68,61 +68,6 @@ struct sx		vnet_sxlock;
 struct vnet_list_head vnet_head;
 struct vnet *vnet0;
 
-/*
- * Move an ifnet to or from another vnet, specified by the jail id.
- */
-int
-vi_if_move(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
-{
-	struct ifnet *t_ifp;
-	struct prison *pr;
-	struct vnet *new_vnet;
-	int error;
-
-	sx_slock(&allprison_lock);
-	pr = prison_find_child(td->td_ucred->cr_prison, jid);
-	sx_sunlock(&allprison_lock);
-	if (pr == NULL)
-		return (ENXIO);
-	prison_hold_locked(pr);
-	mtx_unlock(&pr->pr_mtx);
-	if (ifp != NULL) {
-		/* SIOCSIFVNET */
-		new_vnet = pr->pr_vnet;
-	} else {
-		/* SIOCSIFRVNET */
-		new_vnet = TD_TO_VNET(td);
-		CURVNET_SET(pr->pr_vnet);
-		ifp = ifunit(ifname);
-		CURVNET_RESTORE();
-		if (ifp == NULL) {
-			prison_free(pr);
-			return (ENXIO);
-		}
-	}
-
-	error = 0;
-	if (new_vnet != ifp->if_vnet) {
-		/*
-		 * Check for naming clashes in target vnet.  Not locked so races
-		 * are possible.
-		 */
-		CURVNET_SET_QUIET(new_vnet);
-		t_ifp = ifunit(ifname);
-		CURVNET_RESTORE();
-		if (t_ifp != NULL)
-			error = EEXIST;
-		else {
-			/* Detach from curvnet and attach to new_vnet. */
-			if_vmove(ifp, new_vnet);
-
-			/* Report the new if_xname back to the userland */
-			sprintf(ifname, "%s", ifp->if_xname);
-		}
-	}
-	prison_free(pr);
-	return (error);
-}
 
 struct vnet *
 vnet_alloc(void)

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Sun Jul 26 11:25:57 2009	(r195890)
+++ head/sys/net/if.c	Sun Jul 26 11:29:26 2009	(r195891)
@@ -894,6 +894,94 @@ if_vmove(struct ifnet *ifp, struct vnet 
 
 	CURVNET_RESTORE();
 }
+
+/*
+ * Move an ifnet to or from another child prison/vnet, specified by the jail id.
+ */
+static int
+if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
+{
+	struct prison *pr;
+	struct ifnet *difp;
+
+	/* Try to find the prison within our visibility. */
+	sx_slock(&allprison_lock);
+	pr = prison_find_child(td->td_ucred->cr_prison, jid);
+	sx_sunlock(&allprison_lock);
+	if (pr == NULL)
+		return (ENXIO);
+	prison_hold_locked(pr);
+	mtx_unlock(&pr->pr_mtx);
+
+	/* Do not try to move the iface from and to the same prison. */
+	if (pr->pr_vnet == ifp->if_vnet) {
+		prison_free(pr);
+		return (EEXIST);
+	}
+
+	/* Make sure the named iface does not exists in the dst. prison/vnet. */
+	/* XXX Lock interfaces to avoid races. */
+	CURVNET_SET(pr->pr_vnet);
+	difp = ifunit(ifname);
+	CURVNET_RESTORE();
+	if (difp != NULL) {
+		prison_free(pr);
+		return (EEXIST);
+	}
+
+	/* Move the interface into the child jail/vnet. */
+	if_vmove(ifp, pr->pr_vnet);
+
+	/* Report the new if_xname back to the userland. */
+	sprintf(ifname, "%s", ifp->if_xname);
+
+	prison_free(pr);
+	return (0);
+}
+
+static int
+if_vmove_reclaim(struct thread *td, char *ifname, int jid)
+{
+	struct prison *pr;
+	struct vnet *vnet_dst;
+	struct ifnet *ifp;
+
+	/* Try to find the prison within our visibility. */
+	sx_slock(&allprison_lock);
+	pr = prison_find_child(td->td_ucred->cr_prison, jid);
+	sx_sunlock(&allprison_lock);
+	if (pr == NULL)
+		return (ENXIO);
+	prison_hold_locked(pr);
+	mtx_unlock(&pr->pr_mtx);
+
+	/* Make sure the named iface exists in the source prison/vnet. */
+	CURVNET_SET(pr->pr_vnet);
+	ifp = ifunit(ifname);		/* XXX Lock to avoid races. */
+	if (ifp == NULL) {
+		CURVNET_RESTORE();
+		prison_free(pr);
+		return (ENXIO);
+	}
+
+	/* Do not try to move the iface from and to the same prison. */
+	vnet_dst = TD_TO_VNET(td);
+	if (vnet_dst == ifp->if_vnet) {
+		CURVNET_RESTORE();
+		prison_free(pr);
+		return (EEXIST);
+	}
+
+	/* Get interface back from child jail/vnet. */
+	if_vmove(ifp, vnet_dst);
+	CURVNET_RESTORE();
+
+	/* Report the new if_xname back to the userland. */
+	sprintf(ifname, "%s", ifp->if_xname);
+
+	prison_free(pr);
+	return (0);
+}
 #endif /* VIMAGE */
 
 /*
@@ -1990,7 +2078,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp,
 		error = priv_check(td, PRIV_NET_SETIFVNET);
 		if (error)
 			return (error);
-		error = vi_if_move(td, ifp, ifr->ifr_name, ifr->ifr_jid);
+		error = if_vmove_loan(td, ifp, ifr->ifr_name, ifr->ifr_jid);
 		break;
 #endif
 
@@ -2184,7 +2272,7 @@ ifioctl(struct socket *so, u_long cmd, c
 		error = priv_check(td, PRIV_NET_SETIFVNET);
 		if (error)
 			return (error);
-		return (vi_if_move(td, NULL, ifr->ifr_name, ifr->ifr_jid));
+		return (if_vmove_reclaim(td, ifr->ifr_name, ifr->ifr_jid));
 #endif
 	case SIOCIFCREATE:
 	case SIOCIFCREATE2:

Modified: head/sys/sys/vimage.h
==============================================================================
--- head/sys/sys/vimage.h	Sun Jul 26 11:25:57 2009	(r195890)
+++ head/sys/sys/vimage.h	Sun Jul 26 11:29:26 2009	(r195891)
@@ -67,7 +67,6 @@ struct vnet {
 
 struct vnet;
 struct ifnet;
-int	vi_if_move(struct thread *, struct ifnet *, char *, int);
 struct vnet *vnet_alloc(void);
 void	vnet_destroy(struct vnet *);
 void	vnet_foreach(void (*vnet_foreach_fn)(struct vnet *, void *),


More information about the svn-src-head mailing list