Large subnet patch

Bin Guo bguo at bluesocket.com
Thu Mar 31 00:14:25 UTC 2005


I'm having some problem with my email client, hope you can see
the patch.
<patch>
 includes/dhcpd.h  |   18 +++++++++++++++++
 includes/site.h   |    4 +++
 server/confpars.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 server/dhcp.c     |   49 +++++++++++++++++++++++++++++++++++++++++++++++
 server/mdb.c      |   43 +++++++++++++++++++++++++++++++++++++++++
 server/omapi.c    |    8 +++++++
 6 files changed, 178 insertions(+)

Index: dhcp-3.0.2/server/omapi.c
===================================================================
--- dhcp-3.0.2.orig/server/omapi.c	2004-11-24 12:39:19.000000000 -0500
+++ dhcp-3.0.2/server/omapi.c	2005-03-09 13:56:25.000000000 -0500
@@ -1630,6 +1630,14 @@ isc_result_t dhcp_pool_destroy (omapi_ob
 	pool -> prohibit_list = (struct permit *)0;
 #endif
 
+#if defined (LARGE_SUBNET)
+	while (pool -> range) {
+		struct range *next = pool -> range -> next;
+		dfree (pool -> range, MDL);
+		pool -> range = next;
+	}
+#endif/*LARGE_SUBNET*/
+
 	return ISC_R_SUCCESS;
 }
 
Index: dhcp-3.0.2/server/mdb.c
===================================================================
--- dhcp-3.0.2.orig/server/mdb.c	2004-09-01 16:19:44.000000000 -0400
+++ dhcp-3.0.2/server/mdb.c	2005-03-11 16:49:54.000000000 -0500
@@ -446,12 +446,22 @@ int find_host_for_network (struct subnet
 	return 0;
 }
 
+#if defined (LARGE_SUBNET)
+int new_address_range (cfile, low, high, subnet, pool, lpchain, instantiate)
+	struct parse *cfile;
+	struct iaddr low, high;
+	struct subnet *subnet;
+	struct pool *pool;
+	struct lease **lpchain;
+	int instantiate;
+#else /*LARGE_SUBNET*/
 void new_address_range (cfile, low, high, subnet, pool, lpchain)
 	struct parse *cfile;
 	struct iaddr low, high;
 	struct subnet *subnet;
 	struct pool *pool;
 	struct lease **lpchain;
