From owner-p4-projects@FreeBSD.ORG Fri Nov 30 19:01:32 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0911816A420; Fri, 30 Nov 2007 19:01:32 +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 96F1216A41A for ; Fri, 30 Nov 2007 19:01:31 +0000 (UTC) (envelope-from zec@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 8DD2E13C45B for ; Fri, 30 Nov 2007 19:01:31 +0000 (UTC) (envelope-from zec@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id lAUJ1VEv070333 for ; Fri, 30 Nov 2007 19:01:31 GMT (envelope-from zec@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id lAUJ1VJJ070330 for perforce@freebsd.org; Fri, 30 Nov 2007 19:01:31 GMT (envelope-from zec@FreeBSD.org) Date: Fri, 30 Nov 2007 19:01:31 GMT Message-Id: <200711301901.lAUJ1VJJ070330@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to zec@FreeBSD.org using -f From: Marko Zec To: Perforce Change Reviews Cc: Subject: PERFORCE change 129833 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, 30 Nov 2007 19:01:32 -0000 http://perforce.freebsd.org/chv.cgi?CH=129833 Change 129833 by zec@zec_tpx32 on 2007/11/30 19:00:38 Introduce a new driver-specific ifnet method if_reassign() which should handle requests for reassigning an ifnet from one vnet to another. ether_redesign() is the first if_redesign() implementation, with more to follow. Requests for reassigning ifnets with no registered if_reassign() method will be denied, which solves the issue of kernel panics on attempts to reassign non-ethernet ifnets. Affected files ... .. //depot/projects/vimage/src/sys/kern/kern_vimage.c#56 edit .. //depot/projects/vimage/src/sys/net/if_ethersubr.c#17 edit .. //depot/projects/vimage/src/sys/net/if_var.h#10 edit .. //depot/projects/vimage/src/sys/net80211/ieee80211.c#7 edit .. //depot/projects/vimage/src/sys/sys/vimage.h#51 edit Differences ... ==== //depot/projects/vimage/src/sys/kern/kern_vimage.c#56 (text+ko) ==== @@ -278,76 +278,22 @@ return (0); } - /* - * Move the interface to another vnet. The interface can be specified either - * by ifp argument, or by name contained in vi_req->vi_chroot 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. + * 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! */ -int -vi_if_move(vi_req, ifp, vip) - struct vi_req *vi_req; - struct ifnet *ifp; - struct vimage *vip; +void +if_reassign_common(struct ifnet *ifp, struct vnet *new_vnet, const char *dname) { - struct vimage *new_vip; - struct vnet *new_vnet = NULL; - u_char eaddr[6]; - - if (vi_req == NULL || strcmp(vi_req->vi_name, "..") == 0) { - if (IS_DEFAULT_VIMAGE(vip)) - return (ENXIO); - new_vnet = vip->vi_parent->v_net; - } else { - new_vip = vimage_by_name(vip, vi_req->vi_name); - if (new_vip == NULL) - return (ENXIO); - new_vnet = new_vip->v_net; - } - - if (ifp == NULL) - ifp = ifunit(vi_req->vi_chroot); - if (ifp == NULL) - return (ENXIO); - - if (vi_req != NULL) { - struct ifnet *t_ifp; - - CURVNET_SET_QUIET(new_vnet); - t_ifp = ifunit(vi_req->vi_if_xname); - CURVNET_RESTORE(); - if (t_ifp != NULL) - return (EEXIST); - } - - /* Loopback interfaces cannot be moved across network stacks */ - if (ifp->if_flags & IFF_LOOPBACK) - return (EPERM); - - /* - * This is tricky. First we have to detach the interface, - * and then reattach it to the target vnet. Before doing - * that, we reassing the interface unit number to look nice - * in the target vnet. - */ - switch (ifp->if_type) { - case IFT_ETHER: - case IFT_L2VLAN: - bcopy(IF_LLADDR(ifp), eaddr, 6); - ether_ifdetach(ifp); - break; - case IFT_PROPVIRTUAL: /* XXX ng_eiface */ - if_detach(ifp); - break; - default: - panic("don't know yet how to handle iftype %d", ifp->if_type); - /* if_detach(ifp); */ - } - ifp->if_bpf = NULL; /* do/while construct needed to confine scope of INIT_VNET_NET() */ do { INIT_VNET_NET(curvnet); @@ -386,54 +332,78 @@ snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ifp->if_dname, ifp->if_dunit); } else { - if (vi_req && strlen(vi_req->vi_if_xname) > 0) { - snprintf(ifp->if_xname, IFNAMSIZ, "%s", - vi_req->vi_if_xname); - } else { - int unit = 0; - struct ifnet *iter; + 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); + } + CURVNET_RESTORE(); +} -#define FINDFREEUNIT(dname) \ - 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); +/* + * Move the interface to another vnet. The interface can be specified either + * by ifp argument, or by name contained in vi_req->vi_chroot 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. + */ +int +vi_if_move(vi_req, ifp, vip) + struct vi_req *vi_req; + struct ifnet *ifp; + struct vimage *vip; +{ + struct vimage *new_vip; + struct vnet *new_vnet = NULL; - switch (ifp->if_type) { - case IFT_ETHER: - case IFT_L2VLAN: - FINDFREEUNIT("eth"); - break; - case IFT_PROPVIRTUAL: - FINDFREEUNIT("ser"); - break; - default: - break; - } - } + if (vi_req == NULL || strcmp(vi_req->vi_name, "..") == 0) { + if (IS_DEFAULT_VIMAGE(vip)) + return (ENXIO); + new_vnet = vip->vi_parent->v_net; + } else { + new_vip = vimage_by_name(vip, vi_req->vi_name); + if (new_vip == NULL) + return (ENXIO); + new_vnet = new_vip->v_net; } - switch (ifp->if_type) { - case IFT_ETHER: - case IFT_L2VLAN: - ether_ifattach(ifp, eaddr); - break; - case IFT_PROPVIRTUAL: /* XXX ng_eiface */ - if_attach(ifp); - break; - default: - panic("don't know yet how to handle iftype %d", ifp->if_type); - /* if_attach(ifp); */ + if (ifp == NULL) + ifp = ifunit(vi_req->vi_chroot); + if (ifp == NULL) + return (ENXIO); + + /* Abort if driver did not provide a if_reassign() method */ + if (ifp->if_reassign == NULL) + return (ENODEV); + + if (vi_req != NULL) { + struct ifnet *t_ifp; + + CURVNET_SET_QUIET(new_vnet); + t_ifp = ifunit(vi_req->vi_if_xname); + CURVNET_RESTORE(); + if (t_ifp != NULL) + 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); + /* Report the new if_xname back to the userland */ if (vi_req != NULL) sprintf(vi_req->vi_chroot, "%s", ifp->if_xname); - CURVNET_RESTORE(); return (0); } ==== //depot/projects/vimage/src/sys/net/if_ethersubr.c#17 (text+ko) ==== @@ -886,6 +886,25 @@ 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 */ @@ -906,6 +925,9 @@ 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; ==== //depot/projects/vimage/src/sys/net/if_var.h#10 (text+ko) ==== @@ -130,6 +130,7 @@ * field is deprecated. Use if_addr or ifaddr_byindex() instead. */ struct knlist if_klist; /* events attached to this if */ + struct vnet *if_vnet; /* network stack instance */ int if_pcount; /* number of promiscuous listeners */ struct carp_if *if_carp; /* carp interface structure */ struct bpf_if *if_bpf; /* packet filter structure */ @@ -160,6 +161,9 @@ (void *); int (*if_resolvemulti) /* validate/resolve multicast */ (struct ifnet *, struct sockaddr **, struct sockaddr *); + void (*if_reassign) /* reassign to vnet routine */ + (struct ifnet *, struct vnet *, char *); + struct vnet *if_home_vnet; /* where this ifnet originates from */ struct ifaddr *if_addr; /* pointer to link-level address */ void *if_spare2; /* spare pointer 2 */ void *if_spare3; /* spare pointer 3 */ @@ -187,9 +191,6 @@ /* protected by if_addr_mtx */ void *if_pf_kif; void *if_lagg; /* lagg glue */ - - struct vnet *if_vnet; /* network stack instance */ - struct vnet *if_home_vnet; /* where this ifnet originates from */ }; typedef void if_init_f_t(void *); ==== //depot/projects/vimage/src/sys/net80211/ieee80211.c#7 (text+ko) ==== @@ -31,6 +31,8 @@ * IEEE 802.11 generic handler */ +#include "opt_vimage.h" + #include #include #include @@ -213,6 +215,10 @@ ether_ifattach(ifp, ic->ic_myaddr); ifp->if_output = ieee80211_output; +#ifdef VIMAGE + /* Override ether_reassign() */ + ifp->if_reassign = NULL; /* XXX not implemented yet */ +#endif bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); ==== //depot/projects/vimage/src/sys/sys/vimage.h#51 (text+ko) ==== @@ -342,6 +342,8 @@ void vi_cpu_acct(void *); int vi_td_ioctl(u_long, struct vi_req *, struct thread *); int vi_if_move(struct vi_req *, struct ifnet *, struct vimage *); +void if_reassign_common(struct ifnet *, struct vnet *, const char *); + int vi_symlookup(struct kld_sym_lookup *, char *); struct vimage *vnet2vimage(struct vnet *); struct vimage *vimage_by_name(struct vimage *, char *);