From: Ted Lemon Date: Tue, 2 May 2000 00:17:30 +0000 (+0000) Subject: - Support load balancing. X-Git-Tag: V3-BETA-2-PATCH-1~212 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85a537351f40fc2560a5e0a8d68e015b9e16ad57;p=thirdparty%2Fdhcp.git - Support load balancing. - Actually start the failover protocol. - Fixes to get the protocol to the point of a completed handshake. - Initial failover state machine (needs work yet). --- diff --git a/server/failover.c b/server/failover.c index 89acc0d2b..2474cccbb 100644 --- a/server/failover.c +++ b/server/failover.c @@ -43,7 +43,7 @@ #ifndef lint static char copyright[] = -"$Id: failover.c,v 1.8 2000/03/17 04:00:31 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n"; +"$Id: failover.c,v 1.9 2000/05/02 00:17:30 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -56,14 +56,54 @@ static dhcp_failover_state_t *failover_states; static isc_result_t do_a_failover_option (omapi_object_t *, dhcp_failover_link_t *); -void enter_failover_peer (peer) +void dhcp_failover_startup () +{ + dhcp_failover_state_t *state; + isc_result_t status; + + for (state = failover_states; state; state = state -> next) { + if (state -> i_am == secondary) { + status = (dhcp_failover_listen + ((omapi_object_t *)state)); + } else { + status = (dhcp_failover_link_initiate + ((omapi_object_t *)state)); + } + if (status != ISC_R_SUCCESS) { + log_error ("failover peer %s: %s", state -> name, + isc_result_totext (status)); + } + } +} + +isc_result_t enter_failover_peer (peer) dhcp_failover_state_t *peer; { + dhcp_failover_state_t *dup = (dhcp_failover_state_t *)0; + isc_result_t status; + + status = find_failover_peer (&dup, peer -> name); + if (status == ISC_R_NOTFOUND) { + if (failover_states) { + omapi_object_reference + ((omapi_object_t **)&peer -> next, + (omapi_object_t *)failover_states, MDL); + omapi_object_dereference + ((omapi_object_t **)&failover_states, MDL); + } + omapi_object_reference ((omapi_object_t **)&failover_states, + (omapi_object_t *)peer, MDL); + return ISC_R_SUCCESS; + } + if (status == ISC_R_SUCCESS) + return ISC_R_EXISTS; + + return status; } isc_result_t find_failover_peer (peer, name) dhcp_failover_state_t **peer; - char *name; + const char *name; { dhcp_failover_state_t *p; @@ -96,12 +136,13 @@ isc_result_t dhcp_failover_link_initiate (omapi_object_t *h) { isc_result_t status; dhcp_failover_link_t *obj; - unsigned long port; omapi_value_t *value = (omapi_value_t *)0; dhcp_failover_state_t *state; omapi_object_t *o; int i; struct data_string ds; + omapi_addr_list_t *addrs = (omapi_addr_list_t *)0; + omapi_addr_t local_addr; /* Find the failover state in the object chain. */ for (o = h; o -> outer; o = o -> outer) @@ -122,52 +163,80 @@ isc_result_t dhcp_failover_link_initiate (omapi_object_t *h) obj -> type = dhcp_type_failover_link; option_cache_reference (&obj -> peer_address, state -> address, MDL); obj -> peer_port = state -> port; + omapi_object_reference ((omapi_object_t **)&obj -> state_object, + (omapi_object_t *)state, MDL); memset (&ds, 0, sizeof ds); if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, obj -> peer_address, MDL)) { - option_cache_dereference (&obj -> peer_address, MDL); omapi_object_dereference ((omapi_object_t **)&obj, MDL); return ISC_R_UNEXPECTED; } - /* Kludge around the fact that omapi_connect expects an ASCII string - representing the address to which to connect. */ - status = ISC_R_INVALIDARG; - for (i = 0; i + 4 <= ds.len; i += 4) { - char peer_name [40]; - sprintf (peer_name, "%d.%d.%d.%d", - ds.data [i], ds.data [i + 1], - ds.data [i + 2], ds.data [i + 3]); - status = omapi_connect ((omapi_object_t *)obj, - peer_name, port); - if (status == ISC_R_SUCCESS) - break; + /* Make an omapi address list out of a buffer containing zero or more + IPv4 addresses. */ + status = omapi_addr_list_new (&addrs, ds.len / 4, MDL); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, MDL); + return status; + } + + for (i = 0; i < addrs -> count; i++) { + addrs -> addresses [i].addrtype = AF_INET; + addrs -> addresses [i].addrlen = sizeof (struct in_addr); + memcpy (addrs -> addresses [i].address, + &ds.data [i * 4], sizeof (struct in_addr)); + addrs -> addresses [i].port = obj -> peer_port; } data_string_forget (&ds, MDL); - /* If we didn't connect to any of the addresses, give up. */ + /* Now figure out the local address that we're supposed to use. */ + if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, + (struct option_state *)0, + (struct option_state *)0, + &global_scope, state -> server_addr, + MDL)) { + memset (&local_addr, 0, sizeof local_addr); + local_addr.addrtype = AF_INET; + local_addr.addrlen = sizeof (struct in_addr); + } else { + if (ds.len != sizeof (struct in_addr)) { + data_string_forget (&ds, MDL); + omapi_object_dereference ((omapi_object_t **)&obj, + MDL); + omapi_addr_list_dereference (&addrs, MDL); + return ISC_R_INVALIDARG; + } + local_addr.addrtype = AF_INET; + local_addr.addrlen = ds.len; + memcpy (local_addr.address, ds.data, ds.len); + data_string_forget (&ds, MDL); + local_addr.port = state -> listen_port; + } + + status = omapi_connect_list ((omapi_object_t *)obj, + addrs, &local_addr); + omapi_addr_list_dereference (&addrs, MDL); + + /* If we didn't succeed in starting to connect, fail. */ if (status != ISC_R_SUCCESS) { - lose: + loselose: omapi_object_dereference ((omapi_object_t **)&obj, MDL); - option_cache_dereference (&obj -> peer_address, MDL); return status; } status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); - if (status != ISC_R_SUCCESS) - goto lose; + if (status != ISC_R_SUCCESS) { + lose: + omapi_disconnect (h, 1); + goto loselose; + } status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) goto lose; - /* Send the introductory message. */ - status = dhcp_failover_send_connect ((omapi_object_t *)obj); - if (status != ISC_R_SUCCESS) - goto lose; - omapi_object_dereference ((omapi_object_t **)&obj, MDL); return ISC_R_SUCCESS; } @@ -187,6 +256,14 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h, } link = (dhcp_failover_link_t *)h; + if (!strcmp (name, "connect")) { + /* Send the introductory message. */ + status = dhcp_failover_send_connect (h); + if (status != ISC_R_SUCCESS) + omapi_disconnect (h, 1); + return status; + } + /* Not a signal we recognize? */ if (strcmp (name, "ready")) { if (h -> inner && h -> inner -> type -> signal_handler) @@ -557,6 +634,9 @@ isc_result_t dhcp_failover_link_destroy (omapi_object_t *h, dfree (link -> imsg, file, line); link -> imsg = (failover_message_t *)0; } + if (link -> state_object) + omapi_object_dereference + ((omapi_object_t **)&link -> state_object, MDL); return ISC_R_SUCCESS; } @@ -609,8 +689,9 @@ isc_result_t dhcp_failover_listen (omapi_object_t *h) { isc_result_t status; dhcp_failover_listener_t *obj; - unsigned long port; omapi_value_t *value = (omapi_value_t *)0; + omapi_addr_t local_addr; + unsigned long port; status = omapi_get_value_str (h, (omapi_object_t *)0, "local-port", &value); @@ -625,6 +706,28 @@ isc_result_t dhcp_failover_listen (omapi_object_t *h) omapi_value_dereference (&value, MDL); if (status != ISC_R_SUCCESS) return status; + local_addr.port = port; + + status = omapi_get_value_str (h, (omapi_object_t *)0, + "local-address", &value); + if (status != ISC_R_SUCCESS) + return status; + if (!value -> value) { + nogood: + omapi_value_dereference (&value, MDL); + return ISC_R_INVALIDARG; + } + + if (value -> value -> type != omapi_datatype_data || + value -> value -> u.buffer.len != sizeof (struct in_addr)) + goto nogood; + + memcpy (local_addr.address, value -> value -> u.buffer.value, + value -> value -> u.buffer.len); + local_addr.addrlen = value -> value -> u.buffer.len; + local_addr.addrtype = AF_INET; + + omapi_value_dereference (&value, MDL); obj = (dhcp_failover_listener_t *)dmalloc (sizeof *obj, MDL); if (!obj) @@ -632,10 +735,9 @@ isc_result_t dhcp_failover_listen (omapi_object_t *h) memset (obj, 0, sizeof *obj); obj -> refcnt = 1; obj -> type = dhcp_type_failover_listener; - obj -> local_port = port; + obj -> local_port = local_addr.port; - status = omapi_listen ((omapi_object_t *)obj, port, 1); - omapi_object_dereference ((omapi_object_t **)&obj, MDL); + status = omapi_listen_addr ((omapi_object_t *)obj, &local_addr, 1); if (status != ISC_R_SUCCESS) return status; @@ -651,6 +753,7 @@ isc_result_t dhcp_failover_listen (omapi_object_t *h) return status; } + status = omapi_object_dereference ((omapi_object_t **)&obj, MDL); return status; } @@ -664,7 +767,7 @@ isc_result_t dhcp_failover_listener_signal (omapi_object_t *o, omapi_connection_object_t *c; dhcp_failover_link_t *obj; dhcp_failover_listener_t *p; - dhcp_failover_state_t *state; + dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0; if (!o || o -> type != dhcp_type_failover_listener) return ISC_R_INVALIDARG; @@ -684,22 +787,27 @@ isc_result_t dhcp_failover_listener_signal (omapi_object_t *o, /* See if we can find a secondary failover_state object that matches this connection. */ - for (state = failover_states; state; state = state -> next) { + for (s = failover_states; s; s = s -> next) { int i; struct data_string ds; + /* XXX Really we should accept the connection, check the + XXX authentication, and if it's good, use the server + XXX identifier, rather than looking at the IP source + XXX address, which isn't secure anyway. */ memset (&ds, 0, sizeof ds); if (evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, - state -> address, MDL)) { + s -> address, MDL)) { for (i = 0; i < ds.len; i += 4) { if (!memcmp (&ds.data [i], - &c -> remote_addr, 4)) - break; + &c -> remote_addr.sin_addr, 4)) + state = s; } + data_string_forget (&ds, MDL); } } @@ -708,9 +816,7 @@ isc_result_t dhcp_failover_listener_signal (omapi_object_t *o, if (!state) { /* XXX Send a refusal message first? XXX Look in protocol spec for guidance. */ - /* XXX An error message from a connect signal should - XXX drop the connection - make sure this is what - XXX actually happens! */ + omapi_disconnect (o, 1); return ISC_R_INVALIDARG; } @@ -877,14 +983,136 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, return ISC_R_NOTFOUND; } + /* Handle connect signals by seeing what state we're in + and potentially doing a state transition. */ + if (!strcmp (name, "connect")) { + /* If we already have a link to the peer, it must be + dead, so drop it. + XXX Is this the right thing to do? */ + if (state -> link_to_peer) { + omapi_disconnect ((omapi_object_t *) + state -> link_to_peer, 1); + omapi_object_dereference (&state -> link_to_peer, MDL); + dhcp_failover_state_transition (state, "disconnect"); + } + dhcp_failover_state_transition (state, "connect"); + } + /* Handle all the events we care about... */ return ISC_R_SUCCESS; } +isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state, + const char *name) +{ + /* XXX Check these state transitions against the spec! */ + if (!strcmp (name, "disconnect")) { + switch (state -> my_state) { + case potential_conflict_nic: + case partner_down: + case communications_interrupted: + /* Already in the right state? */ + return ISC_R_SUCCESS; + + case potential_conflict: + return dhcp_failover_set_state + (state, potential_conflict_nic); + + case recover: + case normal: + return dhcp_failover_set_state + (state, communications_interrupted); + + /* XXX ??? */ + case invalid_state: + default: + return dhcp_failover_set_state + (state, potential_conflict_nic); + + return dhcp_failover_set_state + (state, communications_interrupted); + } + } else if (!strcmp (name, "connect")) { + switch (state -> my_state) { + case communications_interrupted: + case partner_down: + return dhcp_failover_set_state (state, recover); + + case recover: + case potential_conflict: + return dhcp_failover_set_state + (state, potential_conflict_nic); + + /* XXX ??? */ + case invalid_state: + default: + return dhcp_failover_set_state (state, + potential_conflict); + case normal: + return dhcp_failover_set_state (state, recover); + } + } else { + } + return ISC_R_INVALIDARG; +} + +isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, + enum failover_state new_state) +{ + /* First make the transition out of the current state. */ + switch (state -> my_state) { + case normal: + case recover: + /* Any updates that haven't been acked yet, we have to + resend, just in case. */ + if (state -> ack_queue_tail) { + if (state -> update_queue_head) { + omapi_object_reference + ((omapi_object_t **) + &state -> ack_queue_tail -> next_pending, + (omapi_object_t *)state -> update_queue_head, + MDL); + omapi_object_dereference ((omapi_object_t **) + &state -> update_queue_head, + MDL); + } + omapi_object_reference ((omapi_object_t **) + &state -> update_queue_head, + (omapi_object_t *)state -> ack_queue_head, + MDL); + if (!state -> update_queue_tail) + omapi_object_reference + ((omapi_object_t **) + &state -> update_queue_tail, + (omapi_object_t *)state -> ack_queue_tail, MDL); + omapi_object_dereference ((omapi_object_t **) + &state -> ack_queue_tail, MDL); + omapi_object_dereference ((omapi_object_t **) + &state -> ack_queue_head, MDL); + state -> cur_unacked_updates = 0; + } + cancel_timeout (dhcp_failover_keepalive, state); + break; + + case partner_down: + case communications_interrupted: + case potential_conflict_nic: + case potential_conflict: + default: + break; + } + + switch (new_state) + { + default: + } + return ISC_R_SUCCESS; +} + isc_result_t dhcp_failover_state_set_value (omapi_object_t *h, - omapi_object_t *id, - omapi_data_string_t *name, - omapi_typed_data_t *value) + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) { if (h -> type != dhcp_type_failover_state) return ISC_R_INVALIDARG; @@ -895,14 +1123,100 @@ isc_result_t dhcp_failover_state_set_value (omapi_object_t *h, return ISC_R_NOTFOUND; } +void dhcp_failover_keepalive (void *vs) +{ + dhcp_failover_state_t *state = vs; +} + isc_result_t dhcp_failover_state_get_value (omapi_object_t *h, - omapi_object_t *id, - omapi_data_string_t *name, - omapi_value_t **value) + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) { + dhcp_failover_state_t *s; + struct option_cache *oc; + struct data_string ds; + isc_result_t status; + if (h -> type != dhcp_type_failover_state) return ISC_R_INVALIDARG; + s = (dhcp_failover_state_t *)h; + if (!omapi_ds_strcmp (name, "name")) { + if (s -> name) + return omapi_make_string_value (value, + name, s -> name, MDL); + return ISC_R_NOTFOUND; + } else if (!omapi_ds_strcmp (name, "partner-address")) { + oc = s -> address; + getaddr: + memset (&ds, 0, sizeof ds); + if (!evaluate_option_cache (&ds, (struct packet *)0, + (struct lease *)0, + (struct option_state *)0, + (struct option_state *)0, + &global_scope, oc, MDL)) { + return ISC_R_NOTFOUND; + } + status = omapi_make_const_value (value, + name, ds.data, ds.len, MDL); + data_string_forget (&ds, MDL); + return status; + } else if (!omapi_ds_strcmp (name, "local-address")) { + oc = s -> server_addr; + goto getaddr; + } else if (!omapi_ds_strcmp (name, "partner-port")) { + return omapi_make_int_value (value, name, s -> port, MDL); + } else if (!omapi_ds_strcmp (name, "local-port")) { + return omapi_make_int_value (value, + name, s -> listen_port, MDL); + } else if (!omapi_ds_strcmp (name, "max-outstanding-updates")) { + return omapi_make_uint_value (value, name, + s -> max_flying_updates, MDL); + } else if (!omapi_ds_strcmp (name, "mclt")) { + return omapi_make_uint_value (value, name, s -> mclt, MDL); + } else if (!omapi_ds_strcmp (name, "load-balance-max-secs")) { + return omapi_make_int_value (value, name, + s -> load_balance_max_secs, MDL); + } else if (!omapi_ds_strcmp (name, "load-balance-hba")) { + if (s -> hba) + return omapi_make_const_value (value, name, + s -> hba, 32, MDL); + return ISC_R_NOTFOUND; + } else if (!omapi_ds_strcmp (name, "partner-state")) { + return omapi_make_uint_value (value, name, + s -> partner_state, MDL); + } else if (!omapi_ds_strcmp (name, "local-state")) { + return omapi_make_uint_value (value, name, + s -> my_state, MDL); + } else if (!omapi_ds_strcmp (name, "partner-stos")) { + return omapi_make_int_value (value, name, + s -> partner_stos, MDL); + } else if (!omapi_ds_strcmp (name, "local-stos")) { + return omapi_make_int_value (value, name, + s -> my_stos, MDL); + } else if (!omapi_ds_strcmp (name, "hierarchy")) { + return omapi_make_uint_value (value, name, s -> i_am, MDL); + } else if (!omapi_ds_strcmp (name, "last-packet-sent")) { + return omapi_make_int_value (value, name, + s -> last_packet_sent, MDL); + } else if (!omapi_ds_strcmp (name, "last-timestamp-received")) { + return omapi_make_int_value (value, name, + s -> last_timestamp_received, + MDL); + } else if (!omapi_ds_strcmp (name, "skew")) { + return omapi_make_int_value (value, name, s -> skew, MDL); + } else if (!omapi_ds_strcmp (name, "max-transmit-idle")) { + return omapi_make_uint_value (value, name, + s -> max_transmit_idle, MDL); + } else if (!omapi_ds_strcmp (name, "max-response-delay")) { + return omapi_make_uint_value (value, name, + s -> max_response_delay, MDL); + } else if (!omapi_ds_strcmp (name, "cur-unacked-updates")) { + return omapi_make_int_value (value, name, + s -> cur_unacked_updates, MDL); + } + if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); @@ -912,8 +1226,20 @@ isc_result_t dhcp_failover_state_get_value (omapi_object_t *h, isc_result_t dhcp_failover_state_destroy (omapi_object_t *h, const char *file, int line) { + dhcp_failover_state_t *s; + if (h -> type != dhcp_type_failover_state) return ISC_R_INVALIDARG; + s = (dhcp_failover_state_t *)h; + if (s -> link_to_peer) + omapi_object_dereference (&s -> link_to_peer, MDL); + if (s -> name) + dfree (s -> name, MDL); + if (s -> address) + option_cache_dereference (&s -> address, MDL); + if (s -> server_addr) + option_cache_dereference (&s -> server_addr, MDL); + return ISC_R_SUCCESS; } @@ -922,16 +1248,231 @@ isc_result_t dhcp_failover_state_destroy (omapi_object_t *h, isc_result_t dhcp_failover_state_stuff (omapi_object_t *c, omapi_object_t *id, - omapi_object_t *p) + omapi_object_t *h) { - int i; + dhcp_failover_state_t *s; + omapi_connection_object_t *conn; + isc_result_t status; - if (p -> type != dhcp_type_failover_state) + if (c -> type != omapi_type_connection) return ISC_R_INVALIDARG; + conn = (omapi_connection_object_t *)c; - if (p -> inner && p -> inner -> type -> stuff_values) - return (*(p -> inner -> type -> stuff_values)) (c, id, - p -> inner); + if (h -> type != dhcp_type_failover_state) + return ISC_R_INVALIDARG; + s = (dhcp_failover_state_t *)h; + + status = omapi_connection_put_name (c, "name"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_string (c, s -> name); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "partner-address"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof s -> address); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_copyin (c, (u_int8_t *)&s -> address, + sizeof s -> address); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "partner-port"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, (u_int32_t)s -> port); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "local-address"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof s -> server_addr); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_copyin (c, (u_int8_t *)&s -> server_addr, + sizeof s -> server_addr); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "local-port"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, (u_int32_t)s -> listen_port); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "max-outstanding-updates"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, s -> max_flying_updates); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "mclt"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, s -> mclt); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "load-balance-max-secs"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_put_uint32 + (c, (u_int32_t)s -> load_balance_max_secs)); + if (status != ISC_R_SUCCESS) + return status; + + + if (s -> hba) { + status = omapi_connection_put_name (c, "load-balance-hba"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, 32); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_copyin (c, s -> hba, 32); + if (status != ISC_R_SUCCESS) + return status; + } + + status = omapi_connection_put_name (c, "partner-state"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, s -> partner_state); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "local-state"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, s -> my_state); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "partner-stos"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, (u_int32_t)s -> partner_stos); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "local-stos"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, (u_int32_t)s -> my_stos); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "hierarchy"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, s -> i_am); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "last-packet-sent"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_put_uint32 + (c, (u_int32_t)s -> last_packet_sent)); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "last-timestamp-received"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_put_uint32 + (c, (u_int32_t)s -> last_timestamp_received)); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "skew"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, (u_int32_t)s -> skew); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "max-transmit-idle"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_put_uint32 + (c, (u_int32_t)s -> max_transmit_idle)); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "max-response-delay"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_put_uint32 + (c, (u_int32_t)s -> max_response_delay)); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "cur-unacked-updates"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_put_uint32 + (c, (u_int32_t)s -> cur_unacked_updates)); + if (status != ISC_R_SUCCESS) + return status; + + if (h -> inner && h -> inner -> type -> stuff_values) + return (*(h -> inner -> type -> stuff_values)) (c, id, + h -> inner); return ISC_R_SUCCESS; } @@ -1014,7 +1555,8 @@ failover_option_t *dhcp_failover_make_option (unsigned code, int i; unsigned size, count; unsigned val; - struct iaddr *ival; + u_int8_t *iaddr; + unsigned ilen; u_int8_t *bval; char *fmt; #if defined (DEBUG_FAILOVER_MESSAGES) @@ -1118,19 +1660,21 @@ failover_option_t *dhcp_failover_make_option (unsigned code, case FT_IPADDR: for (i = 0; i < count; i++) { - ival = va_arg (va, struct iaddr *); - if (ival -> len != 4) { + ilen = va_arg (va, unsigned); + iaddr = va_arg (va, u_int8_t *); + if (ilen != 4) { dfree (option.data, MDL); log_error ("IP addrlen=%d, should be 4.", - ival -> len); + ilen); return &null_failover_option; } #if defined (DEBUG_FAILOVER_MESSAGES) - sprintf (tbuf, " %s", piaddr (*ival)); + sprintf (tbuf, " %u.%u.%u.%u", iaddr [0], iaddr [1], + iaddr [2], iaddr [3]); failover_print (obuf, obufix, obufmax, tbuf); #endif - memcpy (&option.data [4 + i * 4], ival -> iabuf, 4); + memcpy (&option.data [4 + i * 4], iaddr, ilen); } break; @@ -1259,9 +1803,12 @@ isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *link, if (!bad_option && opbuf) memcpy (&opbuf [opix], option -> data, option -> count); - opix += option -> count; - dfree (option -> data, MDL); - dfree (option, MDL); + if (option != &null_failover_option && + option != &skip_failover_option) { + opix += option -> count; + dfree (option -> data, MDL); + dfree (option, MDL); + } } if (bad_option || !opbuf) @@ -1339,7 +1886,7 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l) (link, l -> outer, FTM_CONNECT, dhcp_failover_make_option (FTO_SERVER_ADDR, FMA, - &state -> server_addr), + 4, &state -> server_addr), dhcp_failover_make_option (FTO_MAX_UNACKED, FMA, state -> max_flying_updates), dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA, @@ -1401,6 +1948,7 @@ isc_result_t dhcp_failover_update_peer (struct lease *lease, int releasep) (link, link -> outer, FTM_BNDUPD, dhcp_failover_make_option (FTO_ASSIGNED_IP_ADDRESS, FMA, + lease -> ip_addr.len, lease -> ip_addr.iabuf), dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, 0 /* ??? */), @@ -1464,4 +2012,74 @@ void failover_print (char *obuf, void update_partner (struct lease *lease) { } + +/* Taken from draft-ietf-dhc-loadb-01.txt: */ +/* A "mixing table" of 256 distinct values, in pseudo-random order. */ +unsigned char loadb_mx_tbl[256] = { + 251, 175, 119, 215, 81, 14, 79, 191, 103, 49, + 181, 143, 186, 157, 0, 232, 31, 32, 55, 60, + 152, 58, 17, 237, 174, 70, 160, 144, 220, 90, + 57, 223, 59, 3, 18, 140, 111, 166, 203, 196, + 134, 243, 124, 95, 222, 179, 197, 65, 180, 48, + 36, 15, 107, 46, 233, 130, 165, 30, 123, 161, + 209, 23, 97, 16, 40, 91, 219, 61, 100, 10, + 210, 109, 250, 127, 22, 138, 29, 108, 244, 67, + 207, 9, 178, 204, 74, 98, 126, 249, 167, 116, + 34, 77, 193, 200, 121, 5, 20, 113, 71, 35, + 128, 13, 182, 94, 25, 226, 227, 199, 75, 27, + 41, 245, 230, 224, 43, 225, 177, 26, 155, 150, + 212, 142, 218, 115, 241, 73, 88, 105, 39, 114, + 62, 255, 192, 201, 145, 214, 168, 158, 221, 148, + 154, 122, 12, 84, 82, 163, 44, 139, 228, 236, + 205, 242, 217, 11, 187, 146, 159, 64, 86, 239, + 195, 42, 106, 198, 118, 112, 184, 172, 87, 2, + 173, 117, 176, 229, 247, 253, 137, 185, 99, 164, + 102, 147, 45, 66, 231, 52, 141, 211, 194, 206, + 246, 238, 56, 110, 78, 248, 63, 240, 189, 93, + 92, 51, 53, 183, 19, 171, 72, 50, 33, 104, + 101, 69, 8, 252, 83, 120, 76, 135, 85, 54, + 202, 125, 188, 213, 96, 235, 136, 208, 162, 129, + 190, 132, 156, 38, 47, 1, 7, 254, 24, 4, + 216, 131, 89, 21, 28, 133, 37, 153, 149, 80, + 170, 68, 6, 169, 234, 151 }; + +static unsigned char loadb_p_hash (const unsigned char *, unsigned); +static unsigned char loadb_p_hash (const unsigned char *key, unsigned len) +{ + unsigned char hash = len; + int i; + for(i = len; i > 0; ) + hash = loadb_mx_tbl [hash ^ (key [--i])]; + return hash; +} + +int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state) +{ + struct option_cache *oc; + struct data_string ds; + unsigned char hbaix; + int hm; + + if (state -> load_balance_max_secs < ntohs (packet -> raw -> secs)) { + return 1; + } + + oc = lookup_option (&dhcp_universe, packet -> options, + DHO_DHCP_CLIENT_IDENTIFIER); + memset (&ds, 0, sizeof ds); + if (oc && + evaluate_option_cache (&ds, packet, (struct lease *)0, + packet -> options, (struct option_state *)0, + &global_scope, oc, MDL)) { + hbaix = loadb_p_hash (ds.data, ds.len); + } else { + hbaix = loadb_p_hash (packet -> raw -> chaddr, + packet -> raw -> hlen); + } + hm = (state -> hba [hbaix / 8] & (1 << (hbaix & 3))); + if (state -> i_am == primary) + return hm; + else + return !hm; +} #endif /* defined (FAILOVER_PROTOCOL) */