+#endif/*LARGE_SUBNET*/
 {
 	struct lease *address_range, *lp, *plp;
 	struct iaddr net;
@@ -515,6 +525,10 @@ void new_address_range (cfile, low, high
 #if defined (COMPACT_LEASES)
 	address_range = new_leases (max - min + 1, MDL);
 	if (!address_range) {
+#if defined (LARGE_SUBNET)
+		if (!cfile && instantiate)
+			return 0;
+#endif/*LARGE_SUBNET*/
 		strcpy (lowbuf, piaddr (low));
 		strcpy (highbuf, piaddr (high));
 		log_fatal ("No memory for address range %s-%s.",
@@ -532,6 +546,11 @@ void new_address_range (cfile, low, high
 		lease_reference (&lp, &address_range [i], MDL);
 #else
 		status = lease_allocate (&lp, MDL);
+#if defined (LARGE_SUBNET)
+		if (status != ISC_R_SUCCESS)
+			if (!cfile && instantiate)
+				return i;
+#endif/*LARGE_SUBNET*/
 		if (status != ISC_R_SUCCESS)
 			log_fatal ("No memory for lease %s: %s",
 				   piaddr (ip_addr (subnet -> net,
@@ -552,16 +571,37 @@ void new_address_range (cfile, low, high
 		/* Remember the lease in the IP address hash. */
 		if (find_lease_by_ip_addr (&lt, lp -> ip_addr, MDL)) {
 			if (lt -> pool) {
+#if defined (LARGE_SUBNET)
+				if (!cfile)
+					log_error ("lease %s is declared twice!",
+						   piaddr (lp -> ip_addr));
+				else
+#endif/*LARGE_SUBNET*/
 				parse_warn (cfile,
 					    "lease %s is declared twice!",
 					    piaddr (lp -> ip_addr));
 			} else
 				pool_reference (&lt -> pool, pool, MDL);
 			lease_dereference (&lt, MDL);
+#if defined (LARGE_SUBNET)
+		} else {
+			lease_hash_add (lease_ip_addr_hash,
+					lp -> ip_addr.iabuf,
+					lp -> ip_addr.len, lp, MDL);
+			if (instantiate) {
+				/***
+				log_debug ("instantiating lease: %u.%u.%u.%u",
+			   		   lp -> ip_addr.iabuf[0], lp -> ip_addr.iabuf[1], lp -> ip_addr.iabuf[2], lp -> ip_addr.iabuf[3]);
+				***/
+				lease_instantiate (NULL, 0, lp);
+			}
+		}
+#else /*LARGE_SUBNET*/
 		} else
 			lease_hash_add (lease_ip_addr_hash,
 					lp -> ip_addr.iabuf,
 					lp -> ip_addr.len, lp, MDL);
+#endif/*LARGE_SUBNET*/
 		/* Put the lease on the chain for the caller. */
 		if (lpchain) {
 			if (*lpchain) {
@@ -572,6 +612,9 @@ void new_address_range (cfile, low, high
 		}
 		lease_dereference (&lp, MDL);
 	}
+#if defined (LARGE_SUBNET)
+	return i;
+#endif/*LARGE_SUBNET*/
 }
 
 int find_subnet (struct subnet **sp,
Index: dhcp-3.0.2/server/confpars.c
===================================================================
--- dhcp-3.0.2.orig/server/confpars.c	2004-11-24 12:39:18.000000000 -0500
+++ dhcp-3.0.2/server/confpars.c	2005-03-09 13:57:55.000000000 -0500
@@ -3245,9 +3245,65 @@ void parse_address_range (cfile, group, 
 	}
 #endif /* FAILOVER_PROTOCOL */
 
+#if defined (LARGE_SUBNET)
+	do {
+		unsigned min, max;
+		struct range *range;
+
+		/* Make sure that high and low addresses are in same subnet. */
+		net = subnet_number (low, subnet -> netmask);
+		if (!addr_eq (net, subnet_number (high, subnet -> netmask)))
+			break;
+
+		/* Make sure that the addresses are on the correct subnet. */
+		if (!addr_eq (net, subnet -> net))
+			break;
+
+		/* Get the high and low host addresses... */
+		max = host_addr (high, subnet -> netmask);
+		min = host_addr (low, subnet -> netmask);
+
+		/* Allow range to be specified high-to-low as well as low-to-high. */
+		if (min > max) {
+			max = min;
+			min = host_addr (high, subnet -> netmask);
+		}
+
+		/* Allocate if range is small enough */
+		if (max - min + 1 <= MAX_ALLOCATE_RANGE)
+			break;
+
+		/* Record the range for later use */
+		range = dmalloc (sizeof(struct range), MDL);
+		if (!range)
+			log_fatal ("Can't allocate range");
+		low  = ip_addr (subnet -> net, subnet -> netmask, min);
+		high = ip_addr (subnet -> net, subnet -> netmask, max);
+		range -> low  = low;
+		range -> high = high;
+		range -> min  = min;
+		range -> max  = max;
+		range -> cnt  = max - min + 1;
+
+		range -> next = pool -> range;
+		pool -> range = range;
+
+		log_debug ("saved range: %u.%u.%u.%u ~ %u.%u.%u.%u, cnt=%u",
+			   low.iabuf[0], low.iabuf[1], low.iabuf[2], low.iabuf[3],
+			   high.iabuf[0], high.iabuf[1], high.iabuf[2], high.iabuf[3], range -> cnt);
+
+		pool_dereference (&pool, MDL);
+		return;
+	} while (0);
+
+	/* Create the new address range... */
+	new_address_range (cfile, low, high, subnet, pool, lpchain, 0);
+	pool_dereference (&pool, MDL);
+#else /*LARGE_SUBNET*/
 	/* Create the new address range... */
 	new_address_range (cfile, low, high, subnet, pool, lpchain);
 	pool_dereference (&pool, MDL);
+#endif/*LARGE_SUBNET*/
 }
 
 /* allow-deny-keyword :== BOOTP
Index: dhcp-3.0.2/server/dhcp.c
===================================================================
--- dhcp-3.0.2.orig/server/dhcp.c	2004-11-24 12:39:19.000000000 -0500
+++ dhcp-3.0.2/server/dhcp.c	2005-03-10 16:54:47.000000000 -0500
@@ -3669,6 +3669,55 @@ int allocate_lease (struct lease **lp, s
 		} else
 #endif
 		{
+#if defined (LARGE_SUBNET)
+			while (!pool -> free && pool -> range) {
+				struct range *range = pool -> range;
+				unsigned cnt = range -> cnt;
+				struct subnet *subnet = NULL;
+
+				if (cnt < 0) cnt = 0;
+				if (cnt > MAX_ALLOCATE_RANGE) cnt = MAX_ALLOCATE_RANGE;
+
+				/* find subnet from shared_network: next_sibling? */
+				if (cnt) {
+					struct shared_network *share = pool -> shared_network;
+					for (subnet = share -> subnets; subnet; subnet = subnet -> next_sibling) {
+						struct iaddr net = subnet_number (range -> low, subnet -> netmask);
+						if (!addr_eq(net, subnet_number (range -> high, subnet -> netmask)))
+							continue;
+						if (addr_eq(net, subnet -> net))
+							break;
+					}
+				}
+				if (!subnet)
+					break;
+
+				if (cnt) {
+					unsigned min = range -> min;
+					unsigned max = range -> min + cnt - 1;
+					struct iaddr low  = range -> low;
+					struct iaddr high = ip_addr (subnet -> net, subnet -> netmask, max);
+					log_debug ("allocating range: %u.%u.%u.%u ~ %u.%u.%u.%u, cnt=%u",
+				  		   low.iabuf[0], low.iabuf[1], low.iabuf[2], low.iabuf[3],
+				  		   high.iabuf[0], high.iabuf[1], high.iabuf[2], high.iabuf[3], cnt);
+					cnt = new_address_range (NULL, low, high, subnet, pool, NULL, 1);
+					if (!cnt) break;
+					range -> min = min = max + 1;
+					range -> cnt -= cnt;
+					if (range -> cnt)
+						range -> low = ip_addr (subnet -> net, subnet -> netmask, min);
+					log_debug ("shrinked range: %u.%u.%u.%u ~ %u.%u.%u.%u, cnt=%u",
+				  		   range -> low.iabuf[0], range -> low.iabuf[1], range -> low.iabuf[2], range -> low.iabuf[3],
+				  		   range -> high.iabuf[0], range -> high.iabuf[1], range -> high.iabuf[2], range -> high.iabuf[3], range -> cnt);
+				}
+
+				if (!range -> cnt) {
+					pool -> range = range -> next;
+					dfree (range, MDL);
+				}
+				break;
+			}
+#endif/*LARGE_SUBNET*/
 			if (pool -> free)
 				candl = pool -> free;
 			else
Index: dhcp-3.0.2/includes/dhcpd.h
===================================================================
--- dhcp-3.0.2.orig/includes/dhcpd.h	2004-11-24 12:39:16.000000000 -0500
+++ dhcp-3.0.2/includes/dhcpd.h	2005-03-10 13:51:36.000000000 -0500
@@ -544,6 +544,15 @@ struct permit {
 	struct class *class;
 };
 
+#if defined (LARGE_SUBNET)
+#define MAX_ALLOCATE_RANGE	256
+struct range {
+	struct range *next;
+	struct iaddr low, high;
+	unsigned min, max, cnt;
+};
+#endif/*LARGE_SUBNET*/
+
 struct pool {
 	OMAPI_OBJECT_PREAMBLE;
 	struct pool *next;
@@ -564,6 +573,9 @@ struct pool {
 #if defined (FAILOVER_PROTOCOL)
 	dhcp_failover_state_t *failover_peer;
 #endif
+#if defined (LARGE_SUBNET)
+	struct range *range;
+#endif/*LARGE_SUBNET*/
 };
 
 struct shared_network {
@@ -2411,9 +2423,15 @@ int find_hosts_by_uid PROTO ((struct hos
 			      unsigned, const char *, int));
 int find_host_for_network PROTO ((struct subnet **, struct host_decl **,
 				  struct iaddr *, struct shared_network *));
+#if defined (LARGE_SUBNET)
+int new_address_range PROTO ((struct parse *, struct iaddr, struct iaddr,
+			      struct subnet *, struct pool *,
+			      struct lease **, int));
+#else /*LARGE_SUBNET*/
 void new_address_range PROTO ((struct parse *, struct iaddr, struct iaddr,
 			       struct subnet *, struct pool *,
 			       struct lease **));
+#endif/*LARGE_SUBNET*/
 isc_result_t dhcp_lease_free (omapi_object_t *, const char *, int);
 isc_result_t dhcp_lease_get (omapi_object_t **, const char *, int);
 int find_grouped_subnet PROTO ((struct subnet **, struct shared_network *,
Index: dhcp-3.0.2/includes/site.h
===================================================================
--- dhcp-3.0.2.orig/includes/site.h	2002-03-12 13:33:39.000000000 -0500
+++ dhcp-3.0.2/includes/site.h	2005-03-09 14:00:49.000000000 -0500
@@ -177,3 +177,7 @@
    traces. */
 
 #define TRACING
+
+/* Define this if you want to be able to support class A/B networks. */
+
+#define LARGE_SUBNET
</patch>


-----Original Message-----
From:	dhcp-hackers-bounce at isc.org on behalf of David W. Hankins
Sent:	Wed 3/30/2005 6:42 PM
To:	dhcp-hackers at isc.org
Cc:	
Subject:	Re: Large subnet patch
our mailing list software strips non-text/plain attachments as
'binary'.

can you send a copy of this patch to dhcp-suggest at isc.org?

i can't promise it will ge integrated in the next feature release, i
haven't looked at it yet, but i'm very interested in the idea since
it's something we'll have to do for ipv6 support (it would be impossible
to enumerate all the leases all the time in a 2^64 address space).

so i'm actually interested in how you solved the problem more than
why.

On Wed, Mar 30, 2005 at 05:37:38PM -0500, Bin Guo wrote:
> Content-Type: text/plain;
> 	charset="Windows-1252"
> Content-Transfer-Encoding: quoted-printable
> This patch is only useful when you want to serve a full class A
> subnet without the required memory to allocate all free leases:
> it defers the free lease allocation until required.
> 
> Of course you will still run out of memory eventually, but a bit
> later...

which leads into the next feature - either forgetting leases in the free
states that are older than 'x', or some lowater/hiwater that deletes
the oldest leases to maintain a memory footprint.

-- 
David W. Hankins		"If you don't do it right the first time,
Software Engineer			you'll just have to do it again."
Internet Systems Consortium, Inc.		-- Jack T. Hankins







More information about the dhcp-hackers mailing list