From owner-svn-src-head@FreeBSD.ORG Sun Jul 26 11:29:27 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1C3F1106564A; Sun, 26 Jul 2009 11:29:27 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 09D008FC14; Sun, 26 Jul 2009 11:29:27 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n6QBTQIL069004; Sun, 26 Jul 2009 11:29:26 GMT (envelope-from bz@svn.freebsd.org) Received: (from bz@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n6QBTQVT069000; Sun, 26 Jul 2009 11:29:26 GMT (envelope-from bz@svn.freebsd.org) Message-Id: <200907261129.n6QBTQVT069000@svn.freebsd.org> From: "Bjoern A. Zeeb" Date: Sun, 26 Jul 2009 11:29:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r195891 - in head/sys: kern net sys X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Jul 2009 11:29:27 -0000 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 ) 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 *),