|
|
a512de |
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
|
|
|
a512de |
index 7e756e0..52ba677 100644
|
|
|
a512de |
--- a/includes/dhcpd.h
|
|
|
a512de |
+++ b/includes/dhcpd.h
|
|
|
a512de |
@@ -3347,6 +3347,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *,
|
|
|
a512de |
isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *,
|
|
|
a512de |
const char *);
|
|
|
a512de |
isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state);
|
|
|
a512de |
+void dhcp_failover_rescind_updates (dhcp_failover_state_t *);
|
|
|
a512de |
isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *,
|
|
|
a512de |
enum failover_state);
|
|
|
a512de |
isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *,
|
|
|
a512de |
diff --git a/server/failover.c b/server/failover.c
|
|
|
a512de |
index 8944102..6083672 100644
|
|
|
a512de |
--- a/server/failover.c
|
|
|
a512de |
+++ b/server/failover.c
|
|
|
a512de |
@@ -1520,8 +1520,16 @@ isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state,
|
|
|
a512de |
/* In these situations, we remain in the current
|
|
|
a512de |
* state, or if in startup enter those states.
|
|
|
a512de |
*/
|
|
|
a512de |
- case communications_interrupted:
|
|
|
a512de |
case conflict_done:
|
|
|
a512de |
+ /* As the peer may not have received or may have
|
|
|
a512de |
+ * lost track of updates we sent previously we
|
|
|
a512de |
+ * rescind them, causing us to retransmit them
|
|
|
a512de |
+ * on an update request.
|
|
|
a512de |
+ */
|
|
|
a512de |
+ dhcp_failover_rescind_updates(state);
|
|
|
a512de |
+ /* fall through */
|
|
|
a512de |
+
|
|
|
a512de |
+ case communications_interrupted:
|
|
|
a512de |
case partner_down:
|
|
|
a512de |
case paused:
|
|
|
a512de |
case recover:
|
|
|
a512de |
@@ -1704,6 +1712,52 @@ isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state)
|
|
|
a512de |
return ISC_R_SUCCESS;
|
|
|
a512de |
}
|
|
|
a512de |
|
|
|
a512de |
+/*!
|
|
|
a512de |
+ * \brief Return any leases on the ack queue back to the update queue
|
|
|
a512de |
+ *
|
|
|
a512de |
+ * Re-schedule any pending updates by moving them from the ack queue
|
|
|
a512de |
+ * (update sent awaiting response) back to the update queue (need to
|
|
|
a512de |
+ * send an update for this lease). This will result in a retransmission
|
|
|
a512de |
+ * of the update.
|
|
|
a512de |
+ *
|
|
|
a512de |
+ * \param state is the state block for the failover connection we are
|
|
|
a512de |
+ * updating.
|
|
|
a512de |
+ */
|
|
|
a512de |
+
|
|
|
a512de |
+void dhcp_failover_rescind_updates (dhcp_failover_state_t *state)
|
|
|
a512de |
+{
|
|
|
a512de |
+ struct lease *lp;
|
|
|
a512de |
+
|
|
|
a512de |
+ if (state->ack_queue_tail == NULL)
|
|
|
a512de |
+ return;
|
|
|
a512de |
+
|
|
|
a512de |
+ /* Zap the flags. */
|
|
|
a512de |
+ for (lp = state->ack_queue_head; lp; lp = lp->next_pending)
|
|
|
a512de |
+ lp->flags = ((lp->flags & ~ON_ACK_QUEUE) | ON_UPDATE_QUEUE);
|
|
|
a512de |
+
|
|
|
a512de |
+ /* Now hook the ack queue to the beginning of the update queue. */
|
|
|
a512de |
+ if (state->update_queue_head) {
|
|
|
a512de |
+ lease_reference(&state->ack_queue_tail->next_pending,
|
|
|
a512de |
+ state->update_queue_head, MDL);
|
|
|
a512de |
+ lease_dereference(&state->update_queue_head, MDL);
|
|
|
a512de |
+ }
|
|
|
a512de |
+ lease_reference(&state->update_queue_head, state->ack_queue_head, MDL);
|
|
|
a512de |
+
|
|
|
a512de |
+ if (!state->update_queue_tail) {
|
|
|
a512de |
+#if defined (POINTER_DEBUG)
|
|
|
a512de |
+ if (state->ack_queue_tail->next_pending) {
|
|
|
a512de |
+ log_error("next pending on ack queue tail.");
|
|
|
a512de |
+ abort();
|
|
|
a512de |
+ }
|
|
|
a512de |
+#endif
|
|
|
a512de |
+ lease_reference(&state->update_queue_tail,
|
|
|
a512de |
+ state->ack_queue_tail, MDL);
|
|
|
a512de |
+ }
|
|
|
a512de |
+ lease_dereference(&state->ack_queue_tail, MDL);
|
|
|
a512de |
+ lease_dereference(&state->ack_queue_head, MDL);
|
|
|
a512de |
+ state->cur_unacked_updates = 0;
|
|
|
a512de |
+}
|
|
|
a512de |
+
|
|
|
a512de |
isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state,
|
|
|
a512de |
enum failover_state new_state)
|
|
|
a512de |
{
|
|
|
a512de |
@@ -1724,37 +1778,9 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state,
|
|
|
a512de |
case normal:
|
|
|
a512de |
case potential_conflict:
|
|
|
a512de |
case partner_down:
|
|
|
a512de |
- if (state -> ack_queue_tail) {
|
|
|
a512de |
- struct lease *lp;
|
|
|
a512de |
-
|
|
|
a512de |
- /* Zap the flags. */
|
|
|
a512de |
- for (lp = state -> ack_queue_head; lp; lp = lp -> next_pending)
|
|
|
a512de |
- lp -> flags = ((lp -> flags & ~ON_ACK_QUEUE) |
|
|
|
a512de |
- ON_UPDATE_QUEUE);
|
|
|
a512de |
-
|
|
|
a512de |
- /* Now hook the ack queue to the beginning of the update
|
|
|
a512de |
- queue. */
|
|
|
a512de |
- if (state -> update_queue_head) {
|
|
|
a512de |
- lease_reference (&state -> ack_queue_tail -> next_pending,
|
|
|
a512de |
- state -> update_queue_head, MDL);
|
|
|
a512de |
- lease_dereference (&state -> update_queue_head, MDL);
|
|
|
a512de |
- }
|
|
|
a512de |
- lease_reference (&state -> update_queue_head,
|
|
|
a512de |
- state -> ack_queue_head, MDL);
|
|
|
a512de |
- if (!state -> update_queue_tail) {
|
|
|
a512de |
-#if defined (POINTER_DEBUG)
|
|
|
a512de |
- if (state -> ack_queue_tail -> next_pending) {
|
|
|
a512de |
- log_error ("next pending on ack queue tail.");
|
|
|
a512de |
- abort ();
|
|
|
a512de |
- }
|
|
|
a512de |
-#endif
|
|
|
a512de |
- lease_reference (&state -> update_queue_tail,
|
|
|
a512de |
- state -> ack_queue_tail, MDL);
|
|
|
a512de |
- }
|
|
|
a512de |
- lease_dereference (&state -> ack_queue_tail, MDL);
|
|
|
a512de |
- lease_dereference (&state -> ack_queue_head, MDL);
|
|
|
a512de |
- state -> cur_unacked_updates = 0;
|
|
|
a512de |
- }
|
|
|
a512de |
+ /* Move the ack queue to the update queue */
|
|
|
a512de |
+ dhcp_failover_rescind_updates(state);
|
|
|
a512de |
+
|
|
|
a512de |
/* We will re-queue a timeout later, if applicable. */
|
|
|
a512de |
cancel_timeout (dhcp_failover_keepalive, state);
|
|
|
a512de |
break;
|
|
|
a512de |
@@ -1858,7 +1884,9 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state,
|
|
|
a512de |
break;
|
|
|
a512de |
|
|
|
a512de |
case potential_conflict:
|
|
|
a512de |
- if (state -> i_am == primary)
|
|
|
a512de |
+ if ((state->i_am == primary) ||
|
|
|
a512de |
+ ((state->i_am == secondary) &&
|
|
|
a512de |
+ (state->partner.state == conflict_done)))
|
|
|
a512de |
dhcp_failover_send_update_request (state);
|
|
|
a512de |
break;
|
|
|
a512de |
|
|
|
a512de |
@@ -1961,7 +1989,18 @@ isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *state,
|
|
|
a512de |
if (state -> partner.state == new_state && state -> me.state) {
|
|
|
a512de |
switch (state -> me.state) {
|
|
|
a512de |
case startup:
|
|
|
a512de |
- dhcp_failover_set_state (state, state -> saved_state);
|
|
|
a512de |
+ /*
|
|
|
a512de |
+ * If we have a peer state we must be connected.
|
|
|
a512de |
+ * If so we should move to potential_conflict
|
|
|
a512de |
+ * instead of resolution_interrupted, otherwise
|
|
|
a512de |
+ * back to whereever we were before we stopped.
|
|
|
a512de |
+ */
|
|
|
a512de |
+ if (state->saved_state == resolution_interrupted)
|
|
|
a512de |
+ dhcp_failover_set_state(state,
|
|
|
a512de |
+ potential_conflict);
|
|
|
a512de |
+ else
|
|
|
a512de |
+ dhcp_failover_set_state(state,
|
|
|
a512de |
+ state->saved_state);
|
|
|
a512de |
return ISC_R_SUCCESS;
|
|
|
a512de |
|
|
|
a512de |
case unknown_state:
|
|
|
a512de |
@@ -2179,6 +2218,17 @@ isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *state,
|
|
|
a512de |
dhcp_failover_set_state(state, new_state);
|
|
|
a512de |
break;
|
|
|
a512de |
|
|
|
a512de |
+ case potential_conflict:
|
|
|
a512de |
+ case resolution_interrupted:
|
|
|
a512de |
+ /*
|
|
|
a512de |
+ * This can happen when the connection is lost and
|
|
|
a512de |
+ * recovered after the primary has moved to
|
|
|
a512de |
+ * conflict-done but the secondary is still in
|
|
|
a512de |
+ * potential-conflict. In that case, we have to
|
|
|
a512de |
+ * remain in conflict-done.
|
|
|
a512de |
+ */
|
|
|
a512de |
+ break;
|
|
|
a512de |
+
|
|
|
a512de |
default:
|
|
|
a512de |
log_fatal("Peer %s: Invalid attempt to move from %s "
|
|
|
a512de |
"to %s while local state is conflict-done.",
|
|
|
a512de |
@@ -4867,16 +4917,17 @@ isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *state)
|
|
|
a512de |
if (!link -> outer || link -> outer -> type != omapi_type_connection)
|
|
|
a512de |
return DHCP_R_INVALIDARG;
|
|
|
a512de |
|
|
|
a512de |
- if (state -> curUPD)
|
|
|
a512de |
- return ISC_R_ALREADYRUNNING;
|
|
|
a512de |
+ /* We allow an update to be restarted in case we requested an update
|
|
|
a512de |
+ * and were interrupted by something. If we had an ALL going we need
|
|
|
a512de |
+ * to restart that. Otherwise we simply continue with the request */
|
|
|
a512de |
+ if (state -> curUPD == FTM_UPDREQALL) {
|
|
|
a512de |
+ return (dhcp_failover_send_update_request_all(state));
|
|
|
a512de |
+ }
|
|
|
a512de |
|
|
|
a512de |
- status = (dhcp_failover_put_message
|
|
|
a512de |
- (link, link -> outer,
|
|
|
a512de |
- FTM_UPDREQ, link->xid++,
|
|
|
a512de |
- (failover_option_t *)0));
|
|
|
a512de |
+ status = (dhcp_failover_put_message(link, link -> outer, FTM_UPDREQ,
|
|
|
a512de |
+ link -> xid++, NULL));
|
|
|
a512de |
|
|
|
a512de |
- if (status == ISC_R_SUCCESS)
|
|
|
a512de |
- state -> curUPD = FTM_UPDREQ;
|
|
|
a512de |
+ state -> curUPD = FTM_UPDREQ;
|
|
|
a512de |
|
|
|
a512de |
#if defined (DEBUG_FAILOVER_MESSAGES)
|
|
|
a512de |
if (status != ISC_R_SUCCESS)
|
|
|
a512de |
@@ -4886,7 +4937,12 @@ isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *state)
|
|
|
a512de |
log_debug ("%s", obuf);
|
|
|
a512de |
}
|
|
|
a512de |
#endif
|
|
|
a512de |
- log_info ("Sent update request message to %s", state -> name);
|
|
|
a512de |
+ if (status == ISC_R_SUCCESS) {
|
|
|
a512de |
+ log_info("Sent update request message to %s", state -> name);
|
|
|
a512de |
+ } else {
|
|
|
a512de |
+ log_error("Failed to send update request all message to %s: %s",
|
|
|
a512de |
+ state -> name, isc_result_totext(status));
|
|
|
a512de |
+ }
|
|
|
a512de |
return status;
|
|
|
a512de |
}
|
|
|
a512de |
|
|
|
a512de |
@@ -4913,17 +4969,14 @@ isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t
|
|
|
a512de |
if (!link -> outer || link -> outer -> type != omapi_type_connection)
|
|
|
a512de |
return DHCP_R_INVALIDARG;
|
|
|
a512de |
|
|
|
a512de |
- /* If there is an UPDREQ in progress, then upgrade to UPDREQALL. */
|
|
|
a512de |
- if (state -> curUPD && (state -> curUPD != FTM_UPDREQ))
|
|
|
a512de |
- return ISC_R_ALREADYRUNNING;
|
|
|
a512de |
+ /* We allow an update to be restarted in case we requested an update
|
|
|
a512de |
+ * and were interrupted by something.
|
|
|
a512de |
+ */
|
|
|
a512de |
|
|
|
a512de |
- status = (dhcp_failover_put_message
|
|
|
a512de |
- (link, link -> outer,
|
|
|
a512de |
- FTM_UPDREQALL, link->xid++,
|
|
|
a512de |
- (failover_option_t *)0));
|
|
|
a512de |
+ status = (dhcp_failover_put_message(link, link -> outer, FTM_UPDREQALL,
|
|
|
a512de |
+ link -> xid++, NULL));
|
|
|
a512de |
|
|
|
a512de |
- if (status == ISC_R_SUCCESS)
|
|
|
a512de |
- state -> curUPD = FTM_UPDREQALL;
|
|
|
a512de |
+ state -> curUPD = FTM_UPDREQALL;
|
|
|
a512de |
|
|
|
a512de |
#if defined (DEBUG_FAILOVER_MESSAGES)
|
|
|
a512de |
if (status != ISC_R_SUCCESS)
|
|
|
a512de |
@@ -4933,7 +4986,12 @@ isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t
|
|
|
a512de |
log_debug ("%s", obuf);
|
|
|
a512de |
}
|
|
|
a512de |
#endif
|
|
|
a512de |
- log_info ("Sent update request all message to %s", state -> name);
|
|
|
a512de |
+ if (status == ISC_R_SUCCESS) {
|
|
|
a512de |
+ log_info("Sent update request all message to %s", state -> name);
|
|
|
a512de |
+ } else {
|
|
|
a512de |
+ log_error("Failed to send update request all message to %s: %s",
|
|
|
a512de |
+ state -> name, isc_result_totext(status));
|
|
|
a512de |
+ }
|
|
|
a512de |
return status;
|
|
|
a512de |
}
|
|
|
a512de |
|