From owner-svn-src-head@FreeBSD.ORG Mon Mar 2 20:00:04 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id ACE4E148; Mon, 2 Mar 2015 20:00:04 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 972A1CDD; Mon, 2 Mar 2015 20:00:04 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t22K04Hg057978; Mon, 2 Mar 2015 20:00:04 GMT (envelope-from hrs@FreeBSD.org) Received: (from hrs@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t22K03sY057966; Mon, 2 Mar 2015 20:00:03 GMT (envelope-from hrs@FreeBSD.org) Message-Id: <201503022000.t22K03sY057966@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: hrs set sender to hrs@FreeBSD.org using -f From: Hiroki Sato Date: Mon, 2 Mar 2015 20:00:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279538 - head/sys/net X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 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: Mon, 02 Mar 2015 20:00:04 -0000 Author: hrs Date: Mon Mar 2 20:00:03 2015 New Revision: 279538 URL: https://svnweb.freebsd.org/changeset/base/279538 Log: Fix group membership of cloned interfaces when one is moved by if_vmove(). In if_vmove(), if_detach_internal() and if_attach_internal() were called in series to detach and reattach the interface. When detaching, if_delgroup() was called and the interface leaves all of the group membership. And then upon attachment, if_addgroup(ifp, IFG_ALL) was called and it joined only "all" group again. This had a problem. Normally, a cloned interface automatically joins a group whose name is ifc_name of the cloner in addition to "all" upon creation. However, if_vmove() removed the membership and did not restore upon attachment. Differential Revision: https://reviews.freebsd.org/D1859 Modified: head/sys/net/if.c head/sys/net/if_clone.c head/sys/net/if_clone.h Modified: head/sys/net/if.c ============================================================================== --- head/sys/net/if.c Mon Mar 2 19:14:58 2015 (r279537) +++ head/sys/net/if.c Mon Mar 2 20:00:03 2015 (r279538) @@ -172,8 +172,8 @@ static void do_link_state_change(void *, static int if_getgroup(struct ifgroupreq *, struct ifnet *); static int if_getgroupmembers(struct ifgroupreq *); static void if_delgroups(struct ifnet *); -static void if_attach_internal(struct ifnet *, int); -static void if_detach_internal(struct ifnet *, int); +static void if_attach_internal(struct ifnet *, int, struct if_clone *); +static void if_detach_internal(struct ifnet *, int, struct if_clone **); #ifdef INET6 /* @@ -558,6 +558,15 @@ ifq_delete(struct ifaltq *ifq) * tasks, given that we are moving from one vnet to another an ifnet which * has already been fully initialized. * + * Note that if_detach_internal() removes group membership unconditionally + * even when vmove flag is set, and if_attach_internal() adds only IFG_ALL. + * Thus, when if_vmove() is applied to a cloned interface, group membership + * is lost while a cloned one always joins a group whose name is + * ifc->ifc_name. To recover this after if_detach_internal() and + * if_attach_internal(), the cloner should be specified to + * if_attach_internal() via ifc. If it is non-NULL, if_attach_internal() + * attempts to join a group whose name is ifc->ifc_name. + * * XXX: * - The decision to return void and thus require this function to * succeed is questionable. @@ -568,7 +577,7 @@ void if_attach(struct ifnet *ifp) { - if_attach_internal(ifp, 0); + if_attach_internal(ifp, 0, NULL); } /* @@ -623,7 +632,7 @@ if_hw_tsomax_update(if_t ifp, struct ifn } static void -if_attach_internal(struct ifnet *ifp, int vmove) +if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) { unsigned socksize, ifasize; int namelen, masklen; @@ -642,6 +651,10 @@ if_attach_internal(struct ifnet *ifp, in if_addgroup(ifp, IFG_ALL); + /* Restore group membership for cloned interfaces. */ + if (vmove && ifc != NULL) + if_clone_addgroup(ifp, ifc); + getmicrotime(&ifp->if_lastchange); ifp->if_epoch = time_uptime; @@ -860,12 +873,12 @@ if_detach(struct ifnet *ifp) { CURVNET_SET_QUIET(ifp->if_vnet); - if_detach_internal(ifp, 0); + if_detach_internal(ifp, 0, NULL); CURVNET_RESTORE(); } static void -if_detach_internal(struct ifnet *ifp, int vmove) +if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) { struct ifaddr *ifa; struct radix_node_head *rnh; @@ -894,6 +907,10 @@ if_detach_internal(struct ifnet *ifp, in return; /* XXX this should panic as well? */ } + /* Check if this is a cloned interface or not. */ + if (vmove && ifcp != NULL) + *ifcp = if_clone_findifc(ifp); + /* * Remove/wait for pending events. */ @@ -999,12 +1016,13 @@ if_detach_internal(struct ifnet *ifp, in void if_vmove(struct ifnet *ifp, struct vnet *new_vnet) { + struct if_clone *ifc; /* * Detach from current vnet, but preserve LLADDR info, do not * mark as dead etc. so that the ifnet can be reattached later. */ - if_detach_internal(ifp, 1); + if_detach_internal(ifp, 1, &ifc); /* * Unlink the ifnet from ifindex_table[] in current vnet, and shrink @@ -1034,7 +1052,7 @@ if_vmove(struct ifnet *ifp, struct vnet ifnet_setbyindex_locked(ifp->if_index, ifp); IFNET_WUNLOCK(); - if_attach_internal(ifp, 1); + if_attach_internal(ifp, 1, ifc); CURVNET_RESTORE(); } Modified: head/sys/net/if_clone.c ============================================================================== --- head/sys/net/if_clone.c Mon Mar 2 19:14:58 2015 (r279537) +++ head/sys/net/if_clone.c Mon Mar 2 20:00:03 2015 (r279538) @@ -518,6 +518,49 @@ done: } /* + * if_clone_findifc() looks up ifnet from the current + * cloner list, and returns ifc if found. Note that ifc_refcnt + * is incremented. + */ +struct if_clone * +if_clone_findifc(struct ifnet *ifp) +{ + struct if_clone *ifc, *ifc0; + struct ifnet *ifcifp; + + ifc0 = NULL; + IF_CLONERS_LOCK(); + LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { + IF_CLONE_LOCK(ifc); + LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { + if (ifp == ifcifp) { + ifc0 = ifc; + IF_CLONE_ADDREF_LOCKED(ifc); + break; + } + } + IF_CLONE_UNLOCK(ifc); + if (ifc0 != NULL) + break; + } + IF_CLONERS_UNLOCK(); + + return (ifc0); +} + +/* + * if_clone_addgroup() decrements ifc_refcnt because it is called after + * if_clone_findifc(). + */ +void +if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc) +{ + + if_addgroup(ifp, ifc->ifc_name); + IF_CLONE_REMREF(ifc); +} + +/* * A utility function to extract unit numbers from interface names of * the form name###. * Modified: head/sys/net/if_clone.h ============================================================================== --- head/sys/net/if_clone.h Mon Mar 2 19:14:58 2015 (r279537) +++ head/sys/net/if_clone.h Mon Mar 2 20:00:03 2015 (r279538) @@ -69,6 +69,8 @@ void vnet_if_clone_init(void); int if_clone_create(char *, size_t, caddr_t); int if_clone_destroy(const char *); int if_clone_list(struct if_clonereq *); +struct if_clone *if_clone_findifc(struct ifnet *); +void if_clone_addgroup(struct ifnet *, struct if_clone *); /* The below interface used only by epair(4). */ int if_clone_destroyif(struct if_clone *, struct ifnet *);