Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 0546855d7431d3fdfce69d4cced3d294 > files > 21

dhcp-3.0.5-31.el5.src.rpm

diff -up dhcp-3.0.5/server/dhcp.c.exhaustion dhcp-3.0.5/server/dhcp.c
--- dhcp-3.0.5/server/dhcp.c.exhaustion	2010-08-04 15:43:59.000000000 +0200
+++ dhcp-3.0.5/server/dhcp.c	2010-08-04 15:45:29.000000000 +0200
@@ -3087,10 +3087,14 @@ int find_lease (struct lease **lp,
 	}
 
 	/* If we found leases matching the client identifier, loop through
-	   the n_uid pointer looking for one that's actually valid.   We
-	   can't do this until we get here because we depend on
-	   packet -> known, which may be set by either the uid host
-	   lookup or the haddr host lookup. */
+	 * the n_uid pointer looking for one that's actually valid.   We
+	 * can't do this until we get here because we depend on
+	 * packet -> known, which may be set by either the uid host
+	 * lookup or the haddr host lookup.
+	 *
+	 * Note that the n_uid lease chain is sorted in order of
+	 * preference, so the first one is the best one.
+	 */
 	while (uid_lease) {
 #if defined (DEBUG_FIND_LEASE)
 		log_info ("trying next lease matching client id: %s",
@@ -3149,8 +3153,12 @@ int find_lease (struct lease **lp,
 #endif
 
 	/* Find a lease whose hardware address matches, whose client
-	   identifier matches, that's permitted, and that's on the
-	   correct subnet. */
+	 * identifier matches (or equally doesn't have one), that's
+	 * permitted, and that's on the correct subnet.
+	 *
+	 * Note that the n_hw chain is sorted in order of preference, so
+	 * the first one found is the best one.
+	 */
 	h.hlen = packet -> raw -> hlen + 1;
 	h.hbuf [0] = packet -> raw -> htype;
 	memcpy (&h.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
diff -up dhcp-3.0.5/server/mdb.c.exhaustion dhcp-3.0.5/server/mdb.c
--- dhcp-3.0.5/server/mdb.c.exhaustion	2010-08-04 15:43:59.000000000 +0200
+++ dhcp-3.0.5/server/mdb.c	2010-08-04 15:50:09.000000000 +0200
@@ -787,8 +787,6 @@ int supersede_lease (comp, lease, commit
 	int propogate;
 	int pimmediate;
 {
-	int enter_uid = 0;
-	int enter_hwaddr = 0;
 	struct lease *lp, **lq, *prev;
 
 #if defined (FAILOVER_PROTOCOL)
@@ -834,28 +832,21 @@ int supersede_lease (comp, lease, commit
 
 	/* If there's a Unique ID, dissociate it from the hash
 	   table and free it if necessary. */
-	if (comp -> uid) {
-		uid_hash_delete (comp);
-		enter_uid = 1;
-		if (comp -> uid != &comp -> uid_buf [0]) {
-			dfree (comp -> uid, MDL);
-			comp -> uid_max = 0;
-			comp -> uid_len = 0;
+	if (comp->uid) {
+		uid_hash_delete(comp);
+		if (comp->uid != comp->uid_buf) {
+			dfree(comp->uid, MDL);
+			comp->uid_max = 0;
+			comp->uid_len = 0;
 		}
 		comp -> uid = (unsigned char *)0;
-	} else
-		enter_uid = 1;
+	}
 
-	if (comp -> hardware_addr.hlen &&
-	    ((comp -> hardware_addr.hlen !=
-	      lease -> hardware_addr.hlen) ||
-	     memcmp (comp -> hardware_addr.hbuf,
-		     lease -> hardware_addr.hbuf,
-		     comp -> hardware_addr.hlen))) {
-		hw_hash_delete (comp);
-		enter_hwaddr = 1;
-	} else if (!comp -> hardware_addr.hlen)
-		enter_hwaddr = 1;
+	/* If there's a hardware address, remove the lease from its
+	 * old position in the hash bucket's ordered list.
+	 */
+	if (comp->hardware_addr.hlen)
+		hw_hash_delete(comp);
 
 	/* If the lease has been billed to a class, remove the billing. */
 	if (comp -> billing_class != lease -> billing_class) {
@@ -945,14 +936,12 @@ int supersede_lease (comp, lease, commit
 	}
 
 	/* Record the lease in the uid hash if necessary. */
-	if (enter_uid && comp -> uid) {
-		uid_hash_add (comp);
-	}
+	if (comp->uid)
+		uid_hash_add(comp);
 
 	/* Record it in the hardware address hash if necessary. */
-	if (enter_hwaddr && lease -> hardware_addr.hlen) {
-		hw_hash_add (comp);
-	}
+	if (comp->hardware_addr.hlen)
+		hw_hash_add(comp);
 
 #if defined (FAILOVER_PROTOCOL)
 	comp->cltt = lease->cltt;
@@ -1581,29 +1570,117 @@ int find_lease_by_hw_addr (struct lease 
 				  hwaddr, hwlen, file, line);
 }
 
-/* Add the specified lease to the uid hash. */
-
-void uid_hash_add (lease)
-	struct lease *lease;
+/* If the lease is preferred over the candidate, return truth.  The
+ * 'cand' and 'lease' names are retained to read more clearly against
+ * the 'uid_hash_add' and 'hw_hash_add' functions (this is common logic
+ * to those two functions).
+ *
+ * 1) ACTIVE leases are preferred.  The active lease with
+ *    the longest lifetime is preferred over shortest.
+ * 2) "transitional states" are next, this time with the
+ *    most recent CLTT.
+ * 3) free/backup/etc states are next, again with CLTT.  In truth we
+ *    should never see reset leases for this.
+ * 4) Abandoned leases are always dead last.
+ */
+static isc_boolean_t
+client_lease_preferred(struct lease *cand, struct lease *lease)
 {
-	struct lease *head = (struct lease *)0;
-	struct lease *next = (struct lease *)0;
+	if (cand->binding_state == FTS_ACTIVE) {
+		if (lease->binding_state == FTS_ACTIVE &&
+		    lease->ends >= cand->ends)
+			return ISC_TRUE;
+	} else if (cand->binding_state == FTS_EXPIRED ||
+		   cand->binding_state == FTS_RELEASED) {
+		if (lease->binding_state == FTS_ACTIVE)
+			return ISC_TRUE;
+
+		if ((lease->binding_state == FTS_EXPIRED ||
+		     lease->binding_state == FTS_RELEASED) &&
+		    lease->cltt >= cand->cltt)
+			return ISC_TRUE;
+	} else if (cand->binding_state != FTS_ABANDONED) {
+		if (lease->binding_state == FTS_ACTIVE ||
+		    lease->binding_state == FTS_EXPIRED ||
+		    lease->binding_state == FTS_RELEASED)
+			return ISC_TRUE;
+
+		if (lease->binding_state != FTS_ABANDONED &&
+		    lease->cltt >= cand->cltt)
+			return ISC_TRUE;
+	} else /* (cand->binding_state == FTS_ABANDONED) */ {
+		if (lease->binding_state != FTS_ABANDONED ||
+		    lease->cltt >= cand->cltt)
+			return ISC_TRUE;
+	}
 
+	return ISC_FALSE;
+}
+
+/* Add the specified lease to the uid hash. */
+void
+uid_hash_add(struct lease *lease)
+{
+	struct lease *head = NULL;
+	struct lease *cand = NULL;
+	struct lease *prev = NULL;
+	struct lease *next = NULL;
 
 	/* If it's not in the hash, just add it. */
 	if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL))
 		lease_hash_add (lease_uid_hash, lease -> uid,
 				lease -> uid_len, lease, MDL);
 	else {
-		/* Otherwise, attach it to the end of the list. */
-		while (head -> n_uid) {
-			lease_reference (&next, head -> n_uid, MDL);
-			lease_dereference (&head, MDL);
-			lease_reference (&head, next, MDL);
-			lease_dereference (&next, MDL);
+		/* Otherwise, insert it into the list in order of its
+		 * preference for "resuming allocation to the client."
+		 *
+		 * Because we don't have control of the hash bucket index
+		 * directly, we have to remove and re-insert the client
+		 * id into the hash if we're inserting onto the head.
+		 */
+		lease_reference(&cand, head, MDL);
+		while (cand != NULL) {
+			if (client_lease_preferred(cand, lease))
+				break;
+
+			if (prev != NULL)
+				lease_dereference(&prev, MDL);
+			lease_reference(&prev, cand, MDL);
+
+			if (cand->n_uid != NULL)
+				lease_reference(&next, cand->n_uid, MDL);
+
+			lease_dereference(&cand, MDL);
+
+			if (next != NULL) {
+				lease_reference(&cand, next, MDL);
+				lease_dereference(&next, MDL);
+			}
 		}
-		lease_reference (&head -> n_uid, lease, MDL);
-		lease_dereference (&head, MDL);
+
+		/* If we want to insert 'before cand', and prev is NULL,
+		 * then it was the head of the list.  Assume that position.
+		 */
+		if (prev == NULL) {
+			lease_reference(&lease->n_uid, head, MDL);
+			lease_hash_delete(lease_uid_hash, lease->uid,
+					  lease->uid_len, MDL);
+			lease_hash_add(lease_uid_hash, lease->uid,
+				       lease->uid_len, lease, MDL);
+		} else /* (prev != NULL) */ {
+			if(prev->n_uid != NULL) {
+				lease_reference(&lease->n_uid, prev->n_uid,
+						MDL);
+				lease_dereference(&prev->n_uid, MDL);
+			}
+			lease_reference(&prev->n_uid, lease, MDL);
+
+			lease_dereference(&prev, MDL);
+		}
+
+		if (cand != NULL)
+			lease_dereference(&cand, MDL);
+		lease_dereference(&head, MDL);
 	}
 }
 
@@ -1657,11 +1734,13 @@ void uid_hash_delete (lease)
 
 /* Add the specified lease to the hardware address hash. */
 
-void hw_hash_add (lease)
-	struct lease *lease;
+void
+hw_hash_add(struct lease *lease)
 {
-	struct lease *head = (struct lease *)0;
-	struct lease *next = (struct lease *)0;
+	struct lease *head = NULL;
+	struct lease *cand = NULL;
+	struct lease *prev = NULL;
+	struct lease *next = NULL;
 
 	/* If it's not in the hash, just add it. */
 	if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
@@ -1671,16 +1750,59 @@ void hw_hash_add (lease)
 				lease -> hardware_addr.hlen,
 				lease, MDL);
 	else {
-		/* Otherwise, attach it to the end of the list. */
-		while (head -> n_hw) {
-			lease_reference (&next, head -> n_hw, MDL);
-			lease_dereference (&head, MDL);
-			lease_reference (&head, next, MDL);
-			lease_dereference (&next, MDL);
+		/* Otherwise, insert it into the list in order of its
+		 * preference for "resuming allocation to the client."
+		 *
+		 * Because we don't have control of the hash bucket index
+		 * directly, we have to remove and re-insert the client
+		 * id into the hash if we're inserting onto the head.
+		 */
+		lease_reference(&cand, head, MDL);
+		while (cand != NULL) {
+			if (client_lease_preferred(cand, lease))
+				break;
+
+			if (prev != NULL)
+				lease_dereference(&prev, MDL);
+			lease_reference(&prev, cand, MDL);
+
+			if (cand->n_hw != NULL)
+				lease_reference(&next, cand->n_hw, MDL);
+
+			lease_dereference(&cand, MDL);
+
+			if (next != NULL) {
+				lease_reference(&cand, next, MDL);
+				lease_dereference(&next, MDL);
+			}
 		}
 
-		lease_reference (&head -> n_hw, lease, MDL);
-		lease_dereference (&head, MDL);
+		/* If we want to insert 'before cand', and prev is NULL,
+		 * then it was the head of the list.  Assume that position.
+		 */
+		if (prev == NULL) {
+			lease_reference(&lease->n_hw, head, MDL);
+			lease_hash_delete(lease_hw_addr_hash,
+					  lease->hardware_addr.hbuf,
+					  lease->hardware_addr.hlen, MDL);
+			lease_hash_add(lease_hw_addr_hash,
+				       lease->hardware_addr.hbuf,
+				       lease->hardware_addr.hlen,
+				       lease, MDL);
+		} else /* (prev != NULL) */ {
+			if(prev->n_hw != NULL) {
+				lease_reference(&lease->n_hw, prev->n_hw,
+						MDL);
+				lease_dereference(&prev->n_hw, MDL);
+			}
+			lease_reference(&prev->n_hw, lease, MDL);
+
+			lease_dereference(&prev, MDL);
+		}
+
+		if (cand != NULL)
+			lease_dereference(&cand, MDL);
+		lease_dereference(&head, MDL);
 	}
 }