From owner-p4-projects@FreeBSD.ORG Fri May 15 00:24:47 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B1CC31065670; Fri, 15 May 2009 00:24:46 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 58E07106566B for ; Fri, 15 May 2009 00:24:46 +0000 (UTC) (envelope-from zec@fer.hr) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 451578FC0A for ; Fri, 15 May 2009 00:24:46 +0000 (UTC) (envelope-from zec@fer.hr) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n4F0OkxK001735 for ; Fri, 15 May 2009 00:24:46 GMT (envelope-from zec@fer.hr) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n4F0Ojix001733 for perforce@freebsd.org; Fri, 15 May 2009 00:24:45 GMT (envelope-from zec@fer.hr) Date: Fri, 15 May 2009 00:24:45 GMT Message-Id: <200905150024.n4F0Ojix001733@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to zec@fer.hr using -f From: Marko Zec To: Perforce Change Reviews Cc: Subject: PERFORCE change 162097 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 May 2009 00:24:48 -0000 http://perforce.freebsd.org/chv.cgi?CH=162097 Change 162097 by zec@zec_tpx32 on 2009/05/15 00:23:50 First cut implementation of if_vmove(), inspired by Julian's sketches from a few days ago. if_vmove() calls if_detach1() with a flag set resulting in only a subset of common if_detach() tasks being done, i.e. vnet-agnostic state being preserved. The ifnet is then detached from ifindex_table in current vnet, and linked to the ifindex_table in target vnet. Finally, if_attach1() is called with a vmove flag set, resulting in ifnet being attached to the target vnet while preserving vnet-agnostic state such ase LLADDRs, if_* interface methods etc. While here, nuke if_reassign_common() which is no longer used. Affected files ... .. //depot/projects/vimage-commit2/src/sys/kern/kern_vimage.c#41 edit .. //depot/projects/vimage-commit2/src/sys/net/if.c#60 edit .. //depot/projects/vimage-commit2/src/sys/net/if_ethersubr.c#26 edit .. //depot/projects/vimage-commit2/src/sys/net/if_var.h#23 edit Differences ... ==== //depot/projects/vimage-commit2/src/sys/kern/kern_vimage.c#41 (text+ko) ==== @@ -115,86 +115,11 @@ } /* - * 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_locked(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_locked(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(); - -#ifdef NOTYET - /* 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); - } -#endif - CURVNET_RESTORE(); -} - -/* - * Move the interface to another vnet. The interface can be specified either + * Move an ifnet to another vnet. The ifnet 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. + * passed as ifp. 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) @@ -206,6 +131,7 @@ if (vi_req->vi_api_cookie != VI_API_COOKIE) return (EDOOFUS); + /* Find the target vnet. */ if (vi_req == NULL || strcmp(vi_req->vi_name, "..") == 0) { if (IS_DEFAULT_VIMAGE(vip)) return (ENXIO); @@ -217,15 +143,23 @@ new_vnet = new_vip->v_net; } + /* Try to find the target ifnet by name. */ if (ifp == NULL) ifp = ifunit(vi_req->vi_if_xname); + if (ifp == NULL) return (ENXIO); +#if 0 /* Abort if driver did not provide a if_reassign() method */ if (ifp->if_reassign == NULL) return (ENODEV); +#endif + /* + * Check for naming clashes in target vnet. Not locked so races + * are possible. + */ if (vi_req != NULL) { struct ifnet *t_ifp; @@ -236,11 +170,8 @@ 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); + /* Detach from curvnet and attach to new_vnet. */ + if_vmove(ifp, new_vnet); /* Report the new if_xname back to the userland */ if (vi_req != NULL) ==== //depot/projects/vimage-commit2/src/sys/net/if.c#60 (text+ko) ==== @@ -141,6 +141,8 @@ static int if_getgroup(struct ifgroupreq *, struct ifnet *); static int if_getgroupmembers(struct ifgroupreq *); static void if_delgroups(struct ifnet *); +static void if_attach1(struct ifnet *, int); +static void if_detach1(struct ifnet *, int); #ifdef INET6 /* @@ -652,7 +654,10 @@ /* * 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_attach1(), perform only a limited subset of initialization + * tasks, given that we are moving an ifnet which has already been fully + * initialized from one vnet to another. * * XXX: * - The decision to return void and thus require this function to @@ -663,6 +668,13 @@ void if_attach(struct ifnet *ifp) { + + if_attach1(ifp, 0); +} + +static void +if_attach1(struct ifnet *ifp, int vmove) +{ INIT_VNET_NET(curvnet); unsigned socksize, ifasize; int namelen, masklen; @@ -679,7 +691,7 @@ * Record in which vnet has this ifnet been attached * for the first time. */ - if (ifp->if_home_vnet == NULL) + if (ifp->if_home_vnet == NULL) ifp->if_home_vnet = curvnet; #endif @@ -697,55 +709,58 @@ 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); - } + 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); + 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 */ + /* + * 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); @@ -764,7 +779,7 @@ /* 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"); @@ -882,8 +897,10 @@ } /* - * 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_detach1(), 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. @@ -891,10 +908,17 @@ void if_detach(struct ifnet *ifp) { + + if_detach1(ifp, 0); +} + +static void +if_detach1(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; @@ -911,8 +935,12 @@ --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. @@ -922,7 +950,6 @@ /* * Remove routes and flush queues. */ - s = splnet(); if_down(ifp); #ifdef ALTQ if (ALTQ_IS_ENABLED(&ifp->if_snd)) @@ -948,29 +975,27 @@ #endif if_purgemaddrs(ifp); - /* - * Prevent further calls into the device driver via ifnet. - * XXX temporarily disabled in VIMAGE builds as we may need to - * to reattach the ifnet to another vnet. - */ -#ifndef VIMAGE - if_dead(ifp); -#endif + if (!vmove) { + /* + * 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); + /* + * 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); + /* 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); + } } /* @@ -1003,13 +1028,83 @@ ifp->if_afdata[dp->dom_family]); } IF_AFDATA_UNLOCK(ifp); - ifq_detach(&ifp->if_snd); + + if (!vmove) + ifq_detach(&ifp->if_snd); +} + #ifdef VIMAGE - ifp->if_vnet = NULL; - ifp->if_afdata_initialized = 0; -#endif - splx(s); +/* + * if_vmove() 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_vmove(struct ifnet *ifp, struct vnet *new_vnet) +{ + + /* + * Detach from current vnet, but preserve LLADDR info, do not + * mark as dead etc. so that we can reattach later. + */ + if_detach1(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(). + */ + do { + 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(); + } while (0); + + /* + * 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("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(); + + if_attach1(ifp, 1); + + CURVNET_RESTORE(); } +#endif /* VIMAGE */ /* * Add a group to an interface ==== //depot/projects/vimage-commit2/src/sys/net/if_ethersubr.c#26 (text+ko) ==== @@ -924,25 +924,6 @@ return (etherbuf); } -#ifdef VIMAGE -static void -ether_reassign(struct ifnet *ifp, struct vnet *vnet, char *dname) -{ - u_char eaddr[6]; - - bcopy(IF_LLADDR(ifp), eaddr, 6); - ether_ifdetach(ifp); - ifp->if_bpf = NULL; - if_reassign_common(ifp, vnet, "eth"); - if (dname) - snprintf(ifp->if_xname, IFNAMSIZ, "%s", dname); - - CURVNET_SET_QUIET(vnet); - ether_ifattach(ifp, eaddr); - CURVNET_RESTORE(); -} -#endif - /* * Perform common duties while attaching to interface list */ @@ -952,9 +933,6 @@ int i; struct ifaddr *ifa; struct sockaddr_dl *sdl; -#ifdef VIMAGE - struct vnet *home_vnet_0 = ifp->if_home_vnet; -#endif ifp->if_addrlen = ETHER_ADDR_LEN; ifp->if_hdrlen = ETHER_HDR_LEN; @@ -963,9 +941,6 @@ ifp->if_output = ether_output; ifp->if_input = ether_input; ifp->if_resolvemulti = ether_resolvemulti; -#ifdef VIMAGE - ifp->if_reassign = ether_reassign; -#endif if (ifp->if_baudrate == 0) ifp->if_baudrate = IF_Mbps(10); /* just a default */ ifp->if_broadcastaddr = etherbroadcastaddr; @@ -985,11 +960,7 @@ for (i = 0; i < ifp->if_addrlen; i++) if (lla[i] != 0) break; -#ifdef VIMAGE - if (i != ifp->if_addrlen && home_vnet_0 != ifp->if_home_vnet) -#else if (i != ifp->if_addrlen) -#endif if_printf(ifp, "Ethernet address: %6D\n", lla, ":"); } ==== //depot/projects/vimage-commit2/src/sys/net/if_var.h#23 (text+ko) ==== @@ -765,6 +765,7 @@ 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 *);