]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Delayed-ack now works correctly with failover
authorThomas Markwalder <tmark@isc.org>
Tue, 16 Jun 2015 15:43:12 +0000 (11:43 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 16 Jun 2015 15:43:12 +0000 (11:43 -0400)
    Merges in 31474.

Conflicts:

includes/dhcpd.h
server/dhcp.c

RELNOTES
includes/dhcpd.h
server/db.c
server/dhcp.c
server/dhcpd.c

index 192a5edcbeb65ce51cef1acf63933a56b184f0bf..887b422ab578656cd03a51d0cf409bc8eb6cea38 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -60,6 +60,11 @@ by Eric Young (eay@cryptsoft.com).
 
                        Changes since 4.1-ESV-R11
 
+- Delayed-ack now works properly with Failover. Prior to this, bind updates
+  post startup were being queued but never delivered. Among other things, this
+  was causing leases to not transition from expired or released to free.
+  [ISC-Bugs #31474]
+
 - The server now does a better check to see if it can allocate the memory
   for large blocks of v4 leases and should provide a slightly better error
   message.  Note well: the server pre-allocates v4 addresses, if you use
index d374aa36176e4509edc919181d5187f4a00b642d..819c1c3cb33f64d65de661dbb14b7c2e64c06725 100644 (file)
@@ -638,6 +638,10 @@ struct lease_state {
 # define DEFAULT_ACK_DELAY_USECS 250000 /* 1/4 of a second */
 #endif
 
+#if !defined (DEFAULT_MIN_ACK_DELAY_USECS)
+# define DEFAULT_MIN_ACK_DELAY_USECS 10000 /* 1/100 second */
+#endif
+
 #if !defined (DEFAULT_DEFAULT_LEASE_TIME)
 # define DEFAULT_DEFAULT_LEASE_TIME 43200
 #endif
@@ -1969,9 +1973,7 @@ void dhcpinform (struct packet *, int);
 void nak_lease (struct packet *, struct iaddr *cip);
 void ack_lease (struct packet *, struct lease *,
                unsigned int, TIME, char *, int, struct host_decl *);
-void delayed_ack_enqueue(struct lease *);
-void commit_leases_readerdry(void *);
-void flush_ackqueue(void *);
+
 void dhcp_reply (struct lease *);
 int find_lease (struct lease **, struct packet *,
                struct shared_network *, int *, int *, struct lease *,
@@ -1996,6 +1998,9 @@ void get_server_source_address(struct in_addr *from,
 void setup_server_source_address(struct in_addr *from,
                                 struct option_state *options,
                                 struct packet *packet);
+#if defined(DELAYED_ACK)
+void delayed_acks_timer(void *);
+#endif
 
 /* dhcpleasequery.c */
 void dhcpleasequery (struct packet *, int);
@@ -2604,7 +2609,6 @@ isc_result_t write_named_billing_class(const void *, unsigned, void *);
 void write_billing_classes (void);
 int write_billing_class (struct class *);
 void commit_leases_timeout (void *);
-void commit_leases_readerdry(void *);
 int commit_leases (void);
 int commit_leases_timed (void);
 void db_startup (int);
index 0ba711479fba097f6694862106e96d77e4705442..7186cb571fda716a2f86dedb1597a952f31e7e03 100644 (file)
@@ -3,7 +3,7 @@
    Persistent database management routines for DHCPD... */
 
 /*
- * Copyright (c) 2012-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2012-2015 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (c) 1995-2003 by Internet Software Consortium
  *
@@ -978,9 +978,6 @@ int commit_leases ()
                return 0;
        }
 
-       /* send out all deferred ACKs now */
-       flush_ackqueue(NULL);
-
        /* If we haven't rewritten the lease database in over an
           hour, rewrite it now.  (The length of time should probably
           be configurable. */
index d24f520e8b71d713342934caecacfe122d2f6866..04e4e5e1acab3b1ca2dfe2c053e9c1fcca317ed9 100644 (file)
 #include <limits.h>
 #include <sys/time.h>
 
-static void commit_leases_ackout(void *foo);
-
 int outstanding_pings;
 
+#if defined(DELAYED_ACK)
+void delayed_acks_timer(void *);
+static void delayed_ack_enqueue(struct lease *);
+
+
 struct leasequeue *ackqueue_head, *ackqueue_tail;
 static struct leasequeue *free_ackqueue;
-static struct timeval next_fsync;
-int outstanding_acks;
+static struct timeval max_fsync;
+int outstanding_acks = 0;
 int max_outstanding_acks = DEFAULT_DELAYED_ACK;
 int max_ack_delay_secs = DEFAULT_ACK_DELAY_SECS;
 int max_ack_delay_usecs = DEFAULT_ACK_DELAY_USECS;
+int min_ack_delay_usecs = DEFAULT_MIN_ACK_DELAY_USECS;
+#endif
 
 static char dhcp_message [256];
 static int site_code_min;
@@ -2912,14 +2917,17 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
        }
 }
 
-/* CC: queue single ACK:
-   - write the lease (but do not fsync it yet)
-   - add to double linked list
-   - commit if more than xx ACKs pending
-   - Not yet: schedule a fsync at the next interval (1 second?)
+#if defined(DELAYED_ACK)
+/*
+ * CC: queue single ACK:
+ * - write the lease (but do not fsync it yet)
+ * - add to double linked list
+ * - commit if more than xx ACKs pending
+ * - if necessary set the max timer and bump the next timer
+ *   but only up to the max timer value.
  */
 
-void
+static void
 delayed_ack_enqueue(struct lease *lease)
 {
        struct leasequeue *q;
@@ -2946,69 +2954,102 @@ delayed_ack_enqueue(struct lease *lease)
                q->next->prev = q;
 
        outstanding_acks++;
-       if (outstanding_acks > max_outstanding_acks) 
-               commit_leases();
+       if (outstanding_acks > max_outstanding_acks) {
+               /* Cancel any pending timeout and call handler directly */
+               cancel_timeout(delayed_acks_timer, NULL);
+               delayed_acks_timer(NULL);
+       } else {
+               struct timeval next_fsync;
 
-       /* If next_fsync is not set, schedule an fsync. */
-       if (next_fsync.tv_sec == 0 && next_fsync.tv_usec == 0) {
-               next_fsync.tv_sec = cur_tv.tv_sec + max_ack_delay_secs;
-               next_fsync.tv_usec = cur_tv.tv_usec + max_ack_delay_usecs;
+               if (max_fsync.tv_sec == 0 && max_fsync.tv_usec == 0) {
+                       /* set the maximum time we'll wait */
+                       max_fsync.tv_sec = cur_tv.tv_sec + max_ack_delay_secs;
+                       max_fsync.tv_usec = cur_tv.tv_usec +
+                               max_ack_delay_usecs;
 
-               if (next_fsync.tv_usec >= 1000000) {
-                       next_fsync.tv_sec++;
-                       next_fsync.tv_usec -= 1000000;
+                       if (max_fsync.tv_usec >= 1000000) {
+                               max_fsync.tv_sec++;
+                               max_fsync.tv_usec -= 1000000;
+                       }
                }
 
-               add_timeout(&next_fsync, commit_leases_ackout, NULL,
+                /* Set the timeout */
+                next_fsync.tv_sec = cur_tv.tv_sec;
+                next_fsync.tv_usec = cur_tv.tv_usec + min_ack_delay_usecs;
+                if (next_fsync.tv_usec >= 1000000) {
+                        next_fsync.tv_sec++;
+                        next_fsync.tv_usec -= 1000000;
+                }
+                /* but not more than the max */
+                if ((next_fsync.tv_sec > max_fsync.tv_sec) ||
+                    ((next_fsync.tv_sec == max_fsync.tv_sec) &&
+                     (next_fsync.tv_usec > max_fsync.tv_usec))) {
+                        next_fsync.tv_sec = max_fsync.tv_sec;
+                        next_fsync.tv_usec = max_fsync.tv_usec;
+                }
+
+               add_timeout(&next_fsync, delayed_acks_timer, NULL,
                            (tvref_t) NULL, (tvunref_t) NULL);
        }
 }
 
+/* Processes any delayed acks:
+ * Commits the leases and then for each delayed ack:
+ *  - Update the failover peer if we're in failover
+ *  - Send the REPLY to the client
+ */
 void
-commit_leases_readerdry(void *foo) 
+delayed_acks_timer(void *foo)
 {
-       if (outstanding_acks) {
-               commit_leases();
+       struct leasequeue *ack, *p;
+
+       /* Reset max fsync */
+       memset(&max_fsync, 0, sizeof(max_fsync));
 
-               /* Reset next_fsync and cancel any pending timeout. */
-               memset(&next_fsync, 0, sizeof(next_fsync));
-               cancel_timeout(commit_leases_ackout, NULL);
+       if (!outstanding_acks) {
+               /* Nothing to do, so punt, shouldn't happen? */
+               return;
        }
-}
 
-static void
-commit_leases_ackout(void *foo)
-{
-       if (outstanding_acks) {
-               commit_leases();
+       /* Commit the leases first */
+       commit_leases();
 
-               memset(&next_fsync, 0, sizeof(next_fsync));
-       }
-}
+       /* Now process the delayed ACKs
+        - update failover peer
+        - send out the ACK packets
+        - move the queue slots to the free list
+       */
 
-/* CC: process the delayed ACK responses:
-   - send out the ACK packets
-   - move the queue slots to the free list
- */
-void
-flush_ackqueue(void *foo) 
-{
-       struct leasequeue *ack, *p;
        /*  process from bottom to retain packet order */
        for (ack = ackqueue_tail ; ack ; ack = p) { 
                p = ack->prev;
 
+#if defined(FAILOVER_PROTOCOL)
+               /* If we're in failover we need to send any deferred
+               * bind updates as well as the replies */
+               if (ack->lease->pool) {
+                       dhcp_failover_state_t *fpeer;
+
+                       fpeer = ack->lease->pool->failover_peer;
+                       if (fpeer && fpeer->link_to_peer) {
+                               dhcp_failover_send_updates(fpeer);
+                       }
+               }
+#endif
+
                /* dhcp_reply() requires that the reply state still be valid */
                if (ack->lease->state == NULL)
                        log_error("delayed ack for %s has gone stale",
                                  piaddr(ack->lease->ip_addr));
-               else
+               else {
                        dhcp_reply(ack->lease);
+               }
 
                lease_dereference(&ack->lease, MDL);
                ack->next = free_ackqueue;
                free_ackqueue = ack;
        }
+
        ackqueue_head = NULL;
        ackqueue_tail = NULL;
        outstanding_acks = 0;
@@ -3031,6 +3072,8 @@ relinquish_ackqueue(void)
 }
 #endif
 
+#endif /* defined(DELAYED_ACK) */
+
 void dhcp_reply (lease)
        struct lease *lease;
 {
index 991c3688f730e8999cdaa76fcd6d9e87653e67a2..d0ebbf824cb43be2a3bfb60debf8b33f385cb2d9 100644 (file)
@@ -856,8 +856,9 @@ main(int argc, char **argv) {
 
        omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
                             (omapi_object_t *)0, "state", server_running);
-
-       register_eventhandler(&rw_queue_empty,commit_leases_readerdry);
+#if defined(DELAYED_ACK)
+       register_eventhandler(&rw_queue_empty, delayed_acks_timer);
+#endif
        
        /* Receive packets and dispatch them... */
        dispatch ();
@@ -1093,7 +1094,8 @@ void postconf_initialization (int quiet)
                        data_string_forget (&db, MDL);
                }
        }
-       
+
+#if defined(DELAYED_ACK)
        oc = lookup_option(&server_universe, options, SV_DELAYED_ACK);
        if (oc &&
            evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
@@ -1121,6 +1123,7 @@ void postconf_initialization (int quiet)
 
                data_string_forget(&db, MDL);
        }
+#endif
 
        /* Don't need the options anymore. */
        option_state_dereference (&options, MDL);