From owner-svn-src-head@FreeBSD.ORG Fri May 22 22:09:00 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 69D581065686; Fri, 22 May 2009 22:09:00 +0000 (UTC) (envelope-from zec@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 56CBE8FC1C; Fri, 22 May 2009 22:09:00 +0000 (UTC) (envelope-from zec@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 n4MM9066020362; Fri, 22 May 2009 22:09:00 GMT (envelope-from zec@svn.freebsd.org) Received: (from zec@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n4MM90hA020358; Fri, 22 May 2009 22:09:00 GMT (envelope-from zec@svn.freebsd.org) Message-Id: <200905222209.n4MM90hA020358@svn.freebsd.org> From: Marko Zec Date: Fri, 22 May 2009 22:09:00 +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: r192605 - 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: Fri, 22 May 2009 22:09:01 -0000 Author: zec Date: Fri May 22 22:09:00 2009 New Revision: 192605 URL: http://svn.freebsd.org/changeset/base/192605 Log: Introduce the if_vmove() function, which will be used in the future for reassigning ifnets from one vnet to another. if_vmove() works by calling a restricted subset of actions normally executed by if_detach() on an ifnet in the current vnet, and then switches to the target vnet and executes an appropriate subset of if_attach() actions there. if_attach() and if_detach() have become wrapper functions around if_attach_internal() and if_detach_internal(), where the later variants have an additional argument, a flag indicating whether a full attach or detach sequence is to be executed, or only a restricted subset suitable for moving an ifnet from one vnet to another. Hence, if_vmove() will not call if_detach() and if_attach() directly, but will call the if_detach_internal() and if_attach_internal() variants instead, with the vmove flag set. While here, staticize ifnet_setbyindex() since it is not referenced from outside of sys/net/if.c. Also rename ifccnt field in struct vimage to ifcnt, and do some minor whitespace garbage collection where appropriate. This change should have no functional impact on nooptions VIMAGE kernel builds. Reviewed by: bz, rwatson, brooks? Approved by: julian (mentor) Modified: head/sys/kern/kern_vimage.c head/sys/net/if.c head/sys/net/if_var.h head/sys/sys/vimage.h Modified: head/sys/kern/kern_vimage.c ============================================================================== --- head/sys/kern/kern_vimage.c Fri May 22 21:45:43 2009 (r192604) +++ head/sys/kern/kern_vimage.c Fri May 22 22:09:00 2009 (r192605) @@ -391,7 +391,7 @@ DB_SHOW_COMMAND(vnets, db_show_vnets) #endif VNET_FOREACH(vnet_iter) { db_printf("%p %3d %5d", - vnet_iter, vnet_iter->ifccnt, vnet_iter->sockcnt); + vnet_iter, vnet_iter->ifcnt, vnet_iter->sockcnt); db_vnet_ptr(vnet_iter->mod_data[VNET_MOD_NET]); db_vnet_ptr(vnet_iter->mod_data[VNET_MOD_INET]); db_vnet_ptr(vnet_iter->mod_data[VNET_MOD_INET6]); Modified: head/sys/net/if.c ============================================================================== --- head/sys/net/if.c Fri May 22 21:45:43 2009 (r192604) +++ head/sys/net/if.c Fri May 22 22:09:00 2009 (r192605) @@ -142,6 +142,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); #ifdef INET6 /* @@ -239,7 +241,7 @@ ifnet_byindex_ref(u_short idx) return (ifp); } -void +static void ifnet_setbyindex(u_short idx, struct ifnet *ifp) { INIT_VNET_NET(curvnet); @@ -520,8 +522,8 @@ if_alloc(u_char type) IF_ADDR_LOCK_INIT(ifp); TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); - IF_AFDATA_LOCK_INIT(ifp); ifp->if_afdata_initialized = 0; + IF_AFDATA_LOCK_INIT(ifp); TAILQ_INIT(&ifp->if_addrhead); TAILQ_INIT(&ifp->if_prefixhead); TAILQ_INIT(&ifp->if_multiaddrs); @@ -546,7 +548,7 @@ if_alloc(u_char type) static void if_free_internal(struct ifnet *ifp) { - INIT_VNET_NET(ifp->if_vnet); + INIT_VNET_NET(curvnet); /* ifp->if_vnet is already NULL here */ KASSERT((ifp->if_flags & IFF_DYING), ("if_free_internal: interface not dying")); @@ -653,7 +655,10 @@ ifq_detach(struct ifaltq *ifq) /* * Perform generic interface initalization tasks and attach the interface - * to the list of "active" interfaces. + * to the list of "active" interfaces. If vmove flag is set on entry + * to if_attach_internal(), perform only a limited subset of initialization + * tasks, given that we are moving from one vnet to another an ifnet which + * has already been fully initialized. * * XXX: * - The decision to return void and thus require this function to @@ -664,6 +669,13 @@ ifq_detach(struct ifaltq *ifq) void if_attach(struct ifnet *ifp) { + + if_attach_internal(ifp, 0); +} + +static void +if_attach_internal(struct ifnet *ifp, int vmove) +{ INIT_VNET_NET(curvnet); unsigned socksize, ifasize; int namelen, masklen; @@ -692,60 +704,63 @@ if_attach(struct ifnet *ifp) ifp->if_qflush = if_qflush; } + if (!vmove) { #ifdef MAC - mac_ifnet_create(ifp); + mac_ifnet_create(ifp); #endif - if (IS_DEFAULT_VNET(curvnet)) { - ifdev_setbyindex(ifp->if_index, make_dev(&net_cdevsw, - ifp->if_index, UID_ROOT, GID_WHEEL, 0600, "%s/%s", - net_cdevsw.d_name, ifp->if_xname)); - make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", - net_cdevsw.d_name, ifp->if_index); - } - - ifq_attach(&ifp->if_snd, ifp); - - /* - * create a Link Level name for this device - */ - namelen = strlen(ifp->if_xname); - /* - * Always save enough space for any possiable name so we can do - * a rename in place later. - */ - masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; - socksize = masklen + ifp->if_addrlen; - if (socksize < sizeof(*sdl)) - socksize = sizeof(*sdl); - socksize = roundup2(socksize, sizeof(long)); - ifasize = sizeof(*ifa) + 2 * socksize; - ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); - IFA_LOCK_INIT(ifa); - sdl = (struct sockaddr_dl *)(ifa + 1); - sdl->sdl_len = socksize; - sdl->sdl_family = AF_LINK; - bcopy(ifp->if_xname, sdl->sdl_data, namelen); - sdl->sdl_nlen = namelen; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = ifp->if_type; - ifp->if_addr = ifa; - ifa->ifa_ifp = ifp; - ifa->ifa_rtrequest = link_rtrequest; - ifa->ifa_addr = (struct sockaddr *)sdl; - sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); - ifa->ifa_netmask = (struct sockaddr *)sdl; - sdl->sdl_len = masklen; - while (namelen != 0) - sdl->sdl_data[--namelen] = 0xff; - ifa->ifa_refcnt = 1; - TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); - ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */ + if (IS_DEFAULT_VNET(curvnet)) { + ifdev_setbyindex(ifp->if_index, make_dev(&net_cdevsw, + ifp->if_index, UID_ROOT, GID_WHEEL, 0600, "%s/%s", + net_cdevsw.d_name, ifp->if_xname)); + make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", + net_cdevsw.d_name, ifp->if_index); + } + + ifq_attach(&ifp->if_snd, ifp); + + /* + * Create a Link Level name for this device. + */ + namelen = strlen(ifp->if_xname); + /* + * Always save enough space for any possiable name so we + * can do a rename in place later. + */ + masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; + socksize = masklen + ifp->if_addrlen; + if (socksize < sizeof(*sdl)) + socksize = sizeof(*sdl); + socksize = roundup2(socksize, sizeof(long)); + ifasize = sizeof(*ifa) + 2 * socksize; + ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); + IFA_LOCK_INIT(ifa); + sdl = (struct sockaddr_dl *)(ifa + 1); + sdl->sdl_len = socksize; + sdl->sdl_family = AF_LINK; + bcopy(ifp->if_xname, sdl->sdl_data, namelen); + sdl->sdl_nlen = namelen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + ifp->if_addr = ifa; + ifa->ifa_ifp = ifp; + ifa->ifa_rtrequest = link_rtrequest; + ifa->ifa_addr = (struct sockaddr *)sdl; + sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); + ifa->ifa_netmask = (struct sockaddr *)sdl; + sdl->sdl_len = masklen; + while (namelen != 0) + sdl->sdl_data[--namelen] = 0xff; + ifa->ifa_refcnt = 1; + TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); + /* Reliably crash if used uninitialized. */ + ifp->if_broadcastaddr = NULL; + } IFNET_WLOCK(); TAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link); #ifdef VIMAGE - curvnet->ifccnt++; + curvnet->ifcnt++; #endif IFNET_WUNLOCK(); @@ -759,10 +774,10 @@ if_attach(struct ifnet *ifp) /* Announce the interface. */ rt_ifannouncemsg(ifp, IFAN_ARRIVAL); - if (ifp->if_watchdog != NULL) { + if (!vmove && ifp->if_watchdog != NULL) { if_printf(ifp, "WARNING: using obsoleted if_watchdog interface\n"); - + /* * Note that we need if_slowtimo(). If this happens after * boot, then call if_slowtimo() directly. @@ -877,8 +892,10 @@ if_purgemaddrs(struct ifnet *ifp) } /* - * Detach an interface, removing it from the - * list of "active" interfaces. + * Detach an interface, removing it from the list of "active" interfaces. + * If vmove flag is set on entry to if_detach_internal(), perform only a + * limited subset of cleanup tasks, given that we are moving an ifnet from + * one vnet to another, where it must be fully operational. * * XXXRW: There are some significant questions about event ordering, and * how to prevent things from starting to use the interface during detach. @@ -886,10 +903,17 @@ if_purgemaddrs(struct ifnet *ifp) void if_detach(struct ifnet *ifp) { + + if_detach_internal(ifp, 0); +} + +static void +if_detach_internal(struct ifnet *ifp, int vmove) +{ INIT_VNET_NET(ifp->if_vnet); struct ifaddr *ifa; struct radix_node_head *rnh; - int s, i, j; + int i, j; struct domain *dp; struct ifnet *iter; int found = 0; @@ -903,11 +927,15 @@ if_detach(struct ifnet *ifp) } #ifdef VIMAGE if (found) - curvnet->ifccnt--; + curvnet->ifcnt--; #endif IFNET_WUNLOCK(); - if (!found) - return; + if (!found) { + if (vmove) + panic("interface not in it's own ifnet list"); + else + return; /* XXX this should panic as well? */ + } /* * Remove/wait for pending events. @@ -917,7 +945,6 @@ if_detach(struct ifnet *ifp) /* * Remove routes and flush queues. */ - s = splnet(); if_down(ifp); #ifdef ALTQ if (ALTQ_IS_ENABLED(&ifp->if_snd)) @@ -943,25 +970,27 @@ if_detach(struct ifnet *ifp) #endif if_purgemaddrs(ifp); - /* - * Prevent further calls into the device driver via ifnet. - */ - if_dead(ifp); - - /* - * Remove link ifaddr pointer and maybe decrement if_index. - * Clean up all addresses. - */ - ifp->if_addr = NULL; - if (IS_DEFAULT_VNET(curvnet)) - destroy_dev(ifdev_byindex(ifp->if_index)); - ifdev_setbyindex(ifp->if_index, NULL); + if (!vmove) { + /* + * Prevent further calls into the device driver via ifnet. + */ + if_dead(ifp); - /* We can now free link ifaddr. */ - if (!TAILQ_EMPTY(&ifp->if_addrhead)) { - ifa = TAILQ_FIRST(&ifp->if_addrhead); - TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); - IFAFREE(ifa); + /* + * Remove link ifaddr pointer and maybe decrement if_index. + * Clean up all addresses. + */ + ifp->if_addr = NULL; + if (IS_DEFAULT_VNET(curvnet)) + destroy_dev(ifdev_byindex(ifp->if_index)); + ifdev_setbyindex(ifp->if_index, NULL); + + /* We can now free link ifaddr. */ + if (!TAILQ_EMPTY(&ifp->if_addrhead)) { + ifa = TAILQ_FIRST(&ifp->if_addrhead); + TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + IFAFREE(ifa); + } } /* @@ -994,12 +1023,78 @@ if_detach(struct ifnet *ifp) ifp->if_afdata[dp->dom_family]); } IF_AFDATA_UNLOCK(ifp); - ifq_detach(&ifp->if_snd); + ifp->if_afdata_initialized = 0; + + if (!vmove) + ifq_detach(&ifp->if_snd); +} + #ifdef VIMAGE - ifp->if_vnet = NULL; -#endif - splx(s); +/* + * if_vmove() performs a limited version of if_detach() in current + * vnet and if_attach()es the ifnet to the vnet specified as 2nd arg. + * An attempt is made to shrink if_index in current vnet, find an + * unused if_index in target vnet and calls if_grow() if necessary, + * and finally find an unused if_xname for the target vnet. + */ +void +if_vmove(struct ifnet *ifp, struct vnet *new_vnet) +{ + + /* + * 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); + + /* + * Unlink the ifnet from ifindex_table[] in current vnet, + * and shrink the if_index for that vnet if possible. + * do / while construct below is needed to confine the scope + * of INIT_VNET_NET(). + */ + { + INIT_VNET_NET(curvnet); + + IFNET_WLOCK(); + ifnet_setbyindex(ifp->if_index, NULL); + while (V_if_index > 0 && \ + ifnet_byindex_locked(V_if_index) == NULL) + V_if_index--; + IFNET_WUNLOCK(); + }; + + /* + * Switch to the context of the target vnet. + */ + 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_locked(ifp->if_index) == NULL) + break; + } + /* Catch if_index overflow. */ + if (ifp->if_index < 1) + panic("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(); + + if_attach_internal(ifp, 1); + + CURVNET_RESTORE(); } +#endif /* VIMAGE */ /* * Add a group to an interface Modified: head/sys/net/if_var.h ============================================================================== --- head/sys/net/if_var.h Fri May 22 21:45:43 2009 (r192604) +++ head/sys/net/if_var.h Fri May 22 22:09:00 2009 (r192605) @@ -733,7 +733,6 @@ struct ifindex_entry { struct ifnet *ifnet_byindex(u_short idx); struct ifnet *ifnet_byindex_locked(u_short idx); struct ifnet *ifnet_byindex_ref(u_short idx); -void ifnet_setbyindex(u_short idx, struct ifnet *ifp); /* * Given the index, ifaddr_byindex() returns the one and only @@ -761,6 +760,7 @@ void if_grow(void); int if_delmulti(struct ifnet *, struct sockaddr *); void if_delmulti_ifma(struct ifmultiaddr *); void if_detach(struct ifnet *); +void if_vmove(struct ifnet *, struct vnet *); void if_purgeaddrs(struct ifnet *); void if_purgemaddrs(struct ifnet *); void if_down(struct ifnet *); Modified: head/sys/sys/vimage.h ============================================================================== --- head/sys/sys/vimage.h Fri May 22 21:45:43 2009 (r192604) +++ head/sys/sys/vimage.h Fri May 22 22:09:00 2009 (r192605) @@ -178,7 +178,7 @@ struct vnet { LIST_ENTRY(vnet) vnet_le; /* all vnets list */ u_int vnet_magic_n; u_int vnet_id; /* ID num */ - u_int ifccnt; + u_int ifcnt; u_int sockcnt; };