diff --git a/RELNOTES b/RELNOTES index a7027019..b6daddf9 100644 --- a/RELNOTES +++ b/RELNOTES @@ -54,6 +54,11 @@ by Eric Young (eay@cryptsoft.com). Changes since 4.3.2 +- 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 diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 2a43229f..378459b9 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -2313,9 +2313,7 @@ void ack_lease (struct packet *, struct lease *, unsigned int, TIME, char *, int, struct host_decl *); void echo_client_id(struct packet*, struct lease*, struct option_state*, struct option_state*); -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 *, @@ -2953,7 +2951,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); diff --git a/server/db.c b/server/db.c index e1f1beb7..d4d42feb 100644 --- a/server/db.c +++ b/server/db.c @@ -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 * @@ -1017,9 +1017,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. */ diff --git a/server/dhcp.c b/server/dhcp.c index e71720f6..ba32c5b4 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -31,7 +31,6 @@ #include #include -static void commit_leases_ackout(void *foo); static void maybe_return_agent_options(struct packet *packet, struct option_state *options); static int reuse_lease (struct packet* packet, struct lease* new_lease, @@ -40,6 +39,11 @@ static int reuse_lease (struct packet* packet, struct lease* new_lease, int outstanding_pings; +#if defined(DELAYED_ACK) +static void delayed_ack_enqueue(struct lease *); +static void delayed_acks_timer(void *); + + struct leasequeue *ackqueue_head, *ackqueue_tail; static struct leasequeue *free_ackqueue; static struct timeval max_fsync; @@ -49,6 +53,7 @@ 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; @@ -3368,6 +3373,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) } } +#if defined(DELAYED_ACK) + /* * CC: queue single ACK: * - write the lease (but do not fsync it yet) @@ -3377,7 +3384,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) * but only up to the max timer value. */ -void +static void delayed_ack_enqueue(struct lease *lease) { struct leasequeue *q; @@ -3405,11 +3412,9 @@ delayed_ack_enqueue(struct lease *lease) outstanding_acks++; if (outstanding_acks > max_outstanding_acks) { - commit_leases(); - - /* Reset max_fsync and cancel any pending timeout. */ - memset(&max_fsync, 0, sizeof(max_fsync)); - cancel_timeout(commit_leases_ackout, NULL); + /* Cancel any pending timeout and call handler directly */ + cancel_timeout(delayed_acks_timer, NULL); + delayed_acks_timer(NULL); } else { struct timeval next_fsync; @@ -3440,44 +3445,68 @@ delayed_ack_enqueue(struct lease *lease) next_fsync.tv_usec = max_fsync.tv_usec; } - add_timeout(&next_fsync, commit_leases_ackout, NULL, + add_timeout(&next_fsync, delayed_acks_timer, NULL, (tvref_t) NULL, (tvunref_t) NULL); } } -static void -commit_leases_ackout(void *foo) -{ - if (outstanding_acks) { - commit_leases(); - - memset(&max_fsync, 0, sizeof(max_fsync)); - } -} - -/* CC: process the delayed ACK responses: - - send out the ACK packets - - move the queue slots to the free list +/* 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 -flush_ackqueue(void *foo) +static void +delayed_acks_timer(void *foo) { struct leasequeue *ack, *p; + + /* Reset max fsync */ + memset(&max_fsync, 0, sizeof(max_fsync)); + + if (!outstanding_acks) { + /* Nothing to do, so punt, shouldn't happen? */ + return; + } + + /* Commit the leases first */ + commit_leases(); + + /* Now process the delayed ACKs + - update failover peer + - send out the ACK packets + - move the queue slots to the free list + */ + /* 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; @@ -3500,6 +3529,8 @@ relinquish_ackqueue(void) } #endif +#endif /* defined(DELAYED_ACK) */ + void dhcp_reply (lease) struct lease *lease; { diff --git a/server/dhcpd.c b/server/dhcpd.c index cb4f0112..ebb6d3e3 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -1059,7 +1059,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, @@ -1087,6 +1088,7 @@ void postconf_initialization (int quiet) data_string_forget(&db, MDL); } +#endif oc = lookup_option(&server_universe, options, SV_DONT_USE_FSYNC); if ((oc != NULL) &&