--- //depot/projects/smpng/sys/net/if.c 2009/12/16 22:22:28 +++ //depot/user/jhb/socket/net/if.c 2009/12/21 20:06:35 @@ -1974,6 +1974,63 @@ return (ifp); } +int +if_rename(struct ifnet *ifp, const char *new_name) +{ + struct sockaddr_dl *sdl; + struct ifaddr *ifa; + size_t namelen, onamelen; + + if (new_name[0] == '\0') + return (EINVAL); + if (ifunit(new_name) != NULL) + return (EEXIST); + + /* + * XXX: Locking. Nothing else seems to lock if_flags, and + * there are numerous other races with the ifunit() checks not + * being atomic with namespace changes (renames, vmoves, + * if_attach, etc). + */ + ifp->if_flags |= IFF_RENAMING; + + /* Announce the departure of the interface. */ + rt_ifannouncemsg(ifp, IFAN_DEPARTURE); + EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); + + log(LOG_INFO, "%s: changing name to '%s'\n", ifp->if_xname, new_name); + + strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); + ifa = ifp->if_addr; + IFA_LOCK(ifa); + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + namelen = strlen(new_name); + onamelen = sdl->sdl_nlen; + + /* + * Move the address if needed. This is safe because we + * allocate space for a name of length IFNAMSIZ when we create + * this in if_attach(). + */ + if (namelen != onamelen) + bcopy(sdl->sdl_data + onamelen, sdl->sdl_data + namelen, + sdl->sdl_alen); + bcopy(new_name, sdl->sdl_data, namelen); + sdl->sdl_nlen = namelen; + sdl = (struct sockaddr_dl *)ifa->ifa_netmask; + bzero(sdl->sdl_data, onamelen); + while (namelen != 0) + sdl->sdl_data[--namelen] = 0xff; + IFA_UNLOCK(ifa); + + EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); + /* Announce the return of the interface. */ + rt_ifannouncemsg(ifp, IFAN_ARRIVAL); + + ifp->if_flags &= ~IFF_RENAMING; + return (0); +} + /* * Hardware specific interface ioctls. */ @@ -1984,10 +2041,7 @@ struct ifstat *ifs; int error = 0; int new_flags, temp_flags; - size_t namelen, onamelen; char new_name[IFNAMSIZ]; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; ifr = (struct ifreq *)data; switch (cmd) { @@ -2091,44 +2145,7 @@ error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL); if (error != 0) return (error); - if (new_name[0] == '\0') - return (EINVAL); - if (ifunit(new_name) != NULL) - return (EEXIST); - - /* Announce the departure of the interface. */ - rt_ifannouncemsg(ifp, IFAN_DEPARTURE); - EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); - - log(LOG_INFO, "%s: changing name to '%s'\n", - ifp->if_xname, new_name); - - strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); - ifa = ifp->if_addr; - IFA_LOCK(ifa); - sdl = (struct sockaddr_dl *)ifa->ifa_addr; - namelen = strlen(new_name); - onamelen = sdl->sdl_nlen; - /* - * Move the address if needed. This is safe because we - * allocate space for a name of length IFNAMSIZ when we - * create this in if_attach(). - */ - if (namelen != onamelen) { - bcopy(sdl->sdl_data + onamelen, - sdl->sdl_data + namelen, sdl->sdl_alen); - } - bcopy(new_name, sdl->sdl_data, namelen); - sdl->sdl_nlen = namelen; - sdl = (struct sockaddr_dl *)ifa->ifa_netmask; - bzero(sdl->sdl_data, onamelen); - while (namelen != 0) - sdl->sdl_data[--namelen] = 0xff; - IFA_UNLOCK(ifa); - - EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); - /* Announce the return of the interface. */ - rt_ifannouncemsg(ifp, IFAN_ARRIVAL); + error = if_rename(ifp, new_name); break; #ifdef VIMAGE --- //depot/projects/smpng/sys/net/if.h 2009/12/16 22:22:28 +++ //depot/user/jhb/socket/net/if.h 2009/12/21 20:06:35 @@ -150,6 +150,7 @@ #define IFF_MONITOR 0x40000 /* (n) user-requested monitor mode */ #define IFF_STATICARP 0x80000 /* (n) static ARP */ #define IFF_DYING 0x200000 /* (n) interface is winding down */ +#define IFF_RENAMING 0x400000 /* (n) interface is being renamed */ /* * Old names for driver flags so that user space tools can continue to use --- //depot/projects/smpng/sys/net/if_var.h 2009/12/16 22:22:28 +++ //depot/user/jhb/socket/net/if_var.h 2009/12/21 20:06:35 @@ -841,9 +841,9 @@ void if_qflush(struct ifnet *); void if_ref(struct ifnet *); void if_rele(struct ifnet *); +int if_rename(struct ifnet *, const char *); int if_setlladdr(struct ifnet *, const u_char *, int); void if_up(struct ifnet *); -/*void ifinit(void);*/ /* declared in systm.h for main() */ int ifioctl(struct socket *, u_long, caddr_t, struct thread *); int ifpromisc(struct ifnet *, int); struct ifnet *ifunit(const char *); --- //depot/projects/smpng/sys/net/if_vlan.c 2009/09/10 18:23:03 +++ //depot/user/jhb/socket/net/if_vlan.c 2009/12/21 20:13:49 @@ -99,6 +99,7 @@ #define TRUNK(ifv) ((ifv)->ifv_trunk) #define PARENT(ifv) ((ifv)->ifv_trunk->parent) int ifv_pflags; /* special flags we have set on parent */ + int ifv_flags; struct ifv_linkmib { int ifvm_encaplen; /* encapsulation length */ int ifvm_mtufudge; /* MTU fudged by this much */ @@ -117,6 +118,8 @@ #define ifv_mtufudge ifv_mib.ifvm_mtufudge #define ifv_mintu ifv_mib.ifvm_mintu +#define IFV_SHOULD_RENAME 0x0001 /* Should track parent iface's rename. */ + /* Special flags we should propagate to parent. */ static struct { int flag; @@ -137,7 +140,7 @@ static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface"); -static eventhandler_tag ifdetach_tag; +static eventhandler_tag ifattach_tag, ifdetach_tag; /* * We have a global mutex, that is used to serialize configuration @@ -191,6 +194,8 @@ static void vlan_link_state(struct ifnet *ifp, int link); static void vlan_capabilities(struct ifvlan *ifv); static void vlan_trunk_capabilities(struct ifnet *ifp); +static void vlan_check_rename(struct ifnet *ifp, struct ifvlan *ifv); +static int vlan_handle_rename(struct ifnet *ifp, struct ifvlan *ifv); static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, const char *, int *); @@ -198,6 +203,7 @@ static int vlan_clone_create(struct if_clone *, char *, size_t, caddr_t); static int vlan_clone_destroy(struct if_clone *, struct ifnet *); +static void vlan_ifattach(void *arg, struct ifnet *ifp); static void vlan_ifdetach(void *arg, struct ifnet *ifp); static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, @@ -463,10 +469,91 @@ } /* + * When a trunk interface is renamed, check to see if a child vlan + * interface should have its name updated (that is, if the vlan's name + * is .). This is called while the trunk interface still + * has the old name. + */ +static void +vlan_check_rename(struct ifnet *ifp, struct ifvlan *ifv) +{ + char name[IFNAMSIZ]; + + snprintf(name, sizeof(name), "%s.%d", ifp->if_xname, ifv->ifv_tag); + if (strcmp(ifv->ifv_ifp->if_xname, name) == 0) + ifv->ifv_flags |= IFV_SHOULD_RENAME; +} + +/* + * Once a trunk interface has been renamed, update a vlan's interface + * name if needed. If the vlan interface's new name is too long, then + * the interface's name remains unchanged. Renaming the interface + * cannot be done while holding the vlan lock, so this function + * returns true if it drops the lock to do a rename. This lets the + * calling code restart its loop. + */ +static int +vlan_handle_rename(struct ifnet *ifp, struct ifvlan *ifv) +{ + char name[IFNAMSIZ]; + + if (ifv->ifv_flags & IFV_SHOULD_RENAME) { + ifv->ifv_flags &= ~IFV_SHOULD_RENAME; + if (snprintf(name, sizeof(name), "%s.%d", ifp->if_xname, + ifv->ifv_tag) < IFNAMSIZ) { + VLAN_UNLOCK(); + if_rename(ifv->ifv_ifp, name); + return (1); + } + } + + return (0); +} + +/* + * A handler for network interface arrival events. This is only used + * for updating the names of vlan interfaces when a parent interface + * is renamed. + */ +static void +vlan_ifattach(void *arg __unused, struct ifnet *ifp) +{ + struct ifvlan *ifv; + int i; + + /* + * Check if it's a trunk interface first of all + * to avoid needless locking. + */ + if (ifp->if_vlantrunk == NULL) + return; + + /* Ignore true attach events. */ + if (!(ifp->if_flags & IFF_RENAMING)) + return; + +restart: + VLAN_LOCK(); +#ifdef VLAN_ARRAY + for (i = 0; i < VLAN_ARRAY_SIZE; i++) + if ((ifv = ifp->if_vlantrunk->vlans[i])) + if (vlan_handle_rename(ifp, ifv)) + goto restart; +#else /* VLAN_ARRAY */ + for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) + if ((ifv = LIST_FIRST(&ifp->if_vlantrunk->hash[i]))) + if (vlan_handle_rename(ifp, ifv)) + goto restart; +#endif /* VLAN_ARRAY */ + VLAN_UNLOCK(); +} + +/* * A handler for network interface departure events. * Track departure of trunks here so that we don't access invalid * pointers or whatever if a trunk is ripped from under us, e.g., - * by ejecting its hot-plug card. + * by ejecting its hot-plug card. However, if an ifnet is simply + * being renamed, then there's no need to tear down the state. */ static void vlan_ifdetach(void *arg __unused, struct ifnet *ifp) @@ -482,6 +569,25 @@ return; VLAN_LOCK(); + + /* + * If the ifnet is just being renamed, check to see if any of the + * child vlan's should be renamed as well. + */ + if (ifp->if_flags & IFF_RENAMING) { +#ifdef VLAN_ARRAY + for (i = 0; i < VLAN_ARRAY_SIZE; i++) + if ((ifv = ifp->if_vlantrunk->vlans[i])) + vlan_check_rename(ifp, ifv); +#else /* VLAN_ARRAY */ + for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) + if ((ifv = LIST_FIRST(&ifp->if_vlantrunk->hash[i]))) + vlan_check_rename(ifp, ifv); +#endif /* VLAN_ARRAY */ + VLAN_UNLOCK(); + return; + } + /* * OK, it's a trunk. Loop over and detach all vlan's on it. * Check trunk pointer after each vlan_unconfig() as it will @@ -528,10 +634,17 @@ switch (type) { case MOD_LOAD: + ifattach_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event, + vlan_ifattach, NULL, EVENTHANDLER_PRI_ANY); + if (ifattach_tag == NULL) + return (ENOMEM); ifdetach_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, vlan_ifdetach, NULL, EVENTHANDLER_PRI_ANY); - if (ifdetach_tag == NULL) + if (ifdetach_tag == NULL) { + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, + ifattach_tag); return (ENOMEM); + } VLAN_LOCK_INIT(); vlan_input_p = vlan_input; vlan_link_state_p = vlan_link_state; @@ -550,6 +663,7 @@ case MOD_UNLOAD: if_clone_detach(&vlan_cloner); EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifdetach_tag); + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ifattach_tag); vlan_input_p = NULL; vlan_link_state_p = NULL; vlan_trunk_cap_p = NULL;