svn commit: r253590 - in head/sys: kern net sys

Marcel Moolenaar marcel at FreeBSD.org
Wed Jul 24 04:24:22 UTC 2013


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 <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
+#include <sys/uuid.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -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 *);


More information about the svn-src-all mailing list