From owner-svn-src-all@FreeBSD.ORG Wed Jul 24 04:24:22 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 062BAD70; Wed, 24 Jul 2013 04:24:22 +0000 (UTC) (envelope-from marcel@FreeBSD.org) 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)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id E9CA1280A; Wed, 24 Jul 2013 04:24:21 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r6O4OLPL000916; Wed, 24 Jul 2013 04:24:21 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r6O4OLEZ000913; Wed, 24 Jul 2013 04:24:21 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <201307240424.r6O4OLEZ000913@svn.freebsd.org> From: Marcel Moolenaar Date: Wed, 24 Jul 2013 04:24:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r253590 - in head/sys: kern net sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jul 2013 04:24:22 -0000 Author: marcel Date: Wed Jul 24 04:24:21 2013 New Revision: 253590 URL: http://svnweb.freebsd.org/changeset/base/253590 Log: Decouple the UUID generator from network interfaces by having MAC addresses added to the UUID generator using uuid_ether_add(). The UUID generator keeps an arbitrary number of MAC addresses, under the assumption that they are rarely removed (= uuid_ether_del()). This achieves the following: 1. It brings up closer to having the network stack as a loadable module. 2. It allows the UUID generator to filter MAC addresses for best results (= highest chance of uniqeness). 3. MAC addresses can come from anywhere, irrespactive of whether it's used for an interface or not. A side-effect of the change is that when no MAC addresses have been added, a random multicast MAC address is created once and re-used if needed. Previusly, when a random MAC address was needed, it was created for every call. Thus, a change in behaviour is introduced for when no MAC addresses exist. Obtained from: Juniper Networks, Inc. Modified: head/sys/kern/kern_uuid.c head/sys/net/if_ethersubr.c head/sys/sys/uuid.h Modified: head/sys/kern/kern_uuid.c ============================================================================== --- head/sys/kern/kern_uuid.c Wed Jul 24 04:05:48 2013 (r253589) +++ head/sys/kern/kern_uuid.c Wed Jul 24 04:24:21 2013 (r253590) @@ -71,54 +71,41 @@ struct uuid_private { CTASSERT(sizeof(struct uuid_private) == 16); +struct uuid_macaddr { + uint16_t state; +#define UUID_ETHER_EMPTY 0 +#define UUID_ETHER_RANDOM 1 +#define UUID_ETHER_UNIQUE 2 + uint16_t node[UUID_NODE_LEN>>1]; +}; + static struct uuid_private uuid_last; +#define UUID_NETHER 4 +static struct uuid_macaddr uuid_ether[UUID_NETHER]; + static struct mtx uuid_mutex; MTX_SYSINIT(uuid_lock, &uuid_mutex, "UUID generator mutex lock", MTX_DEF); /* - * Return the first MAC address we encounter or, if none was found, - * construct a sufficiently random multicast address. We don't try - * to return the same MAC address as previously returned. We always - * generate a new multicast address if no MAC address exists in the - * system. - * It would be nice to know if 'ifnet' or any of its sub-structures - * has been changed in any way. If not, we could simply skip the - * scan and safely return the MAC address we returned before. + * Return the first MAC address added in the array. If it's empty, then + * construct a sufficiently random multicast MAC address first. Any + * addresses added later will bump the random MAC address up tp the next + * index. */ static void uuid_node(uint16_t *node) { - struct ifnet *ifp; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; int i; - CURVNET_SET(TD_TO_VNET(curthread)); - IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { - /* Walk the address list */ - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - sdl = (struct sockaddr_dl*)ifa->ifa_addr; - if (sdl != NULL && sdl->sdl_family == AF_LINK && - sdl->sdl_type == IFT_ETHER) { - /* Got a MAC address. */ - bcopy(LLADDR(sdl), node, UUID_NODE_LEN); - IF_ADDR_RUNLOCK(ifp); - IFNET_RUNLOCK_NOSLEEP(); - CURVNET_RESTORE(); - return; - } - } - IF_ADDR_RUNLOCK(ifp); + if (uuid_ether[0].state == UUID_ETHER_EMPTY) { + for (i = 0; i < (UUID_NODE_LEN>>1); i++) + uuid_ether[0].node[i] = (uint16_t)arc4random(); + *((uint8_t*)uuid_ether[0].node) |= 0x01; + uuid_ether[0].state = UUID_ETHER_RANDOM; } - IFNET_RUNLOCK_NOSLEEP(); - for (i = 0; i < (UUID_NODE_LEN>>1); i++) - node[i] = (uint16_t)arc4random(); - *((uint8_t*)node) |= 0x01; - CURVNET_RESTORE(); + node[i] = uuid_ether[0].node[i]; } /* @@ -211,6 +198,77 @@ sys_uuidgen(struct thread *td, struct uu } int +uuid_ether_add(const uint8_t *addr) +{ + int i; + uint8_t c; + + /* + * Validate input. No multicast addresses and no addresses that + * are all zeroes. + */ + if (addr[0] & 0x01) + return (EINVAL); + c = 0; + for (i = 0; i < UUID_NODE_LEN; i++) + c += addr[i]; + if (c == 0) + return (EINVAL); + + mtx_lock(&uuid_mutex); + + /* Make sure the MAC isn't known already and that there's space. */ + i = 0; + while (i < UUID_NETHER && uuid_ether[i].state == UUID_ETHER_UNIQUE) { + if (!bcmp(addr, uuid_ether[i].node, UUID_NODE_LEN)) { + mtx_unlock(&uuid_mutex); + return (EEXIST); + } + i++; + } + if (i == UUID_NETHER) { + mtx_unlock(&uuid_mutex); + return (ENOSPC); + } + + /* Insert MAC at index, moving the non-empty entry if possible. */ + if (uuid_ether[i].state == UUID_ETHER_RANDOM && i < UUID_NETHER - 1) + uuid_ether[i + 1] = uuid_ether[i]; + uuid_ether[i].state = UUID_ETHER_UNIQUE; + bcopy(addr, uuid_ether[i].node, UUID_NODE_LEN); + mtx_unlock(&uuid_mutex); + return (0); +} + +int +uuid_ether_del(const uint8_t *addr) +{ + int i; + + mtx_lock(&uuid_mutex); + i = 0; + while (i < UUID_NETHER && uuid_ether[i].state == UUID_ETHER_UNIQUE && + bcmp(addr, uuid_ether[i].node, UUID_NODE_LEN)) + i++; + if (i == UUID_NETHER || uuid_ether[i].state != UUID_ETHER_UNIQUE) { + mtx_unlock(&uuid_mutex); + return (ENOENT); + } + + /* Remove it by shifting higher index entries down. */ + while (i < UUID_NETHER - 1 && uuid_ether[i].state != UUID_ETHER_EMPTY) { + uuid_ether[i] = uuid_ether[i + 1]; + i++; + } + if (uuid_ether[i].state != UUID_ETHER_EMPTY) { + uuid_ether[i].state = UUID_ETHER_EMPTY; + bzero(uuid_ether[i].node, UUID_NODE_LEN); + } + mtx_unlock(&uuid_mutex); + return (0); +} + +int snprintf_uuid(char *buf, size_t sz, struct uuid *uuid) { struct uuid_private *id; Modified: head/sys/net/if_ethersubr.c ============================================================================== --- head/sys/net/if_ethersubr.c Wed Jul 24 04:05:48 2013 (r253589) +++ head/sys/net/if_ethersubr.c Wed Jul 24 04:24:21 2013 (r253590) @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -926,6 +927,8 @@ ether_ifattach(struct ifnet *ifp, const break; if (i != ifp->if_addrlen) if_printf(ifp, "Ethernet address: %6D\n", lla, ":"); + + uuid_ether_add(LLADDR(sdl)); } /* @@ -934,6 +937,11 @@ ether_ifattach(struct ifnet *ifp, const void ether_ifdetach(struct ifnet *ifp) { + struct sockaddr_dl *sdl; + + sdl = (struct sockaddr_dl *)(ifp->if_addr->ifa_addr); + uuid_ether_del(LLADDR(sdl)); + if (IFP2AC(ifp)->ac_netgraph != NULL) { KASSERT(ng_ether_detach_p != NULL, ("ng_ether_detach_p is NULL")); Modified: head/sys/sys/uuid.h ============================================================================== --- head/sys/sys/uuid.h Wed Jul 24 04:05:48 2013 (r253589) +++ head/sys/sys/uuid.h Wed Jul 24 04:24:21 2013 (r253590) @@ -58,6 +58,9 @@ struct sbuf; struct uuid *kern_uuidgen(struct uuid *, size_t); +int uuid_ether_add(const uint8_t *); +int uuid_ether_del(const uint8_t *); + int snprintf_uuid(char *, size_t, struct uuid *); int printf_uuid(struct uuid *); int sbuf_printf_uuid(struct sbuf *, struct uuid *);