00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "cdefs.h"
00030 #include "dhcpd.h"
00031 #include <omapip/omapip_p.h>
00032
00033 #include "trace.h"
00034
00035 #if defined (FAILOVER_PROTOCOL)
00036 dhcp_failover_state_t *failover_states;
00037 static isc_result_t do_a_failover_option (omapi_object_t *,
00038 dhcp_failover_link_t *);
00039 dhcp_failover_listener_t *failover_listeners;
00040
00041 static isc_result_t failover_message_reference (failover_message_t **,
00042 failover_message_t *,
00043 const char *file, int line);
00044 static isc_result_t failover_message_dereference (failover_message_t **,
00045 const char *file, int line);
00046
00047 static void dhcp_failover_pool_balance(dhcp_failover_state_t *state);
00048 static void dhcp_failover_pool_reqbalance(dhcp_failover_state_t *state);
00049 static int dhcp_failover_pool_dobalance(dhcp_failover_state_t *state,
00050 isc_boolean_t *sendreq);
00051 static inline int secondary_not_hoarding(dhcp_failover_state_t *state,
00052 struct pool *p);
00053
00054
00055 void dhcp_failover_startup ()
00056 {
00057 dhcp_failover_state_t *state;
00058 isc_result_t status;
00059 struct timeval tv;
00060
00061 for (state = failover_states; state; state = state -> next) {
00062 dhcp_failover_state_transition (state, "startup");
00063
00064 if (state -> pool_count == 0) {
00065 log_error ("failover peer declaration with no %s",
00066 "referring pools.");
00067 log_error ("In order to use failover, you MUST %s",
00068 "refer to your main failover declaration");
00069 log_error ("in each pool declaration. You MUST %s",
00070 "NOT use range declarations outside");
00071 log_fatal ("of pool declarations.");
00072 }
00073
00074
00075 status = dhcp_failover_link_initiate ((omapi_object_t *)state);
00076 if (status != ISC_R_SUCCESS && status != DHCP_R_INCOMPLETE) {
00077 #if defined (DEBUG_FAILOVER_TIMING)
00078 log_info ("add_timeout +90 dhcp_failover_reconnect");
00079 #endif
00080 tv . tv_sec = cur_time + 90;
00081 tv . tv_usec = 0;
00082 add_timeout (&tv,
00083 dhcp_failover_reconnect, state,
00084 (tvref_t)
00085 dhcp_failover_state_reference,
00086 (tvunref_t)
00087 dhcp_failover_state_dereference);
00088 log_error ("failover peer %s: %s", state -> name,
00089 isc_result_totext (status));
00090 }
00091
00092 status = (dhcp_failover_listen
00093 ((omapi_object_t *)state));
00094 if (status != ISC_R_SUCCESS) {
00095 #if defined (DEBUG_FAILOVER_TIMING)
00096 log_info ("add_timeout +90 %s",
00097 "dhcp_failover_listener_restart");
00098 #endif
00099 tv . tv_sec = cur_time + 90;
00100 tv . tv_usec = 0;
00101 add_timeout (&tv,
00102 dhcp_failover_listener_restart,
00103 state,
00104 (tvref_t)omapi_object_reference,
00105 (tvunref_t)omapi_object_dereference);
00106 }
00107 }
00108 }
00109
00110 int dhcp_failover_write_all_states ()
00111 {
00112 dhcp_failover_state_t *state;
00113
00114 for (state = failover_states; state; state = state -> next) {
00115 if (!write_failover_state (state))
00116 return 0;
00117 }
00118 return 1;
00119 }
00120
00121 isc_result_t enter_failover_peer (peer)
00122 dhcp_failover_state_t *peer;
00123 {
00124 dhcp_failover_state_t *dup = (dhcp_failover_state_t *)0;
00125 isc_result_t status;
00126
00127 status = find_failover_peer (&dup, peer -> name, MDL);
00128 if (status == ISC_R_NOTFOUND) {
00129 if (failover_states) {
00130 dhcp_failover_state_reference (&peer -> next,
00131 failover_states, MDL);
00132 dhcp_failover_state_dereference (&failover_states,
00133 MDL);
00134 }
00135 dhcp_failover_state_reference (&failover_states, peer, MDL);
00136 return ISC_R_SUCCESS;
00137 }
00138 dhcp_failover_state_dereference (&dup, MDL);
00139 if (status == ISC_R_SUCCESS)
00140 return ISC_R_EXISTS;
00141 return status;
00142 }
00143
00144 isc_result_t find_failover_peer (peer, name, file, line)
00145 dhcp_failover_state_t **peer;
00146 const char *name;
00147 const char *file;
00148 int line;
00149 {
00150 dhcp_failover_state_t *p;
00151
00152 for (p = failover_states; p; p = p -> next)
00153 if (!strcmp (name, p -> name))
00154 break;
00155 if (p)
00156 return dhcp_failover_state_reference (peer, p, file, line);
00157 return ISC_R_NOTFOUND;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 isc_result_t dhcp_failover_link_initiate (omapi_object_t *h)
00177 {
00178 isc_result_t status;
00179 dhcp_failover_link_t *obj;
00180 dhcp_failover_state_t *state;
00181 omapi_object_t *o;
00182 int i;
00183 struct data_string ds;
00184 omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
00185 omapi_addr_t local_addr;
00186
00187
00188 for (o = h; o -> outer; o = o -> outer)
00189 ;
00190 for (; o; o = o -> inner) {
00191 if (o -> type == dhcp_type_failover_state)
00192 break;
00193 }
00194 if (!o)
00195 return DHCP_R_INVALIDARG;
00196 state = (dhcp_failover_state_t *)o;
00197
00198 obj = (dhcp_failover_link_t *)0;
00199 status = dhcp_failover_link_allocate (&obj, MDL);
00200 if (status != ISC_R_SUCCESS)
00201 return status;
00202 option_cache_reference (&obj -> peer_address,
00203 state -> partner.address, MDL);
00204 obj -> peer_port = state -> partner.port;
00205 dhcp_failover_state_reference (&obj -> state_object, state, MDL);
00206
00207 memset (&ds, 0, sizeof ds);
00208 if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
00209 (struct client_state *)0,
00210 (struct option_state *)0,
00211 (struct option_state *)0,
00212 &global_scope, obj -> peer_address, MDL)) {
00213 dhcp_failover_link_dereference (&obj, MDL);
00214 return ISC_R_UNEXPECTED;
00215 }
00216
00217
00218
00219 status = omapi_addr_list_new (&addrs, ds.len / 4, MDL);
00220 if (status != ISC_R_SUCCESS) {
00221 dhcp_failover_link_dereference (&obj, MDL);
00222 return status;
00223 }
00224
00225 for (i = 0; i < addrs -> count; i++) {
00226 addrs -> addresses [i].addrtype = AF_INET;
00227 addrs -> addresses [i].addrlen = sizeof (struct in_addr);
00228 memcpy (addrs -> addresses [i].address,
00229 &ds.data [i * 4], sizeof (struct in_addr));
00230 addrs -> addresses [i].port = obj -> peer_port;
00231 }
00232 data_string_forget (&ds, MDL);
00233
00234
00235 if (!state -> me.address ||
00236 !evaluate_option_cache (&ds, (struct packet *)0,
00237 (struct lease *)0,
00238 (struct client_state *)0,
00239 (struct option_state *)0,
00240 (struct option_state *)0,
00241 &global_scope, state -> me.address,
00242 MDL)) {
00243 memset (&local_addr, 0, sizeof local_addr);
00244 local_addr.addrtype = AF_INET;
00245 local_addr.addrlen = sizeof (struct in_addr);
00246 if (!state -> server_identifier.len) {
00247 log_fatal ("failover peer %s: no local address.",
00248 state -> name);
00249 }
00250 } else {
00251 if (ds.len != sizeof (struct in_addr)) {
00252 log_error("failover peer %s: 'address' parameter "
00253 "fails to resolve to an IPv4 address",
00254 state->name);
00255 data_string_forget (&ds, MDL);
00256 dhcp_failover_link_dereference (&obj, MDL);
00257 omapi_addr_list_dereference (&addrs, MDL);
00258 return DHCP_R_INVALIDARG;
00259 }
00260 local_addr.addrtype = AF_INET;
00261 local_addr.addrlen = ds.len;
00262 memcpy (local_addr.address, ds.data, ds.len);
00263 if (!state -> server_identifier.len)
00264 data_string_copy (&state -> server_identifier,
00265 &ds, MDL);
00266 data_string_forget (&ds, MDL);
00267 local_addr.port = 0;
00268 }
00269
00270 status = omapi_connect_list ((omapi_object_t *)obj,
00271 addrs, &local_addr);
00272 omapi_addr_list_dereference (&addrs, MDL);
00273
00274 dhcp_failover_link_dereference (&obj, MDL);
00275 return status;
00276 }
00277
00278 isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
00279 const char *name, va_list ap)
00280 {
00281 isc_result_t status;
00282 dhcp_failover_link_t *link;
00283 omapi_object_t *c;
00284 dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0;
00285 char *sname;
00286 int slen;
00287 struct timeval tv;
00288
00289 if (h -> type != dhcp_type_failover_link) {
00290
00291 return ISC_R_UNEXPECTED;
00292 }
00293 link = (dhcp_failover_link_t *)h;
00294
00295 if (!strcmp (name, "connect")) {
00296 if (link -> state_object -> i_am == primary) {
00297 status = dhcp_failover_send_connect (h);
00298 if (status != ISC_R_SUCCESS) {
00299 log_info ("dhcp_failover_send_connect: %s",
00300 isc_result_totext (status));
00301 omapi_disconnect (h -> outer, 1);
00302 }
00303 } else
00304 status = ISC_R_SUCCESS;
00305
00306
00307 #if defined (DEBUG_FAILOVER_TIMING)
00308 log_info ("add_timeout +15 %s",
00309 "dhcp_failover_link_startup_timeout");
00310 #endif
00311 tv . tv_sec = cur_time + 15;
00312 tv . tv_usec = 0;
00313 add_timeout (&tv,
00314 dhcp_failover_link_startup_timeout,
00315 link,
00316 (tvref_t)dhcp_failover_link_reference,
00317 (tvunref_t)dhcp_failover_link_dereference);
00318 return status;
00319 }
00320
00321 if (!strcmp (name, "disconnect")) {
00322 if (link -> state_object) {
00323 dhcp_failover_state_reference (&state,
00324 link -> state_object, MDL);
00325 link -> state = dhcp_flink_disconnected;
00326
00327
00328 if (state->link_to_peer == link)
00329 dhcp_failover_state_transition(link->state_object, name);
00330
00331
00332 #if defined (DEBUG_FAILOVER_TIMING)
00333 log_info("add_timeout +5 dhcp_failover_reconnect");
00334 #endif
00335 tv.tv_sec = cur_time + 5;
00336 tv.tv_usec = cur_tv.tv_usec;
00337 add_timeout(&tv, dhcp_failover_reconnect, state,
00338 (tvref_t)dhcp_failover_state_reference,
00339 (tvunref_t)dhcp_failover_state_dereference);
00340
00341 dhcp_failover_state_dereference (&state, MDL);
00342 }
00343 return ISC_R_SUCCESS;
00344 }
00345
00346 if (!strcmp (name, "status")) {
00347 if (link -> state_object) {
00348 isc_result_t status;
00349
00350 status = va_arg(ap, isc_result_t);
00351
00352 if ((status == ISC_R_HOSTUNREACH) || (status == ISC_R_TIMEDOUT)) {
00353 dhcp_failover_state_reference (&state,
00354 link -> state_object, MDL);
00355 link -> state = dhcp_flink_disconnected;
00356
00357
00358 dhcp_failover_state_transition (link -> state_object,
00359 "disconnect");
00360
00361
00362 #if defined (DEBUG_FAILOVER_TIMING)
00363 log_info ("add_timeout +5 %s",
00364 "dhcp_failover_reconnect");
00365 #endif
00366 tv . tv_sec = cur_time + 5;
00367 tv . tv_usec = 0;
00368 add_timeout (&tv, dhcp_failover_reconnect,
00369 state,
00370 (tvref_t)dhcp_failover_state_reference,
00371 (tvunref_t)dhcp_failover_state_dereference);
00372 }
00373 dhcp_failover_state_dereference (&state, MDL);
00374 }
00375 return ISC_R_SUCCESS;
00376 }
00377
00378
00379 if (strcmp (name, "ready")) {
00380 if (h -> inner && h -> inner -> type -> signal_handler)
00381 return (*(h -> inner -> type -> signal_handler))
00382 (h -> inner, name, ap);
00383 return ISC_R_NOTFOUND;
00384 }
00385
00386 if (!h -> outer || h -> outer -> type != omapi_type_connection)
00387 return DHCP_R_INVALIDARG;
00388 c = h -> outer;
00389
00390
00391
00392
00393 switch (link -> state) {
00394 case dhcp_flink_start:
00395 link -> state = dhcp_flink_message_length_wait;
00396 if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
00397 break;
00398 case dhcp_flink_message_length_wait:
00399 next_message:
00400 link -> state = dhcp_flink_message_wait;
00401 link -> imsg = dmalloc (sizeof (failover_message_t), MDL);
00402 if (!link -> imsg) {
00403 status = ISC_R_NOMEMORY;
00404 dhcp_flink_fail:
00405 if (link -> imsg) {
00406 failover_message_dereference (&link->imsg,
00407 MDL);
00408 }
00409 link -> state = dhcp_flink_disconnected;
00410 log_info ("message length wait: %s",
00411 isc_result_totext (status));
00412 omapi_disconnect (c, 1);
00413
00414
00415 return ISC_R_UNEXPECTED;
00416 }
00417 memset (link -> imsg, 0, sizeof (failover_message_t));
00418 link -> imsg -> refcnt = 1;
00419
00420 omapi_connection_get_uint16 (c, &link -> imsg_len);
00421 link -> imsg_count = 0;
00422
00423
00424 if (link->imsg_len < DHCP_FAILOVER_MIN_MESSAGE_SIZE ||
00425 link->imsg_len > DHCP_FAILOVER_MAX_MESSAGE_SIZE) {
00426 status = ISC_R_UNEXPECTED;
00427 goto dhcp_flink_fail;
00428 }
00429
00430 if ((omapi_connection_require (c, link -> imsg_len - 2U)) !=
00431 ISC_R_SUCCESS)
00432 break;
00433 case dhcp_flink_message_wait:
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 link -> imsg_count += 2;
00444
00445
00446 omapi_connection_copyout (&link -> imsg -> type, c, 1);
00447 link -> imsg_count++;
00448
00449
00450 omapi_connection_copyout (&link -> imsg_payoff, c, 1);
00451 link -> imsg_count++;
00452
00453
00454 omapi_connection_get_uint32 (c, &link -> imsg -> time);
00455 link -> imsg_count += 4;
00456
00457
00458 omapi_connection_get_uint32 (c, &link -> imsg -> xid);
00459 link -> imsg_count += 4;
00460
00461 #if defined (DEBUG_FAILOVER_MESSAGES)
00462 # if !defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
00463 if (link->imsg->type == FTM_CONTACT)
00464 goto skip_contact;
00465 # endif
00466 log_info ("link: message %s payoff %d time %ld xid %ld",
00467 dhcp_failover_message_name (link -> imsg -> type),
00468 link -> imsg_payoff,
00469 (unsigned long)link -> imsg -> time,
00470 (unsigned long)link -> imsg -> xid);
00471 # if !defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
00472 skip_contact:
00473 # endif
00474 #endif
00475
00476
00477 if (link -> imsg_payoff - link -> imsg_count) {
00478 omapi_connection_copyout ((unsigned char *)0, c,
00479 (link -> imsg_payoff -
00480 link -> imsg_count));
00481 link -> imsg_count = link -> imsg_payoff;
00482 }
00483
00484
00485 while (link -> imsg_count < link -> imsg_len) {
00486 status = do_a_failover_option (c, link);
00487 if (status != ISC_R_SUCCESS)
00488 goto dhcp_flink_fail;
00489 }
00490
00491
00492
00493
00494 if (link -> imsg -> type == FTM_CONNECT) {
00495 const char *errmsg;
00496 int reason;
00497
00498 if (!(link->imsg->options_present &
00499 FTB_RELATIONSHIP_NAME)) {
00500 errmsg = "missing relationship-name";
00501 reason = FTR_INVALID_PARTNER;
00502 goto badconnect;
00503 }
00504
00505
00506
00507
00508 for (s = failover_states; s; s = s -> next) {
00509 if (dhcp_failover_state_match_by_name(s,
00510 &link->imsg->relationship_name))
00511 state = s;
00512 }
00513
00514
00515
00516 if (!state) {
00517 errmsg = "unknown failover relationship name";
00518 reason = FTR_INVALID_PARTNER;
00519
00520 badconnect:
00521
00522
00523
00524 if (state != NULL) {
00525 sname = state->name;
00526 slen = strlen(sname);
00527 } else if (link->imsg->options_present &
00528 FTB_RELATIONSHIP_NAME) {
00529 sname = (char *)link->imsg->
00530 relationship_name.data;
00531 slen = link->imsg->relationship_name.count;
00532 } else {
00533 sname = "unknown";
00534 slen = strlen(sname);
00535 }
00536
00537 log_error("Failover CONNECT from %.*s: %s",
00538 slen, sname, errmsg);
00539 dhcp_failover_send_connectack
00540 ((omapi_object_t *)link, state,
00541 reason, errmsg);
00542 log_info ("failover: disconnect: %s", errmsg);
00543 omapi_disconnect (c, 0);
00544 link -> state = dhcp_flink_disconnected;
00545 return ISC_R_SUCCESS;
00546 }
00547
00548 if ((cur_time > link -> imsg -> time &&
00549 cur_time - link -> imsg -> time > 60) ||
00550 (cur_time < link -> imsg -> time &&
00551 link -> imsg -> time - cur_time > 60)) {
00552 errmsg = "time offset too large";
00553 reason = FTR_TIMEMISMATCH;
00554 goto badconnect;
00555 }
00556
00557 if (!(link -> imsg -> options_present & FTB_HBA) ||
00558 link -> imsg -> hba.count != 32) {
00559 errmsg = "invalid HBA";
00560 reason = FTR_HBA_CONFLICT;
00561 goto badconnect;
00562 }
00563 if (state -> hba)
00564 dfree (state -> hba, MDL);
00565 state -> hba = dmalloc (32, MDL);
00566 if (!state -> hba) {
00567 errmsg = "no memory";
00568 reason = FTR_MISC_REJECT;
00569 goto badconnect;
00570 }
00571 memcpy (state -> hba, link -> imsg -> hba.data, 32);
00572
00573 if (!link -> state_object)
00574 dhcp_failover_state_reference
00575 (&link -> state_object, state, MDL);
00576 if (!link -> peer_address)
00577 option_cache_reference
00578 (&link -> peer_address,
00579 state -> partner.address, MDL);
00580 }
00581
00582
00583
00584
00585 if (!link -> state_object) {
00586 log_info ("failover: connect: no matching state.");
00587 omapi_disconnect (c, 1);
00588 link -> state = dhcp_flink_disconnected;
00589 return DHCP_R_INVALIDARG;
00590 }
00591
00592
00593
00594 omapi_signal ((omapi_object_t *)link -> state_object,
00595 "message", link);
00596 link -> state = dhcp_flink_message_length_wait;
00597 if (link -> imsg)
00598 failover_message_dereference (&link -> imsg, MDL);
00599
00600
00601
00602
00603
00604 if ((omapi_connection_require (c, 2)) == ISC_R_SUCCESS)
00605 goto next_message;
00606 break;
00607
00608 default:
00609 log_fatal("Impossible case at %s:%d.", MDL);
00610 break;
00611 }
00612 return ISC_R_SUCCESS;
00613 }
00614
00615 static isc_result_t do_a_failover_option (c, link)
00616 omapi_object_t *c;
00617 dhcp_failover_link_t *link;
00618 {
00619 u_int16_t option_code;
00620 u_int16_t option_len;
00621 unsigned char *op;
00622 unsigned op_size;
00623 unsigned op_count;
00624 int i;
00625
00626 if (link -> imsg_count + 2 > link -> imsg_len) {
00627 log_error ("FAILOVER: message overflow at option code.");
00628 return DHCP_R_PROTOCOLERROR;
00629 }
00630
00631
00632 omapi_connection_get_uint16 (c, &option_code);
00633 link -> imsg_count += 2;
00634
00635 if (link -> imsg_count + 2 > link -> imsg_len) {
00636 log_error ("FAILOVER: message overflow at length.");
00637 return DHCP_R_PROTOCOLERROR;
00638 }
00639
00640
00641 omapi_connection_get_uint16 (c, &option_len);
00642 link -> imsg_count += 2;
00643
00644 if (link -> imsg_count + option_len > link -> imsg_len) {
00645 log_error ("FAILOVER: message overflow at data.");
00646 return DHCP_R_PROTOCOLERROR;
00647 }
00648
00649
00650 if ((option_code > FTO_MAX) ||
00651 (ft_options[option_code].type == FT_UNDEF)) {
00652 #if defined (DEBUG_FAILOVER_MESSAGES)
00653 log_debug (" option code %d (%s) len %d (not recognized)",
00654 option_code,
00655 dhcp_failover_option_name (option_code),
00656 option_len);
00657 #endif
00658 omapi_connection_copyout ((unsigned char *)0, c, option_len);
00659 link -> imsg_count += option_len;
00660 return ISC_R_SUCCESS;
00661 }
00662
00663
00664 if (ft_options [option_code].type == FT_DIGEST) {
00665 link -> imsg_count += option_len;
00666 if (link -> imsg_count != link -> imsg_len) {
00667 log_error ("FAILOVER: digest not at end of message");
00668 return DHCP_R_PROTOCOLERROR;
00669 }
00670 #if defined (DEBUG_FAILOVER_MESSAGES)
00671 log_debug (" option %s len %d",
00672 ft_options [option_code].name, option_len);
00673 #endif
00674
00675 omapi_connection_copyout ((unsigned char *)0, c, option_len);
00676 return ISC_R_SUCCESS;
00677 }
00678
00679
00680 if (link -> imsg -> options_present & ft_options [option_code].bit) {
00681 log_error ("FAILOVER: duplicate option %s",
00682 ft_options [option_code].name);
00683 return DHCP_R_PROTOCOLERROR;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692 if (ft_options [option_code].bit &&
00693 !(fto_allowed [link -> imsg -> type] &
00694 ft_options [option_code].bit)) {
00695 omapi_connection_copyout ((unsigned char *)0, c, option_len);
00696 link -> imsg_count += option_len;
00697 return ISC_R_SUCCESS;
00698 }
00699
00700
00701
00702 if (ft_options [option_code].num_present) {
00703
00704
00705
00706
00707 op = ((unsigned char *)link -> imsg) +
00708 ft_options [option_code].offset;
00709 op_size = ft_sizes [ft_options [option_code].type];
00710 op_count = ft_options [option_code].num_present;
00711
00712 if (option_len != op_size * op_count) {
00713 log_error ("FAILOVER: option size (%d:%d), option %s",
00714 option_len,
00715 (ft_sizes [ft_options [option_code].type] *
00716 ft_options [option_code].num_present),
00717 ft_options [option_code].name);
00718 return DHCP_R_PROTOCOLERROR;
00719 }
00720 } else {
00721 failover_option_t *fo;
00722
00723
00724
00725 if (ft_options [option_code].type == FT_DDNS1 ||
00726 ft_options [option_code].type == FT_DDNS1) {
00727 ddns_fqdn_t *ddns =
00728 ((ddns_fqdn_t *)
00729 (((char *)link -> imsg) +
00730 ft_options [option_code].offset));
00731
00732 op_count = (ft_options [option_code].type == FT_DDNS1
00733 ? 1 : 2);
00734
00735 omapi_connection_copyout (&ddns -> codes [0],
00736 c, op_count);
00737 link -> imsg_count += op_count;
00738 if (op_count == 1)
00739 ddns -> codes [1] = 0;
00740 op_size = 1;
00741 op_count = option_len - op_count;
00742
00743 ddns -> length = op_count;
00744 ddns -> data = dmalloc (op_count, MDL);
00745 if (!ddns -> data) {
00746 log_error ("FAILOVER: no memory getting%s(%d)",
00747 " DNS data ", op_count);
00748
00749
00750
00751 return DHCP_R_PROTOCOLERROR;
00752 }
00753 omapi_connection_copyout (ddns -> data, c, op_count);
00754 goto out;
00755 }
00756
00757
00758
00759
00760
00761
00762 op_size = ft_sizes [ft_options [option_code].type];
00763
00764
00765
00766 if (op_size > 1 && option_len % op_size) {
00767 log_error ("FAILOVER: option_len %d not %s%d",
00768 option_len, "multiple of ", op_size);
00769 return DHCP_R_PROTOCOLERROR;
00770 }
00771
00772 op_count = option_len / op_size;
00773
00774 fo = ((failover_option_t *)
00775 (((char *)link -> imsg) +
00776 ft_options [option_code].offset));
00777
00778 fo -> count = op_count;
00779 fo -> data = dmalloc (option_len, MDL);
00780 if (!fo -> data) {
00781 log_error ("FAILOVER: no memory getting %s (%d)",
00782 "option data", op_count);
00783
00784 return DHCP_R_PROTOCOLERROR;
00785 }
00786 op = fo -> data;
00787 }
00788
00789
00790
00791 if (op_size == 1 || ft_options [option_code].type == FT_IPADDR) {
00792 omapi_connection_copyout ((unsigned char *)op, c, option_len);
00793 link -> imsg_count += option_len;
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816 if ((option_code == 11) && (option_len > 9) &&
00817 (strncmp((const char *)op, "isc-V3.0.", 9) == 0)) {
00818 log_error("WARNING: failover as of versions 3.1.0 and "
00819 "on are not reverse compatible with "
00820 "versions 3.0.x.");
00821 }
00822
00823 goto out;
00824 }
00825
00826
00827
00828 for (i = 0; i < op_count; i++) {
00829 switch (ft_options [option_code].type) {
00830 case FT_UINT32:
00831 omapi_connection_get_uint32 (c, (u_int32_t *)op);
00832 op += 4;
00833 link -> imsg_count += 4;
00834 break;
00835
00836 case FT_UINT16:
00837 omapi_connection_get_uint16 (c, (u_int16_t *)op);
00838 op += 2;
00839 link -> imsg_count += 2;
00840 break;
00841
00842 default:
00843
00844
00845 log_error ("FAILOVER: option %s: bad type %d",
00846 ft_options [option_code].name,
00847 ft_options [option_code].type);
00848 return DHCP_R_PROTOCOLERROR;
00849 }
00850 }
00851 out:
00852
00853 link -> imsg -> options_present |= ft_options [option_code].bit;
00854 return ISC_R_SUCCESS;
00855 }
00856
00857 isc_result_t dhcp_failover_link_set_value (omapi_object_t *h,
00858 omapi_object_t *id,
00859 omapi_data_string_t *name,
00860 omapi_typed_data_t *value)
00861 {
00862 if (h -> type != omapi_type_protocol)
00863 return DHCP_R_INVALIDARG;
00864
00865
00866 if (!omapi_ds_strcmp (name, "link-port") ||
00867 !omapi_ds_strcmp (name, "link-name") ||
00868 !omapi_ds_strcmp (name, "link-state"))
00869 return ISC_R_NOPERM;
00870
00871 if (h -> inner && h -> inner -> type -> set_value)
00872 return (*(h -> inner -> type -> set_value))
00873 (h -> inner, id, name, value);
00874 return ISC_R_NOTFOUND;
00875 }
00876
00877 isc_result_t dhcp_failover_link_get_value (omapi_object_t *h,
00878 omapi_object_t *id,
00879 omapi_data_string_t *name,
00880 omapi_value_t **value)
00881 {
00882 dhcp_failover_link_t *link;
00883
00884 if (h -> type != omapi_type_protocol)
00885 return DHCP_R_INVALIDARG;
00886 link = (dhcp_failover_link_t *)h;
00887
00888 if (!omapi_ds_strcmp (name, "link-port")) {
00889 return omapi_make_int_value (value, name,
00890 (int)link -> peer_port, MDL);
00891 } else if (!omapi_ds_strcmp (name, "link-state")) {
00892 if (link -> state >= dhcp_flink_state_max)
00893 return omapi_make_string_value (value, name,
00894 "invalid link state",
00895 MDL);
00896 return omapi_make_string_value
00897 (value, name,
00898 dhcp_flink_state_names [link -> state], MDL);
00899 }
00900
00901 if (h -> inner && h -> inner -> type -> get_value)
00902 return (*(h -> inner -> type -> get_value))
00903 (h -> inner, id, name, value);
00904 return ISC_R_NOTFOUND;
00905 }
00906
00907 isc_result_t dhcp_failover_link_destroy (omapi_object_t *h,
00908 const char *file, int line)
00909 {
00910 dhcp_failover_link_t *link;
00911 if (h -> type != dhcp_type_failover_link)
00912 return DHCP_R_INVALIDARG;
00913 link = (dhcp_failover_link_t *)h;
00914
00915 if (link -> peer_address)
00916 option_cache_dereference (&link -> peer_address, file, line);
00917 if (link -> imsg)
00918 failover_message_dereference (&link -> imsg, file, line);
00919 if (link -> state_object)
00920 dhcp_failover_state_dereference (&link -> state_object,
00921 file, line);
00922 return ISC_R_SUCCESS;
00923 }
00924
00925
00926
00927
00928 isc_result_t dhcp_failover_link_stuff_values (omapi_object_t *c,
00929 omapi_object_t *id,
00930 omapi_object_t *l)
00931 {
00932 dhcp_failover_link_t *link;
00933 isc_result_t status;
00934
00935 if (l -> type != dhcp_type_failover_link)
00936 return DHCP_R_INVALIDARG;
00937 link = (dhcp_failover_link_t *)l;
00938
00939 status = omapi_connection_put_name (c, "link-port");
00940 if (status != ISC_R_SUCCESS)
00941 return status;
00942 status = omapi_connection_put_uint32 (c, sizeof (int));
00943 if (status != ISC_R_SUCCESS)
00944 return status;
00945 status = omapi_connection_put_uint32 (c, link -> peer_port);
00946 if (status != ISC_R_SUCCESS)
00947 return status;
00948
00949 status = omapi_connection_put_name (c, "link-state");
00950 if (status != ISC_R_SUCCESS)
00951 return status;
00952 if (link -> state >= dhcp_flink_state_max)
00953 status = omapi_connection_put_string (c, "invalid link state");
00954 else
00955 status = (omapi_connection_put_string
00956 (c, dhcp_flink_state_names [link -> state]));
00957 if (status != ISC_R_SUCCESS)
00958 return status;
00959
00960 if (link -> inner && link -> inner -> type -> stuff_values)
00961 return (*(link -> inner -> type -> stuff_values)) (c, id,
00962 link -> inner);
00963 return ISC_R_SUCCESS;
00964 }
00965
00966
00967
00968
00969 isc_result_t dhcp_failover_listen (omapi_object_t *h)
00970 {
00971 isc_result_t status;
00972 dhcp_failover_listener_t *obj, *l;
00973 omapi_value_t *value = (omapi_value_t *)0;
00974 omapi_addr_t local_addr;
00975 unsigned long port;
00976
00977 status = omapi_get_value_str (h, (omapi_object_t *)0,
00978 "local-port", &value);
00979 if (status != ISC_R_SUCCESS)
00980 return status;
00981 if (!value -> value) {
00982 omapi_value_dereference (&value, MDL);
00983 return DHCP_R_INVALIDARG;
00984 }
00985
00986 status = omapi_get_int_value (&port, value -> value);
00987 omapi_value_dereference (&value, MDL);
00988 if (status != ISC_R_SUCCESS)
00989 return status;
00990 local_addr.port = port;
00991
00992 status = omapi_get_value_str (h, (omapi_object_t *)0,
00993 "local-address", &value);
00994 if (status != ISC_R_SUCCESS)
00995 return status;
00996 if (!value -> value) {
00997 nogood:
00998 omapi_value_dereference (&value, MDL);
00999 return DHCP_R_INVALIDARG;
01000 }
01001
01002 if (value -> value -> type != omapi_datatype_data ||
01003 value -> value -> u.buffer.len != sizeof (struct in_addr))
01004 goto nogood;
01005
01006 memcpy (local_addr.address, value -> value -> u.buffer.value,
01007 value -> value -> u.buffer.len);
01008 local_addr.addrlen = value -> value -> u.buffer.len;
01009 local_addr.addrtype = AF_INET;
01010
01011 omapi_value_dereference (&value, MDL);
01012
01013
01014 for (l = failover_listeners; l; l = l -> next) {
01015 if (l -> address.port == local_addr.port &&
01016 l -> address.addrtype == local_addr.addrtype &&
01017 l -> address.addrlen == local_addr.addrlen &&
01018 !memcmp (l -> address.address, local_addr.address,
01019 local_addr.addrlen))
01020 break;
01021 }
01022
01023 if (l)
01024 return ISC_R_SUCCESS;
01025
01026 obj = (dhcp_failover_listener_t *)0;
01027 status = dhcp_failover_listener_allocate (&obj, MDL);
01028 if (status != ISC_R_SUCCESS)
01029 return status;
01030 obj -> address = local_addr;
01031
01032 status = omapi_listen_addr ((omapi_object_t *)obj, &obj -> address, 1);
01033 if (status != ISC_R_SUCCESS)
01034 return status;
01035
01036 status = omapi_object_reference (&h -> outer,
01037 (omapi_object_t *)obj, MDL);
01038 if (status != ISC_R_SUCCESS) {
01039 dhcp_failover_listener_dereference (&obj, MDL);
01040 return status;
01041 }
01042 status = omapi_object_reference (&obj -> inner, h, MDL);
01043 if (status != ISC_R_SUCCESS) {
01044 dhcp_failover_listener_dereference (&obj, MDL);
01045 return status;
01046 }
01047
01048
01049 if (failover_listeners) {
01050 dhcp_failover_listener_reference (&obj -> next,
01051 failover_listeners, MDL);
01052 dhcp_failover_listener_dereference (&failover_listeners, MDL);
01053 }
01054 dhcp_failover_listener_reference (&failover_listeners, obj, MDL);
01055
01056 return dhcp_failover_listener_dereference (&obj, MDL);
01057 }
01058
01059
01060
01061
01062 isc_result_t dhcp_failover_listener_signal (omapi_object_t *o,
01063 const char *name, va_list ap)
01064 {
01065 isc_result_t status;
01066 omapi_connection_object_t *c;
01067 dhcp_failover_link_t *obj;
01068 dhcp_failover_listener_t *p;
01069 dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0;
01070
01071 if (!o || o -> type != dhcp_type_failover_listener)
01072 return DHCP_R_INVALIDARG;
01073 p = (dhcp_failover_listener_t *)o;
01074
01075
01076 if (strcmp (name, "connect")) {
01077 if (p -> inner && p -> inner -> type -> signal_handler)
01078 return (*(p -> inner -> type -> signal_handler))
01079 (p -> inner, name, ap);
01080 return ISC_R_NOTFOUND;
01081 }
01082
01083 c = va_arg (ap, omapi_connection_object_t *);
01084 if (!c || c -> type != omapi_type_connection)
01085 return DHCP_R_INVALIDARG;
01086
01087
01088
01089 for (s = failover_states; s; s = s -> next) {
01090 if (dhcp_failover_state_match
01091 (s, (u_int8_t *)&c -> remote_addr.sin_addr,
01092 sizeof c -> remote_addr.sin_addr)) {
01093 state = s;
01094 break;
01095 }
01096 }
01097 if (!state) {
01098 log_info ("failover: listener: no matching state");
01099 omapi_disconnect ((omapi_object_t *)c, 1);
01100 return(ISC_R_NOTFOUND);
01101 }
01102
01103 obj = (dhcp_failover_link_t *)0;
01104 status = dhcp_failover_link_allocate (&obj, MDL);
01105 if (status != ISC_R_SUCCESS)
01106 return status;
01107 obj -> peer_port = ntohs (c -> remote_addr.sin_port);
01108
01109 status = omapi_object_reference (&obj -> outer,
01110 (omapi_object_t *)c, MDL);
01111 if (status != ISC_R_SUCCESS) {
01112 lose:
01113 dhcp_failover_link_dereference (&obj, MDL);
01114 log_info ("failover: listener: picayune failure.");
01115 omapi_disconnect ((omapi_object_t *)c, 1);
01116 return status;
01117 }
01118
01119 status = omapi_object_reference (&c -> inner,
01120 (omapi_object_t *)obj, MDL);
01121 if (status != ISC_R_SUCCESS)
01122 goto lose;
01123
01124 status = dhcp_failover_state_reference (&obj -> state_object,
01125 state, MDL);
01126 if (status != ISC_R_SUCCESS)
01127 goto lose;
01128
01129 omapi_signal_in ((omapi_object_t *)obj, "connect");
01130
01131 return dhcp_failover_link_dereference (&obj, MDL);
01132 }
01133
01134 isc_result_t dhcp_failover_listener_set_value (omapi_object_t *h,
01135 omapi_object_t *id,
01136 omapi_data_string_t *name,
01137 omapi_typed_data_t *value)
01138 {
01139 if (h -> type != dhcp_type_failover_listener)
01140 return DHCP_R_INVALIDARG;
01141
01142 if (h -> inner && h -> inner -> type -> set_value)
01143 return (*(h -> inner -> type -> set_value))
01144 (h -> inner, id, name, value);
01145 return ISC_R_NOTFOUND;
01146 }
01147
01148 isc_result_t dhcp_failover_listener_get_value (omapi_object_t *h,
01149 omapi_object_t *id,
01150 omapi_data_string_t *name,
01151 omapi_value_t **value)
01152 {
01153 if (h -> type != dhcp_type_failover_listener)
01154 return DHCP_R_INVALIDARG;
01155
01156 if (h -> inner && h -> inner -> type -> get_value)
01157 return (*(h -> inner -> type -> get_value))
01158 (h -> inner, id, name, value);
01159 return ISC_R_NOTFOUND;
01160 }
01161
01162 isc_result_t dhcp_failover_listener_destroy (omapi_object_t *h,
01163 const char *file, int line)
01164 {
01165 dhcp_failover_listener_t *l;
01166
01167 if (h -> type != dhcp_type_failover_listener)
01168 return DHCP_R_INVALIDARG;
01169 l = (dhcp_failover_listener_t *)h;
01170 if (l -> next)
01171 dhcp_failover_listener_dereference (&l -> next, file, line);
01172
01173 return ISC_R_SUCCESS;
01174 }
01175
01176
01177
01178
01179 isc_result_t dhcp_failover_listener_stuff (omapi_object_t *c,
01180 omapi_object_t *id,
01181 omapi_object_t *p)
01182 {
01183 if (p -> type != dhcp_type_failover_listener)
01184 return DHCP_R_INVALIDARG;
01185
01186 if (p -> inner && p -> inner -> type -> stuff_values)
01187 return (*(p -> inner -> type -> stuff_values)) (c, id,
01188 p -> inner);
01189 return ISC_R_SUCCESS;
01190 }
01191
01192
01193
01194 isc_result_t dhcp_failover_register (omapi_object_t *h)
01195 {
01196 isc_result_t status;
01197 dhcp_failover_state_t *obj;
01198 unsigned long port;
01199 omapi_value_t *value = (omapi_value_t *)0;
01200
01201 status = omapi_get_value_str (h, (omapi_object_t *)0,
01202 "local-port", &value);
01203 if (status != ISC_R_SUCCESS)
01204 return status;
01205 if (!value -> value) {
01206 omapi_value_dereference (&value, MDL);
01207 return DHCP_R_INVALIDARG;
01208 }
01209
01210 status = omapi_get_int_value (&port, value -> value);
01211 omapi_value_dereference (&value, MDL);
01212 if (status != ISC_R_SUCCESS)
01213 return status;
01214
01215 obj = (dhcp_failover_state_t *)0;
01216 dhcp_failover_state_allocate (&obj, MDL);
01217 obj -> me.port = port;
01218
01219 status = omapi_listen ((omapi_object_t *)obj, port, 1);
01220 if (status != ISC_R_SUCCESS) {
01221 dhcp_failover_state_dereference (&obj, MDL);
01222 return status;
01223 }
01224
01225 status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj,
01226 MDL);
01227 if (status != ISC_R_SUCCESS) {
01228 dhcp_failover_state_dereference (&obj, MDL);
01229 return status;
01230 }
01231 status = omapi_object_reference (&obj -> inner, h, MDL);
01232 dhcp_failover_state_dereference (&obj, MDL);
01233 return status;
01234 }
01235
01236
01237
01238 isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
01239 const char *name, va_list ap)
01240 {
01241 isc_result_t status;
01242 dhcp_failover_state_t *state;
01243 dhcp_failover_link_t *link;
01244 struct timeval tv;
01245
01246 if (!o || o -> type != dhcp_type_failover_state)
01247 return DHCP_R_INVALIDARG;
01248 state = (dhcp_failover_state_t *)o;
01249
01250
01251 if (strcmp (name, "disconnect") &&
01252 strcmp (name, "message")) {
01253 if (state -> inner && state -> inner -> type -> signal_handler)
01254 return (*(state -> inner -> type -> signal_handler))
01255 (state -> inner, name, ap);
01256 return ISC_R_NOTFOUND;
01257 }
01258
01259
01260
01261 if (!strcmp (name, "disconnect")) {
01262 link = va_arg (ap, dhcp_failover_link_t *);
01263
01264 dhcp_failover_link_dereference (&state -> link_to_peer, MDL);
01265 dhcp_failover_state_transition (state, "disconnect");
01266 if (state -> i_am == primary) {
01267 #if defined (DEBUG_FAILOVER_TIMING)
01268 log_info ("add_timeout +90 %s",
01269 "dhcp_failover_reconnect");
01270 #endif
01271 tv . tv_sec = cur_time + 90;
01272 tv . tv_usec = 0;
01273 add_timeout (&tv, dhcp_failover_reconnect,
01274 state,
01275 (tvref_t)dhcp_failover_state_reference,
01276 (tvunref_t)
01277 dhcp_failover_state_dereference);
01278 }
01279 } else if (!strcmp (name, "message")) {
01280 link = va_arg (ap, dhcp_failover_link_t *);
01281
01282 if (link -> imsg -> type == FTM_CONNECT) {
01283
01284
01285
01286
01287
01288 if (state -> link_to_peer) {
01289 dhcp_failover_send_connectack
01290 ((omapi_object_t *)link, state,
01291 FTR_DUP_CONNECTION,
01292 "already connected");
01293 omapi_disconnect (link -> outer, 1);
01294 return ISC_R_SUCCESS;
01295 }
01296 if (!(link -> imsg -> options_present & FTB_MCLT)) {
01297 dhcp_failover_send_connectack
01298 ((omapi_object_t *)link, state,
01299 FTR_INVALID_MCLT,
01300 "no MCLT provided");
01301 omapi_disconnect (link -> outer, 1);
01302 return ISC_R_SUCCESS;
01303 }
01304
01305 dhcp_failover_link_reference (&state -> link_to_peer,
01306 link, MDL);
01307 status = (dhcp_failover_send_connectack
01308 ((omapi_object_t *)link, state, 0, 0));
01309 if (status != ISC_R_SUCCESS) {
01310 dhcp_failover_link_dereference
01311 (&state -> link_to_peer, MDL);
01312 log_info ("dhcp_failover_send_connectack: %s",
01313 isc_result_totext (status));
01314 omapi_disconnect (link -> outer, 1);
01315 return ISC_R_SUCCESS;
01316 }
01317 if (link -> imsg -> options_present & FTB_MAX_UNACKED)
01318 state -> partner.max_flying_updates =
01319 link -> imsg -> max_unacked;
01320 if (link -> imsg -> options_present & FTB_RECEIVE_TIMER)
01321 state -> partner.max_response_delay =
01322 link -> imsg -> receive_timer;
01323 state -> mclt = link -> imsg -> mclt;
01324 dhcp_failover_send_state (state);
01325 cancel_timeout (dhcp_failover_link_startup_timeout,
01326 link);
01327 } else if (link -> imsg -> type == FTM_CONNECTACK) {
01328 const char *errmsg;
01329 char errbuf[1024];
01330 int reason;
01331
01332 cancel_timeout (dhcp_failover_link_startup_timeout,
01333 link);
01334
01335 if (!(link->imsg->options_present &
01336 FTB_RELATIONSHIP_NAME)) {
01337 errmsg = "missing relationship-name";
01338 reason = FTR_INVALID_PARTNER;
01339 goto badconnectack;
01340 }
01341
01342 if (link->imsg->options_present & FTB_REJECT_REASON) {
01343
01344 log_error ("Failover CONNECT to %s rejected: %s",
01345 state ? state->name : "unknown",
01346 (dhcp_failover_reject_reason_print
01347 (link -> imsg -> reject_reason)));
01348
01349 omapi_disconnect (link -> outer, 1);
01350 return ISC_R_SUCCESS;
01351 }
01352
01353 if (!dhcp_failover_state_match_by_name(state,
01354 &link->imsg->relationship_name)) {
01355
01356 snprintf(errbuf, sizeof(errbuf), "remote failover "
01357 "relationship name %.*s does not match",
01358 (int)link->imsg->relationship_name.count,
01359 link->imsg->relationship_name.data);
01360 errmsg = errbuf;
01361 reason = FTR_INVALID_PARTNER;
01362 badconnectack:
01363 log_error("Failover CONNECTACK from %s: %s",
01364 state->name, errmsg);
01365 dhcp_failover_send_disconnect ((omapi_object_t *)link,
01366 reason, errmsg);
01367 omapi_disconnect (link -> outer, 0);
01368 return ISC_R_SUCCESS;
01369 }
01370
01371 if (state -> link_to_peer) {
01372 errmsg = "already connected";
01373 reason = FTR_DUP_CONNECTION;
01374 goto badconnectack;
01375 }
01376
01377 if ((cur_time > link -> imsg -> time &&
01378 cur_time - link -> imsg -> time > 60) ||
01379 (cur_time < link -> imsg -> time &&
01380 link -> imsg -> time - cur_time > 60)) {
01381 errmsg = "time offset too large";
01382 reason = FTR_TIMEMISMATCH;
01383 goto badconnectack;
01384 }
01385
01386 dhcp_failover_link_reference (&state -> link_to_peer,
01387 link, MDL);
01388 #if 0
01389
01390
01391
01392
01393 if (state -> me.state == startup)
01394 dhcp_failover_set_state (state,
01395 state -> saved_state);
01396 else
01397 #endif
01398 dhcp_failover_send_state (state);
01399
01400 if (link -> imsg -> options_present & FTB_MAX_UNACKED)
01401 state -> partner.max_flying_updates =
01402 link -> imsg -> max_unacked;
01403 if (link -> imsg -> options_present & FTB_RECEIVE_TIMER)
01404 state -> partner.max_response_delay =
01405 link -> imsg -> receive_timer;
01406 #if defined (DEBUG_FAILOVER_CONTACT_TIMING)
01407 log_info ("add_timeout +%d %s",
01408 (int)state -> partner.max_response_delay / 3,
01409 "dhcp_failover_send_contact");
01410 #endif
01411 tv . tv_sec = cur_time +
01412 (int)state -> partner.max_response_delay / 3;
01413 tv . tv_usec = 0;
01414 add_timeout (&tv,
01415 dhcp_failover_send_contact, state,
01416 (tvref_t)dhcp_failover_state_reference,
01417 (tvunref_t)dhcp_failover_state_dereference);
01418 #if defined (DEBUG_FAILOVER_CONTACT_TIMING)
01419 log_info ("add_timeout +%d %s",
01420 (int)state -> me.max_response_delay,
01421 "dhcp_failover_timeout");
01422 #endif
01423 tv . tv_sec = cur_time +
01424 (int)state -> me.max_response_delay;
01425 tv . tv_usec = 0;
01426 add_timeout (&tv,
01427 dhcp_failover_timeout, state,
01428 (tvref_t)dhcp_failover_state_reference,
01429 (tvunref_t)dhcp_failover_state_dereference);
01430 } else if (link -> imsg -> type == FTM_DISCONNECT) {
01431 if (link -> imsg -> reject_reason) {
01432 log_error ("Failover DISCONNECT from %s: %s",
01433 state ? state->name : "unknown",
01434 (dhcp_failover_reject_reason_print
01435 (link -> imsg -> reject_reason)));
01436 }
01437 omapi_disconnect (link -> outer, 1);
01438 } else if (link -> imsg -> type == FTM_BNDUPD) {
01439 dhcp_failover_process_bind_update (state,
01440 link -> imsg);
01441 } else if (link -> imsg -> type == FTM_BNDACK) {
01442 dhcp_failover_process_bind_ack (state, link -> imsg);
01443 } else if (link -> imsg -> type == FTM_UPDREQ) {
01444 dhcp_failover_process_update_request (state,
01445 link -> imsg);
01446 } else if (link -> imsg -> type == FTM_UPDREQALL) {
01447 dhcp_failover_process_update_request_all
01448 (state, link -> imsg);
01449 } else if (link -> imsg -> type == FTM_UPDDONE) {
01450 dhcp_failover_process_update_done (state,
01451 link -> imsg);
01452 } else if (link -> imsg -> type == FTM_POOLREQ) {
01453 dhcp_failover_pool_reqbalance(state);
01454 } else if (link -> imsg -> type == FTM_POOLRESP) {
01455 log_info ("pool response: %ld leases",
01456 (unsigned long)
01457 link -> imsg -> addresses_transferred);
01458 } else if (link -> imsg -> type == FTM_STATE) {
01459 dhcp_failover_peer_state_changed (state,
01460 link -> imsg);
01461 }
01462
01463
01464
01465
01466
01467 if (state -> link_to_peer &&
01468 state -> link_to_peer == link &&
01469 state -> link_to_peer -> state != dhcp_flink_disconnected)
01470 {
01471 #if defined (DEBUG_FAILOVER_CONTACT_TIMING)
01472 log_info ("add_timeout +%d %s",
01473 (int)state -> me.max_response_delay,
01474 "dhcp_failover_timeout");
01475 #endif
01476 tv . tv_sec = cur_time +
01477 (int)state -> me.max_response_delay;
01478 tv . tv_usec = 0;
01479 add_timeout (&tv,
01480 dhcp_failover_timeout, state,
01481 (tvref_t)dhcp_failover_state_reference,
01482 (tvunref_t)dhcp_failover_state_dereference);
01483
01484 }
01485 }
01486
01487
01488 return ISC_R_SUCCESS;
01489 }
01490
01491 isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state,
01492 const char *name)
01493 {
01494 isc_result_t status;
01495
01496
01497 if (!strcmp (name, "disconnect")) {
01498 if (state -> link_to_peer) {
01499 log_info ("peer %s: disconnected", state -> name);
01500 if (state -> link_to_peer -> state_object)
01501 dhcp_failover_state_dereference
01502 (&state -> link_to_peer -> state_object, MDL);
01503 dhcp_failover_link_dereference (&state -> link_to_peer,
01504 MDL);
01505 }
01506 cancel_timeout (dhcp_failover_send_contact, state);
01507 cancel_timeout (dhcp_failover_timeout, state);
01508 cancel_timeout (dhcp_failover_startup_timeout, state);
01509
01510 switch (state -> me.state == startup ?
01511 state -> saved_state : state -> me.state) {
01512
01513
01514
01515 case communications_interrupted:
01516 case conflict_done:
01517 case partner_down:
01518 case paused:
01519 case recover:
01520 case recover_done:
01521 case recover_wait:
01522 case resolution_interrupted:
01523 case shut_down:
01524
01525 if (state -> me.state == startup)
01526 return (dhcp_failover_set_state
01527 (state, state -> saved_state));
01528 return ISC_R_SUCCESS;
01529
01530 case potential_conflict:
01531 return dhcp_failover_set_state
01532 (state, resolution_interrupted);
01533
01534 case normal:
01535 return dhcp_failover_set_state
01536 (state, communications_interrupted);
01537
01538 case unknown_state:
01539 return dhcp_failover_set_state
01540 (state, resolution_interrupted);
01541
01542 default:
01543 log_fatal("Impossible case at %s:%d.", MDL);
01544 break;
01545 }
01546 } else if (!strcmp (name, "connect")) {
01547 switch (state -> me.state) {
01548 case communications_interrupted:
01549 status = dhcp_failover_set_state (state, normal);
01550 dhcp_failover_send_updates (state);
01551 return status;
01552
01553 case resolution_interrupted:
01554 return dhcp_failover_set_state (state,
01555 potential_conflict);
01556
01557 case conflict_done:
01558 case partner_down:
01559 case potential_conflict:
01560 case normal:
01561 case recover:
01562 case shut_down:
01563 case paused:
01564 case unknown_state:
01565 case recover_done:
01566 case startup:
01567 case recover_wait:
01568 return dhcp_failover_send_state (state);
01569
01570 default:
01571 log_fatal("Impossible case at %s:%d.", MDL);
01572 break;
01573 }
01574 } else if (!strcmp (name, "startup")) {
01575 dhcp_failover_set_state (state, startup);
01576 return ISC_R_SUCCESS;
01577 } else if (!strcmp (name, "connect-timeout")) {
01578 switch (state -> me.state) {
01579 case communications_interrupted:
01580 case partner_down:
01581 case resolution_interrupted:
01582 case paused:
01583 case startup:
01584 case shut_down:
01585 case conflict_done:
01586 return ISC_R_SUCCESS;
01587
01588 case normal:
01589 case recover:
01590 case recover_wait:
01591 case recover_done:
01592 case unknown_state:
01593 return dhcp_failover_set_state
01594 (state, communications_interrupted);
01595
01596 case potential_conflict:
01597 return dhcp_failover_set_state
01598 (state, resolution_interrupted);
01599
01600 default:
01601 log_fatal("Impossible case at %s:%d.", MDL);
01602 break;
01603 }
01604 }
01605 return DHCP_R_INVALIDARG;
01606 }
01607
01608 isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state)
01609 {
01610 switch (state -> me.state) {
01611 case unknown_state:
01612 state -> service_state = not_responding;
01613 state -> nrr = " (my state unknown)";
01614 break;
01615
01616 case partner_down:
01617 state -> service_state = service_partner_down;
01618 state -> nrr = "";
01619 break;
01620
01621 case normal:
01622 state -> service_state = cooperating;
01623 state -> nrr = "";
01624 break;
01625
01626 case communications_interrupted:
01627 state -> service_state = not_cooperating;
01628 state -> nrr = "";
01629 break;
01630
01631 case resolution_interrupted:
01632 case potential_conflict:
01633 case conflict_done:
01634 state -> service_state = not_responding;
01635 state -> nrr = " (resolving conflicts)";
01636 break;
01637
01638 case recover:
01639 state -> service_state = not_responding;
01640 state -> nrr = " (recovering)";
01641 break;
01642
01643 case shut_down:
01644 state -> service_state = not_responding;
01645 state -> nrr = " (shut down)";
01646 break;
01647
01648 case paused:
01649 state -> service_state = not_responding;
01650 state -> nrr = " (paused)";
01651 break;
01652
01653 case recover_wait:
01654 state -> service_state = not_responding;
01655 state -> nrr = " (recover wait)";
01656 break;
01657
01658 case recover_done:
01659 state -> service_state = not_responding;
01660 state -> nrr = " (recover done)";
01661 break;
01662
01663 case startup:
01664 state -> service_state = service_startup;
01665 state -> nrr = " (startup)";
01666 break;
01667
01668 default:
01669 log_fatal("Impossible case at %s:%d.\n", MDL);
01670 break;
01671 }
01672
01673
01674
01675
01676 if (state -> service_state != not_responding) {
01677 switch (state -> partner.state) {
01678 case partner_down:
01679 state -> service_state = not_responding;
01680 state -> nrr = " (peer demands: recovering)";
01681 break;
01682
01683 case potential_conflict:
01684 case conflict_done:
01685 case resolution_interrupted:
01686 state -> service_state = not_responding;
01687 state -> nrr = " (peer demands: resolving conflicts)";
01688 break;
01689
01690
01691 default:
01692 break;
01693 }
01694 }
01695
01696 return ISC_R_SUCCESS;
01697 }
01698
01699 isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state,
01700 enum failover_state new_state)
01701 {
01702 enum failover_state saved_state;
01703 TIME saved_stos;
01704 struct pool *p;
01705 struct shared_network *s;
01706 struct lease *l;
01707 struct timeval tv;
01708
01709 TRACE(DHCPD_FAILOVER_SET_STATE_START(state->me.state, new_state));
01710
01711
01712
01713
01714
01715 switch (state -> me.state) {
01716 case normal:
01717 case potential_conflict:
01718 case partner_down:
01719 if (state -> ack_queue_tail) {
01720 struct lease *lp;
01721
01722
01723 for (lp = state -> ack_queue_head; lp; lp = lp -> next_pending)
01724 lp -> flags = ((lp -> flags & ~ON_ACK_QUEUE) |
01725 ON_UPDATE_QUEUE);
01726
01727
01728
01729 if (state -> update_queue_head) {
01730 lease_reference (&state -> ack_queue_tail -> next_pending,
01731 state -> update_queue_head, MDL);
01732 lease_dereference (&state -> update_queue_head, MDL);
01733 }
01734 lease_reference (&state -> update_queue_head,
01735 state -> ack_queue_head, MDL);
01736 if (!state -> update_queue_tail) {
01737 #if defined (POINTER_DEBUG)
01738 if (state -> ack_queue_tail -> next_pending) {
01739 log_error ("next pending on ack queue tail.");
01740 abort ();
01741 }
01742 #endif
01743 lease_reference (&state -> update_queue_tail,
01744 state -> ack_queue_tail, MDL);
01745 }
01746 lease_dereference (&state -> ack_queue_tail, MDL);
01747 lease_dereference (&state -> ack_queue_head, MDL);
01748 state -> cur_unacked_updates = 0;
01749 }
01750
01751 cancel_timeout (dhcp_failover_keepalive, state);
01752 break;
01753
01754 default:
01755 break;
01756 }
01757
01758
01759 saved_state = state -> me.state;
01760 saved_stos = state -> me.stos;
01761
01762
01763
01764 if (new_state != recover_wait && new_state != startup &&
01765 saved_state != startup)
01766 state -> me.stos = cur_time;
01767
01768
01769
01770
01771
01772
01773 if (new_state == recover && saved_state == shut_down &&
01774 state -> partner.state == partner_down &&
01775 !state -> update_queue_head && !state -> ack_queue_head)
01776 state -> me.stos = cur_time - state -> mclt;
01777
01778 state -> me.state = new_state;
01779 if (new_state == startup && saved_state != startup)
01780 state -> saved_state = saved_state;
01781
01782
01783 if (!write_failover_state (state) || !commit_leases ()) {
01784 log_error ("Unable to record current failover state for %s",
01785 state -> name);
01786 state -> me.state = saved_state;
01787 state -> me.stos = saved_stos;
01788 return ISC_R_IOERROR;
01789 }
01790
01791 log_info ("failover peer %s: I move from %s to %s",
01792 state -> name, dhcp_failover_state_name_print (saved_state),
01793 dhcp_failover_state_name_print (state -> me.state));
01794
01795
01796 if ((state->me.state == normal) && (state->partner.state == normal))
01797 log_info("failover peer %s: Both servers normal", state->name);
01798
01799
01800 if (new_state != startup && saved_state == startup)
01801 cancel_timeout (dhcp_failover_startup_timeout, state);
01802
01803
01804
01805
01806
01807 cancel_timeout(dhcp_failover_auto_partner_down, state);
01808
01809
01810 dhcp_failover_set_service_state (state);
01811
01812
01813 if (state -> link_to_peer)
01814 dhcp_failover_send_state (state);
01815
01816 switch (new_state) {
01817 case communications_interrupted:
01818
01819
01820
01821
01822
01823
01824
01825
01826 if (state->auto_partner_down == 0)
01827 break;
01828
01829 #if defined (DEBUG_FAILOVER_TIMING)
01830 log_info("add_timeout +%lu dhcp_failover_auto_partner_down",
01831 (unsigned long)state->auto_partner_down);
01832 #endif
01833 tv.tv_sec = cur_time + state->auto_partner_down;
01834 tv.tv_usec = 0;
01835 add_timeout(&tv, dhcp_failover_auto_partner_down, state,
01836 (tvref_t)omapi_object_reference,
01837 (tvunref_t)omapi_object_dereference);
01838 break;
01839
01840 case normal:
01841
01842
01843
01844
01845
01846 dhcp_failover_pool_balance(state);
01847 dhcp_failover_generate_update_queue(state, 0);
01848
01849 if (state->update_queue_tail != NULL) {
01850 dhcp_failover_send_updates(state);
01851 log_info("Sending updates to %s.", state->name);
01852 }
01853
01854 break;
01855
01856 case potential_conflict:
01857 if (state -> i_am == primary)
01858 dhcp_failover_send_update_request (state);
01859 break;
01860
01861 case startup:
01862 #if defined (DEBUG_FAILOVER_TIMING)
01863 log_info ("add_timeout +15 %s",
01864 "dhcp_failover_startup_timeout");
01865 #endif
01866 tv . tv_sec = cur_time + 15;
01867 tv . tv_usec = 0;
01868 add_timeout (&tv,
01869 dhcp_failover_startup_timeout,
01870 state,
01871 (tvref_t)omapi_object_reference,
01872 (tvunref_t)
01873 omapi_object_dereference);
01874 break;
01875
01876
01877
01878 case recover_wait:
01879 if (state -> me.stos + state -> mclt > cur_time) {
01880 #if defined (DEBUG_FAILOVER_TIMING)
01881 log_info ("add_timeout +%d %s",
01882 (int)(cur_time -
01883 state -> me.stos + state -> mclt),
01884 "dhcp_failover_startup_timeout");
01885 #endif
01886 tv . tv_sec = (int)(state -> me.stos + state -> mclt);
01887 tv . tv_usec = 0;
01888 add_timeout (&tv,
01889 dhcp_failover_recover_done,
01890 state,
01891 (tvref_t)omapi_object_reference,
01892 (tvunref_t)
01893 omapi_object_dereference);
01894 } else
01895 dhcp_failover_recover_done (state);
01896 break;
01897
01898 case recover:
01899
01900
01901
01902
01903 if (state -> link_to_peer)
01904 dhcp_failover_send_update_request_all (state);
01905 break;
01906
01907 case partner_down:
01908
01909 for (s = shared_networks; s; s = s -> next) {
01910 for (p = s -> pools; p; p = p -> next) {
01911 if (p -> failover_peer == state) {
01912 for (l = p->expired ; l ; l = l->next) {
01913 l->tsfp = state->me.stos + state->mclt;
01914 l->sort_time = (l->tsfp > l->ends) ?
01915 l->tsfp : l->ends;
01916 }
01917 if (p->expired &&
01918 (p->expired->sort_time < p->next_event_time)) {
01919
01920 p->next_event_time = p->expired->sort_time;
01921 #if defined (DEBUG_FAILOVER_TIMING)
01922 log_info ("add_timeout +%d %s",
01923 (int)(cur_time - p->next_event_time),
01924 "pool_timer");
01925 #endif
01926 tv.tv_sec = p->next_event_time;
01927 tv.tv_usec = 0;
01928 add_timeout(&tv, pool_timer, p,
01929 (tvref_t)pool_reference,
01930 (tvunref_t)pool_dereference);
01931 }
01932 }
01933 }
01934 }
01935 break;
01936
01937
01938 default:
01939 break;
01940 }
01941
01942 TRACE(DHCPD_FAILOVER_SET_STATE_DONE());
01943
01944 return ISC_R_SUCCESS;
01945 }
01946
01947 isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *state,
01948 failover_message_t *msg)
01949 {
01950 enum failover_state previous_state = state -> partner.state;
01951 enum failover_state new_state;
01952 int startupp;
01953
01954 new_state = msg -> server_state;
01955 startupp = (msg -> server_flags & FTF_SERVER_STARTUP) ? 1 : 0;
01956
01957 if (state -> partner.state == new_state && state -> me.state) {
01958 switch (state -> me.state) {
01959 case startup:
01960 dhcp_failover_set_state (state, state -> saved_state);
01961 return ISC_R_SUCCESS;
01962
01963 case unknown_state:
01964 case normal:
01965 case potential_conflict:
01966 case recover_done:
01967 case shut_down:
01968 case paused:
01969 case recover_wait:
01970 return ISC_R_SUCCESS;
01971
01972
01973
01974 case partner_down:
01975 case communications_interrupted:
01976 case resolution_interrupted:
01977 case recover:
01978 case conflict_done:
01979 break;
01980
01981 default:
01982 log_fatal("Impossible case at %s:%d.", MDL);
01983 break;
01984 }
01985 }
01986
01987 state -> partner.state = new_state;
01988
01989 log_info ("failover peer %s: peer moves from %s to %s",
01990 state -> name,
01991 dhcp_failover_state_name_print (previous_state),
01992 dhcp_failover_state_name_print (state -> partner.state));
01993
01994
01995 if ((state->me.state == normal) && (state->partner.state == normal))
01996 log_info("failover peer %s: Both servers normal", state->name);
01997
01998 if (!write_failover_state (state) || !commit_leases ()) {
01999
02000
02001
02002 log_error ("Unable to record current failover state for %s",
02003 state -> name);
02004 }
02005
02006
02007
02008
02009 switch (new_state) {
02010 case unknown_state:
02011 case startup:
02012 case normal:
02013 case communications_interrupted:
02014 case partner_down:
02015 case potential_conflict:
02016 case recover:
02017 case paused:
02018 case shut_down:
02019 case recover_done:
02020 case resolution_interrupted:
02021 case conflict_done:
02022 case recover_wait:
02023 break;
02024
02025 default:
02026 log_error("failover peer %s: Invalid state: %d", state->name,
02027 new_state);
02028 dhcp_failover_set_state(state, shut_down);
02029 return ISC_R_SUCCESS;
02030 }
02031
02032
02033
02034
02035 switch (state -> me.state == startup ?
02036 state -> saved_state : state -> me.state) {
02037 case normal:
02038 switch (new_state) {
02039 case normal:
02040 dhcp_failover_state_pool_check (state);
02041 break;
02042
02043 case partner_down:
02044 if (state -> me.state == startup)
02045 dhcp_failover_set_state (state, recover);
02046 else
02047 dhcp_failover_set_state (state,
02048 potential_conflict);
02049 break;
02050
02051 case potential_conflict:
02052 case resolution_interrupted:
02053 case conflict_done:
02054
02055 log_error("Peer %s: Invalid state transition %s "
02056 "to %s.", state->name,
02057 dhcp_failover_state_name_print(previous_state),
02058 dhcp_failover_state_name_print(new_state));
02059 dhcp_failover_set_state (state, shut_down);
02060 break;
02061
02062 case recover:
02063 case shut_down:
02064 dhcp_failover_set_state (state, partner_down);
02065 break;
02066
02067 case paused:
02068 dhcp_failover_set_state (state,
02069 communications_interrupted);
02070 break;
02071
02072 default:
02073
02074
02075
02076 break;
02077 }
02078 break;
02079
02080 case recover:
02081 switch (new_state) {
02082 case recover:
02083 log_info ("failover peer %s: requesting %s",
02084 state -> name, "full update from peer");
02085
02086
02087
02088 if (state -> me.state == recover)
02089 dhcp_failover_send_update_request_all (state);
02090 break;
02091
02092 case potential_conflict:
02093 case resolution_interrupted:
02094 case conflict_done:
02095 case normal:
02096 dhcp_failover_set_state (state, potential_conflict);
02097 break;
02098
02099 case partner_down:
02100 case communications_interrupted:
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114 if (state -> me.state == recover)
02115 dhcp_failover_send_update_request_all (state);
02116 break;
02117
02118 case shut_down:
02119
02120
02121
02122 dhcp_failover_set_state (state, partner_down);
02123 break;
02124
02125
02126 default:
02127
02128
02129
02130 break;
02131 }
02132 break;
02133
02134 case potential_conflict:
02135 switch (new_state) {
02136 case normal:
02137
02138 log_error("Peer %s moves to normal during conflict "
02139 "resolution - panic, shutting down.",
02140 state->name);
02141 dhcp_failover_set_state(state, shut_down);
02142 break;
02143
02144 case conflict_done:
02145 if (previous_state == potential_conflict)
02146 dhcp_failover_send_update_request (state);
02147 else
02148 log_error("Peer %s: Unexpected move to "
02149 "conflict-done.", state->name);
02150 break;
02151
02152 case recover_done:
02153 case recover_wait:
02154 case potential_conflict:
02155 case partner_down:
02156 case communications_interrupted:
02157 case resolution_interrupted:
02158 case paused:
02159 break;
02160
02161 case recover:
02162 dhcp_failover_set_state (state, recover);
02163 break;
02164
02165 case shut_down:
02166 dhcp_failover_set_state (state, partner_down);
02167 break;
02168
02169 default:
02170
02171 break;
02172 }
02173 break;
02174
02175 case conflict_done:
02176 switch (new_state) {
02177 case normal:
02178 case shut_down:
02179 dhcp_failover_set_state(state, new_state);
02180 break;
02181
02182 default:
02183 log_fatal("Peer %s: Invalid attempt to move from %s "
02184 "to %s while local state is conflict-done.",
02185 state->name,
02186 dhcp_failover_state_name_print(previous_state),
02187 dhcp_failover_state_name_print(new_state));
02188 }
02189 break;
02190
02191 case partner_down:
02192
02193 if (startupp)
02194 break;
02195
02196 switch (new_state) {
02197
02198 case recover:
02199 case recover_wait:
02200 break;
02201
02202 case recover_done:
02203 dhcp_failover_set_state (state, normal);
02204 break;
02205
02206 case normal:
02207 case potential_conflict:
02208 case partner_down:
02209 case communications_interrupted:
02210 case resolution_interrupted:
02211 case conflict_done:
02212 dhcp_failover_set_state (state, potential_conflict);
02213 break;
02214
02215 default:
02216
02217 break;
02218 }
02219 break;
02220
02221 case communications_interrupted:
02222 switch (new_state) {
02223 case paused:
02224
02225 break;
02226
02227
02228
02229
02230 case recover:
02231 dhcp_failover_set_state (state, partner_down);
02232 break;
02233
02234 case normal:
02235 case communications_interrupted:
02236 case recover_done:
02237 case recover_wait:
02238
02239
02240 dhcp_failover_send_updates (state);
02241 dhcp_failover_set_state (state, normal);
02242 break;
02243
02244 case potential_conflict:
02245 case partner_down:
02246 case resolution_interrupted:
02247 case conflict_done:
02248 dhcp_failover_set_state (state, potential_conflict);
02249 break;
02250
02251 case shut_down:
02252 dhcp_failover_set_state (state, partner_down);
02253 break;
02254
02255 default:
02256
02257 break;
02258 }
02259 break;
02260
02261 case resolution_interrupted:
02262 switch (new_state) {
02263 case normal:
02264 case recover:
02265 case potential_conflict:
02266 case partner_down:
02267 case communications_interrupted:
02268 case resolution_interrupted:
02269 case conflict_done:
02270 case recover_done:
02271 case recover_wait:
02272 dhcp_failover_set_state (state, potential_conflict);
02273 break;
02274
02275 case shut_down:
02276 dhcp_failover_set_state (state, partner_down);
02277 break;
02278
02279 default:
02280
02281 break;
02282 }
02283 break;
02284
02285
02286 case recover_wait:
02287 break;
02288
02289 case recover_done:
02290 switch (new_state) {
02291 case recover_done:
02292 log_error("Both servers have entered recover-done!");
02293 case normal:
02294 dhcp_failover_set_state (state, normal);
02295 break;
02296
02297 case shut_down:
02298 dhcp_failover_set_state (state, partner_down);
02299 break;
02300
02301 default:
02302
02303
02304
02305
02306
02307 break;
02308 }
02309 break;
02310
02311
02312
02313
02314 case shut_down:
02315 case paused:
02316 break;
02317
02318
02319 case unknown_state:
02320 break;
02321
02322 default:
02323 log_fatal("Impossible condition at %s:%d.", MDL);
02324 break;
02325
02326 }
02327
02328
02329
02330
02331 if (state -> me.state == startup && state -> saved_state != startup)
02332 dhcp_failover_set_state (state, state -> saved_state);
02333
02334
02335
02336 dhcp_failover_set_service_state (state);
02337
02338 return ISC_R_SUCCESS;
02339 }
02340
02341
02342
02343
02344
02345
02346 static void
02347 dhcp_failover_pool_balance(dhcp_failover_state_t *state)
02348 {
02349
02350 cancel_timeout(dhcp_failover_pool_rebalance, state);
02351 state->sched_balance = 0;
02352
02353 dhcp_failover_pool_dobalance(state, NULL);
02354 }
02355
02356
02357
02358
02359
02360
02361 void
02362 dhcp_failover_pool_rebalance(void *failover_state)
02363 {
02364 dhcp_failover_state_t *state;
02365 isc_boolean_t sendreq = ISC_FALSE;
02366
02367 state = (dhcp_failover_state_t *)failover_state;
02368
02369
02370 state->sched_balance = 0;
02371
02372 if (dhcp_failover_pool_dobalance(state, &sendreq))
02373 dhcp_failover_send_updates(state);
02374
02375 if (sendreq)
02376 dhcp_failover_send_poolreq(state);
02377 }
02378
02379
02380
02381
02382
02383 static void
02384 dhcp_failover_pool_reqbalance(dhcp_failover_state_t *state)
02385 {
02386 int queued;
02387
02388
02389 cancel_timeout(dhcp_failover_pool_rebalance, state);
02390 state->sched_balance = 0;
02391
02392 queued = dhcp_failover_pool_dobalance(state, NULL);
02393
02394 dhcp_failover_send_poolresp(state, queued);
02395
02396 if (queued)
02397 dhcp_failover_send_updates(state);
02398 else
02399 log_info("peer %s: Got POOLREQ, answering negatively! "
02400 "Peer may be out of leases or database inconsistent.",
02401 state->name);
02402 }
02403
02404
02405
02406
02407
02408
02409
02410
02411 static int
02412 dhcp_failover_pool_dobalance(dhcp_failover_state_t *state,
02413 isc_boolean_t *sendreq)
02414 {
02415 int lts, total, thresh, hold, panic, pass;
02416 int leases_queued = 0;
02417 struct lease *lp = (struct lease *)0;
02418 struct lease *next = (struct lease *)0;
02419 struct shared_network *s;
02420 struct pool *p;
02421 binding_state_t peer_lease_state;
02422
02423
02424 struct lease **lq;
02425 int (*log_func)(const char *, ...);
02426 const char *result, *reqlog;
02427
02428 if (state -> me.state != normal)
02429 return 0;
02430
02431 TRACE(DHCPD_FAILOVER_POOL_DOBALANCE_START());
02432
02433 state->last_balance = cur_time;
02434
02435 for (s = shared_networks ; s ; s = s->next) {
02436 for (p = s->pools ; p ; p = p->next) {
02437 if (p->failover_peer != state)
02438 continue;
02439
02440
02441
02442
02443
02444
02445
02446 if (p->failover_peer->i_am == primary) {
02447 lts = (p->free_leases - p->backup_leases) / 2;
02448 peer_lease_state = FTS_BACKUP;
02449
02450 lq = &p->free;
02451 } else {
02452 lts = (p->backup_leases - p->free_leases) / 2;
02453 peer_lease_state = FTS_FREE;
02454
02455 lq = &p->backup;
02456 }
02457
02458 total = p->backup_leases + p->free_leases;
02459
02460 thresh = ((total * state->max_lease_misbalance) + 50) / 100;
02461 hold = ((total * state->max_lease_ownership) + 50) / 100;
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476 panic = thresh * -2;
02477
02478 if (panic == 0)
02479 panic = -1;
02480
02481 if ((sendreq != NULL) && (lts < panic)) {
02482 reqlog = " (requesting peer rebalance!)";
02483 *sendreq = ISC_TRUE;
02484 } else
02485 reqlog = "";
02486
02487 log_info("balancing pool %lx %s total %d free %d "
02488 "backup %d lts %d max-own (+/-)%d%s",
02489 (unsigned long)p,
02490 (p->shared_network ?
02491 p->shared_network->name : ""), p->lease_count,
02492 p->free_leases, p->backup_leases, lts, hold,
02493 reqlog);
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507 pass = 0;
02508 lease_reference(&lp, *lq, MDL);
02509
02510 while (lp) {
02511 if (next)
02512 lease_dereference(&next, MDL);
02513 if (lp->next)
02514 lease_reference(&next, lp->next, MDL);
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533 if (pass) {
02534 if (lp->ends) {
02535 if (lts <= hold)
02536 break;
02537 } else {
02538 if (lts <= 0)
02539 break;
02540 }
02541 } else if (lts <= -hold)
02542 break;
02543
02544 if (pass || peer_wants_lease(lp)) {
02545 --lts;
02546 ++leases_queued;
02547 lp->next_binding_state = peer_lease_state;
02548 lp->tstp = cur_time;
02549 lp->starts = cur_time;
02550
02551 if (!supersede_lease(lp, NULL, 0, 1, 0) ||
02552 !write_lease(lp))
02553 log_error("can't commit lease %s on "
02554 "giveaway", piaddr(lp->ip_addr));
02555 }
02556
02557 lease_dereference(&lp, MDL);
02558 if (next)
02559 lease_reference(&lp, next, MDL);
02560 else if (!pass) {
02561 pass = 1;
02562 lease_reference(&lp, *lq, MDL);
02563 }
02564 }
02565
02566 if (next)
02567 lease_dereference(&next, MDL);
02568 if (lp)
02569 lease_dereference(&lp, MDL);
02570
02571 if (lts > thresh) {
02572 result = "IMBALANCED";
02573 log_func = log_error;
02574 } else {
02575 result = "balanced";
02576 log_func = log_info;
02577 }
02578
02579 log_func("%s pool %lx %s total %d free %d backup %d "
02580 "lts %d max-misbal %d", result, (unsigned long)p,
02581 (p->shared_network ?
02582 p->shared_network->name : ""), p->lease_count,
02583 p->free_leases, p->backup_leases, lts, thresh);
02584
02585
02586 dhcp_failover_pool_check(p);
02587 }
02588 }
02589
02590 if (leases_queued)
02591 commit_leases();
02592
02593 TRACE(DHCPD_FAILOVER_POOL_DOBALANCE_DONE());
02594
02595 return leases_queued;
02596 }
02597
02598
02599
02600
02601
02602 void
02603 dhcp_failover_pool_check(struct pool *pool)
02604 {
02605 dhcp_failover_state_t *peer;
02606 TIME est1, est2;
02607 struct timeval tv;
02608
02609 peer = pool->failover_peer;
02610
02611 if(!peer || peer->me.state != normal)
02612 return;
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624 if(pool->free && pool->free->ends < cur_time)
02625 est1 = cur_time - pool->free->ends;
02626 else
02627 est1 = 0;
02628
02629 if(pool->backup && pool->backup->ends < cur_time)
02630 est2 = cur_time - pool->backup->ends;
02631 else
02632 est2 = 0;
02633
02634
02635
02636
02637
02638 est1 = ((est1 * peer->max_lease_misbalance) + 50) / 100;
02639 est2 = ((est2 * peer->max_lease_misbalance) + 50) / 100;
02640
02641
02642
02643
02644 if(peer->i_am == primary)
02645 est1 *= 2;
02646 else
02647 est2 *= 2;
02648
02649
02650 if(est1 > est2)
02651 est1 = est2;
02652
02653
02654 if(est1 > peer->max_balance)
02655 est1 = peer->max_balance;
02656
02657
02658 est1 += cur_time;
02659
02660
02661 est2 = peer->last_balance + peer->min_balance;
02662 if(peer->last_balance && (est1 < est2))
02663 est1 = est2;
02664
02665
02666 est1 += random() % 5;
02667
02668
02669 if(peer->sched_balance) {
02670 if (est1 >= peer->sched_balance)
02671 return;
02672
02673
02674
02675
02676 cancel_timeout(dhcp_failover_pool_rebalance, peer);
02677 }
02678
02679
02680 peer->sched_balance = est1;
02681
02682 #if defined(DEBUG_FAILOVER_TIMING)
02683 log_info("add_timeout +%d dhcp_failover_pool_rebalance",
02684 (int)(est1 - cur_time));
02685 #endif
02686 tv.tv_sec = est1;
02687 tv.tv_usec = 0;
02688 add_timeout(&tv, dhcp_failover_pool_rebalance, peer,
02689 (tvref_t)dhcp_failover_state_reference,
02690 (tvunref_t)dhcp_failover_state_dereference);
02691 }
02692
02693 int dhcp_failover_state_pool_check (dhcp_failover_state_t *state)
02694 {
02695 struct shared_network *s;
02696 struct pool *p;
02697
02698 for (s = shared_networks; s; s = s -> next) {
02699 for (p = s -> pools; p; p = p -> next) {
02700 if (p -> failover_peer != state)
02701 continue;
02702 dhcp_failover_pool_check (p);
02703 }
02704 }
02705 return 0;
02706 }
02707
02708 isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *state)
02709 {
02710 struct lease *lp = (struct lease *)0;
02711 isc_result_t status;
02712
02713
02714 if (!state -> link_to_peer)
02715 return ISC_R_SUCCESS;
02716
02717
02718
02719
02720 if (state->toack_queue_head != NULL)
02721 dhcp_failover_send_acks(state);
02722
02723 while ((state -> partner.max_flying_updates >
02724 state -> cur_unacked_updates) && state -> update_queue_head) {
02725
02726 lease_reference (&lp, state -> update_queue_head, MDL);
02727
02728
02729 status = dhcp_failover_send_bind_update (state, lp);
02730 if (status != ISC_R_SUCCESS) {
02731 lease_dereference (&lp, MDL);
02732 return status;
02733 }
02734 lp -> flags &= ~ON_UPDATE_QUEUE;
02735
02736
02737
02738 lease_dereference (&state -> update_queue_head, MDL);
02739 if (lp -> next_pending) {
02740 lease_reference (&state -> update_queue_head,
02741 lp -> next_pending, MDL);
02742 lease_dereference (&lp -> next_pending, MDL);
02743 } else {
02744 lease_dereference (&state -> update_queue_tail, MDL);
02745 }
02746
02747 if (state -> ack_queue_head) {
02748 lease_reference
02749 (&state -> ack_queue_tail -> next_pending,
02750 lp, MDL);
02751 lease_dereference (&state -> ack_queue_tail, MDL);
02752 } else {
02753 lease_reference (&state -> ack_queue_head, lp, MDL);
02754 }
02755 #if defined (POINTER_DEBUG)
02756 if (lp -> next_pending) {
02757 log_error ("ack_queue_tail: lp -> next_pending");
02758 abort ();
02759 }
02760 #endif
02761 lease_reference (&state -> ack_queue_tail, lp, MDL);
02762 lp -> flags |= ON_ACK_QUEUE;
02763 lease_dereference (&lp, MDL);
02764
02765
02766 state -> cur_unacked_updates++;
02767 }
02768 return ISC_R_SUCCESS;
02769 }
02770
02771
02772
02773
02774
02775 int dhcp_failover_queue_update (struct lease *lease, int immediate)
02776 {
02777 dhcp_failover_state_t *state;
02778
02779 if (!lease -> pool ||
02780 !lease -> pool -> failover_peer)
02781 return 1;
02782
02783
02784 if (lease -> flags & ON_UPDATE_QUEUE)
02785 return 1;
02786
02787
02788 state = lease -> pool -> failover_peer;
02789
02790
02791 if (lease -> flags & ON_ACK_QUEUE)
02792 dhcp_failover_ack_queue_remove (state, lease);
02793
02794 if (state -> update_queue_head) {
02795 lease_reference (&state -> update_queue_tail -> next_pending,
02796 lease, MDL);
02797 lease_dereference (&state -> update_queue_tail, MDL);
02798 } else {
02799 lease_reference (&state -> update_queue_head, lease, MDL);
02800 }
02801 #if defined (POINTER_DEBUG)
02802 if (lease -> next_pending) {
02803 log_error ("next pending on update queue lease.");
02804 #if defined (DEBUG_RC_HISTORY)
02805 dump_rc_history (lease);
02806 #endif
02807 abort ();
02808 }
02809 #endif
02810 lease_reference (&state -> update_queue_tail, lease, MDL);
02811 lease -> flags |= ON_UPDATE_QUEUE;
02812 if (immediate)
02813 dhcp_failover_send_updates (state);
02814 return 1;
02815 }
02816
02817 int dhcp_failover_send_acks (dhcp_failover_state_t *state)
02818 {
02819 failover_message_t *msg = (failover_message_t *)0;
02820
02821
02822 if (!commit_leases ())
02823 return 0;
02824
02825 while (state -> toack_queue_head) {
02826 failover_message_reference
02827 (&msg, state -> toack_queue_head, MDL);
02828 failover_message_dereference
02829 (&state -> toack_queue_head, MDL);
02830 if (msg -> next) {
02831 failover_message_reference
02832 (&state -> toack_queue_head, msg -> next, MDL);
02833 }
02834
02835 dhcp_failover_send_bind_ack (state, msg, 0, (const char *)0);
02836
02837 failover_message_dereference (&msg, MDL);
02838 }
02839
02840 if (state -> toack_queue_tail)
02841 failover_message_dereference (&state -> toack_queue_tail, MDL);
02842 state -> pending_acks = 0;
02843
02844 return 1;
02845 }
02846
02847 void dhcp_failover_toack_queue_timeout (void *vs)
02848 {
02849 dhcp_failover_state_t *state = vs;
02850
02851 #if defined (DEBUG_FAILOVER_TIMING)
02852 log_info ("dhcp_failover_toack_queue_timeout");
02853 #endif
02854
02855 dhcp_failover_send_acks (state);
02856 }
02857
02858
02859
02860
02861 int dhcp_failover_queue_ack (dhcp_failover_state_t *state,
02862 failover_message_t *msg)
02863 {
02864 struct timeval tv;
02865
02866 if (state -> toack_queue_head) {
02867 failover_message_reference
02868 (&state -> toack_queue_tail -> next, msg, MDL);
02869 failover_message_dereference (&state -> toack_queue_tail, MDL);
02870 } else {
02871 failover_message_reference (&state -> toack_queue_head,
02872 msg, MDL);
02873 }
02874 failover_message_reference (&state -> toack_queue_tail, msg, MDL);
02875
02876 state -> pending_acks++;
02877
02878
02879
02880 if (state -> pending_acks >= state -> partner.max_flying_updates / 2) {
02881 dhcp_failover_send_acks (state);
02882 }
02883
02884
02885 if (state -> pending_acks > 0) {
02886 #if defined (DEBUG_FAILOVER_TIMING)
02887 log_info ("add_timeout +2 %s",
02888 "dhcp_failover_toack_queue_timeout");
02889 #endif
02890 tv . tv_sec = cur_time + 2;
02891 tv . tv_usec = 0;
02892 add_timeout (&tv,
02893 dhcp_failover_toack_queue_timeout, state,
02894 (tvref_t)dhcp_failover_state_reference,
02895 (tvunref_t)dhcp_failover_state_dereference);
02896 }
02897
02898 return 1;
02899 }
02900
02901 void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *state,
02902 struct lease *lease)
02903 {
02904 struct lease *lp;
02905
02906 if (!(lease -> flags & ON_ACK_QUEUE))
02907 return;
02908
02909 if (state -> ack_queue_head == lease) {
02910 lease_dereference (&state -> ack_queue_head, MDL);
02911 if (lease -> next_pending) {
02912 lease_reference (&state -> ack_queue_head,
02913 lease -> next_pending, MDL);
02914 lease_dereference (&lease -> next_pending, MDL);
02915 } else {
02916 lease_dereference (&state -> ack_queue_tail, MDL);
02917 }
02918 } else {
02919 for (lp = state -> ack_queue_head;
02920 lp && lp -> next_pending != lease;
02921 lp = lp -> next_pending)
02922 ;
02923
02924 if (!lp)
02925 return;
02926
02927 lease_dereference (&lp -> next_pending, MDL);
02928 if (lease -> next_pending) {
02929 lease_reference (&lp -> next_pending,
02930 lease -> next_pending, MDL);
02931 lease_dereference (&lease -> next_pending, MDL);
02932 } else {
02933 lease_dereference (&state -> ack_queue_tail, MDL);
02934 if (lp -> next_pending) {
02935 log_error ("state -> ack_queue_tail");
02936 abort ();
02937 }
02938 lease_reference (&state -> ack_queue_tail, lp, MDL);
02939 }
02940 }
02941
02942 lease -> flags &= ~ON_ACK_QUEUE;
02943
02944 lease->last_xid = 0;
02945
02946
02947
02948
02949 state -> cur_unacked_updates--;
02950
02951
02952
02953
02954
02955
02956 if (state -> cur_unacked_updates == 0) {
02957 commit_leases();
02958 }
02959 }
02960
02961 isc_result_t dhcp_failover_state_set_value (omapi_object_t *h,
02962 omapi_object_t *id,
02963 omapi_data_string_t *name,
02964 omapi_typed_data_t *value)
02965 {
02966 isc_result_t status;
02967
02968 if (h -> type != dhcp_type_failover_state)
02969 return DHCP_R_INVALIDARG;
02970
02971
02972
02973
02974
02975 if (!omapi_ds_strcmp (name, "name")) {
02976 return ISC_R_SUCCESS;
02977 } else if (!omapi_ds_strcmp (name, "partner-address")) {
02978 return ISC_R_SUCCESS;
02979 } else if (!omapi_ds_strcmp (name, "local-address")) {
02980 return ISC_R_SUCCESS;
02981 } else if (!omapi_ds_strcmp (name, "partner-port")) {
02982 return ISC_R_SUCCESS;
02983 } else if (!omapi_ds_strcmp (name, "local-port")) {
02984 return ISC_R_SUCCESS;
02985 } else if (!omapi_ds_strcmp (name, "max-outstanding-updates")) {
02986 return ISC_R_SUCCESS;
02987 } else if (!omapi_ds_strcmp (name, "mclt")) {
02988 return ISC_R_SUCCESS;
02989 } else if (!omapi_ds_strcmp (name, "load-balance-max-secs")) {
02990 return ISC_R_SUCCESS;
02991 } else if (!omapi_ds_strcmp (name, "load-balance-hba")) {
02992 return ISC_R_SUCCESS;
02993 } else if (!omapi_ds_strcmp (name, "partner-state")) {
02994 return ISC_R_SUCCESS;
02995 } else if (!omapi_ds_strcmp (name, "local-state")) {
02996 unsigned long l;
02997 status = omapi_get_int_value (&l, value);
02998 if (status != ISC_R_SUCCESS)
02999 return status;
03000 return dhcp_failover_set_state ((dhcp_failover_state_t *)h, l);
03001 } else if (!omapi_ds_strcmp (name, "partner-stos")) {
03002 return ISC_R_SUCCESS;
03003 } else if (!omapi_ds_strcmp (name, "local-stos")) {
03004 return ISC_R_SUCCESS;
03005 } else if (!omapi_ds_strcmp (name, "hierarchy")) {
03006 return ISC_R_SUCCESS;
03007 } else if (!omapi_ds_strcmp (name, "last-packet-sent")) {
03008 return ISC_R_SUCCESS;
03009 } else if (!omapi_ds_strcmp (name, "last-timestamp-received")) {
03010 return ISC_R_SUCCESS;
03011 } else if (!omapi_ds_strcmp (name, "skew")) {
03012 return ISC_R_SUCCESS;
03013 } else if (!omapi_ds_strcmp (name, "max-response-delay")) {
03014 return ISC_R_SUCCESS;
03015 } else if (!omapi_ds_strcmp (name, "cur-unacked-updates")) {
03016 return ISC_R_SUCCESS;
03017 }
03018
03019 if (h -> inner && h -> inner -> type -> set_value)
03020 return (*(h -> inner -> type -> set_value))
03021 (h -> inner, id, name, value);
03022 return ISC_R_NOTFOUND;
03023 }
03024
03025 void dhcp_failover_keepalive (void *vs)
03026 {
03027 }
03028
03029 void dhcp_failover_reconnect (void *vs)
03030 {
03031 dhcp_failover_state_t *state = vs;
03032 isc_result_t status;
03033 struct timeval tv;
03034
03035 #if defined (DEBUG_FAILOVER_TIMING)
03036 log_info ("dhcp_failover_reconnect");
03037 #endif
03038
03039
03040 if (state -> link_to_peer)
03041 return;
03042
03043 status = dhcp_failover_link_initiate ((omapi_object_t *)state);
03044 if (status != ISC_R_SUCCESS && status != DHCP_R_INCOMPLETE) {
03045 log_info ("failover peer %s: %s", state -> name,
03046 isc_result_totext (status));
03047 #if defined (DEBUG_FAILOVER_TIMING)
03048 log_info("add_timeout +90 dhcp_failover_reconnect");
03049 #endif
03050 tv . tv_sec = cur_time + 90;
03051 tv . tv_usec = 0;
03052 add_timeout(&tv, dhcp_failover_reconnect, state,
03053 (tvref_t)dhcp_failover_state_reference,
03054 (tvunref_t)dhcp_failover_state_dereference);
03055 }
03056 }
03057
03058 void dhcp_failover_startup_timeout (void *vs)
03059 {
03060 dhcp_failover_state_t *state = vs;
03061
03062 #if defined (DEBUG_FAILOVER_TIMING)
03063 log_info ("dhcp_failover_startup_timeout");
03064 #endif
03065
03066 dhcp_failover_state_transition (state, "disconnect");
03067 }
03068
03069 void dhcp_failover_link_startup_timeout (void *vl)
03070 {
03071 dhcp_failover_link_t *link = vl;
03072 omapi_object_t *p;
03073
03074 for (p = (omapi_object_t *)link; p -> inner; p = p -> inner)
03075 ;
03076 for (; p; p = p -> outer)
03077 if (p -> type == omapi_type_connection)
03078 break;
03079 if (p) {
03080 log_info ("failover: link startup timeout");
03081 omapi_disconnect (p, 1);
03082 }
03083 }
03084
03085 void dhcp_failover_listener_restart (void *vs)
03086 {
03087 dhcp_failover_state_t *state = vs;
03088 isc_result_t status;
03089 struct timeval tv;
03090
03091 #if defined (DEBUG_FAILOVER_TIMING)
03092 log_info ("dhcp_failover_listener_restart");
03093 #endif
03094
03095 status = dhcp_failover_listen ((omapi_object_t *)state);
03096 if (status != ISC_R_SUCCESS) {
03097 log_info ("failover peer %s: %s", state -> name,
03098 isc_result_totext (status));
03099 #if defined (DEBUG_FAILOVER_TIMING)
03100 log_info ("add_timeout +90 %s",
03101 "dhcp_failover_listener_restart");
03102 #endif
03103 tv . tv_sec = cur_time + 90;
03104 tv . tv_usec = 0;
03105 add_timeout (&tv,
03106 dhcp_failover_listener_restart, state,
03107 (tvref_t)dhcp_failover_state_reference,
03108 (tvunref_t)dhcp_failover_state_dereference);
03109 }
03110 }
03111
03112 void
03113 dhcp_failover_auto_partner_down(void *vs)
03114 {
03115 dhcp_failover_state_t *state = vs;
03116
03117 #if defined (DEBUG_FAILOVER_TIMING)
03118 log_info("dhcp_failover_auto_partner_down");
03119 #endif
03120
03121 dhcp_failover_set_state(state, partner_down);
03122 }
03123
03124 isc_result_t dhcp_failover_state_get_value (omapi_object_t *h,
03125 omapi_object_t *id,
03126 omapi_data_string_t *name,
03127 omapi_value_t **value)
03128 {
03129 dhcp_failover_state_t *s;
03130 struct option_cache *oc;
03131 struct data_string ds;
03132 isc_result_t status;
03133
03134 if (h -> type != dhcp_type_failover_state)
03135 return DHCP_R_INVALIDARG;
03136 s = (dhcp_failover_state_t *)h;
03137
03138 if (!omapi_ds_strcmp (name, "name")) {
03139 if (s -> name)
03140 return omapi_make_string_value (value,
03141 name, s -> name, MDL);
03142 return ISC_R_NOTFOUND;
03143 } else if (!omapi_ds_strcmp (name, "partner-address")) {
03144 oc = s -> partner.address;
03145 getaddr:
03146 memset (&ds, 0, sizeof ds);
03147 if (!evaluate_option_cache (&ds, (struct packet *)0,
03148 (struct lease *)0,
03149 (struct client_state *)0,
03150 (struct option_state *)0,
03151 (struct option_state *)0,
03152 &global_scope, oc, MDL)) {
03153 return ISC_R_NOTFOUND;
03154 }
03155 status = omapi_make_const_value (value,
03156 name, ds.data, ds.len, MDL);
03157
03158 if (oc == s -> me.address && !s -> server_identifier.len)
03159 data_string_copy (&s -> server_identifier, &ds, MDL);
03160 data_string_forget (&ds, MDL);
03161 return status;
03162 } else if (!omapi_ds_strcmp (name, "local-address")) {
03163 oc = s -> me.address;
03164 goto getaddr;
03165 } else if (!omapi_ds_strcmp (name, "partner-port")) {
03166 return omapi_make_int_value (value, name,
03167 s -> partner.port, MDL);
03168 } else if (!omapi_ds_strcmp (name, "local-port")) {
03169 return omapi_make_int_value (value,
03170 name, s -> me.port, MDL);
03171 } else if (!omapi_ds_strcmp (name, "max-outstanding-updates")) {
03172 return omapi_make_uint_value (value, name,
03173 s -> me.max_flying_updates,
03174 MDL);
03175 } else if (!omapi_ds_strcmp (name, "mclt")) {
03176 return omapi_make_uint_value (value, name, s -> mclt, MDL);
03177 } else if (!omapi_ds_strcmp (name, "load-balance-max-secs")) {
03178 return omapi_make_int_value (value, name,
03179 s -> load_balance_max_secs, MDL);
03180 } else if (!omapi_ds_strcmp (name, "load-balance-hba")) {
03181 if (s -> hba)
03182 return omapi_make_const_value (value, name,
03183 s -> hba, 32, MDL);
03184 return ISC_R_NOTFOUND;
03185 } else if (!omapi_ds_strcmp (name, "partner-state")) {
03186 return omapi_make_uint_value (value, name,
03187 s -> partner.state, MDL);
03188 } else if (!omapi_ds_strcmp (name, "local-state")) {
03189 return omapi_make_uint_value (value, name,
03190 s -> me.state, MDL);
03191 } else if (!omapi_ds_strcmp (name, "partner-stos")) {
03192 return omapi_make_int_value (value, name,
03193 s -> partner.stos, MDL);
03194 } else if (!omapi_ds_strcmp (name, "local-stos")) {
03195 return omapi_make_int_value (value, name,
03196 s -> me.stos, MDL);
03197 } else if (!omapi_ds_strcmp (name, "hierarchy")) {
03198 return omapi_make_uint_value (value, name, s -> i_am, MDL);
03199 } else if (!omapi_ds_strcmp (name, "last-packet-sent")) {
03200 return omapi_make_int_value (value, name,
03201 s -> last_packet_sent, MDL);
03202 } else if (!omapi_ds_strcmp (name, "last-timestamp-received")) {
03203 return omapi_make_int_value (value, name,
03204 s -> last_timestamp_received,
03205 MDL);
03206 } else if (!omapi_ds_strcmp (name, "skew")) {
03207 return omapi_make_int_value (value, name, s -> skew, MDL);
03208 } else if (!omapi_ds_strcmp (name, "max-response-delay")) {
03209 return omapi_make_uint_value (value, name,
03210 s -> me.max_response_delay,
03211 MDL);
03212 } else if (!omapi_ds_strcmp (name, "cur-unacked-updates")) {
03213 return omapi_make_int_value (value, name,
03214 s -> cur_unacked_updates, MDL);
03215 }
03216
03217 if (h -> inner && h -> inner -> type -> get_value)
03218 return (*(h -> inner -> type -> get_value))
03219 (h -> inner, id, name, value);
03220 return ISC_R_NOTFOUND;
03221 }
03222
03223 isc_result_t dhcp_failover_state_destroy (omapi_object_t *h,
03224 const char *file, int line)
03225 {
03226 dhcp_failover_state_t *s;
03227
03228 if (h -> type != dhcp_type_failover_state)
03229 return DHCP_R_INVALIDARG;
03230 s = (dhcp_failover_state_t *)h;
03231
03232 if (s -> link_to_peer)
03233 dhcp_failover_link_dereference (&s -> link_to_peer, file, line);
03234 if (s -> name) {
03235 dfree (s -> name, MDL);
03236 s -> name = (char *)0;
03237 }
03238 if (s -> partner.address)
03239 option_cache_dereference (&s -> partner.address, file, line);
03240 if (s -> me.address)
03241 option_cache_dereference (&s -> me.address, file, line);
03242 if (s -> hba) {
03243 dfree (s -> hba, file, line);
03244 s -> hba = (u_int8_t *)0;
03245 }
03246 if (s -> update_queue_head)
03247 lease_dereference (&s -> update_queue_head, file, line);
03248 if (s -> update_queue_tail)
03249 lease_dereference (&s -> update_queue_tail, file, line);
03250 if (s -> ack_queue_head)
03251 lease_dereference (&s -> ack_queue_head, file, line);
03252 if (s -> ack_queue_tail)
03253 lease_dereference (&s -> ack_queue_tail, file, line);
03254 if (s -> send_update_done)
03255 lease_dereference (&s -> send_update_done, file, line);
03256 if (s -> toack_queue_head)
03257 failover_message_dereference (&s -> toack_queue_head,
03258 file, line);
03259 if (s -> toack_queue_tail)
03260 failover_message_dereference (&s -> toack_queue_tail,
03261 file, line);
03262 return ISC_R_SUCCESS;
03263 }
03264
03265
03266
03267
03268 isc_result_t dhcp_failover_state_stuff (omapi_object_t *c,
03269 omapi_object_t *id,
03270 omapi_object_t *h)
03271 {
03272
03273
03274 dhcp_failover_state_t *s;
03275 isc_result_t status;
03276
03277 if (c -> type != omapi_type_connection)
03278 return DHCP_R_INVALIDARG;
03279
03280 if (h -> type != dhcp_type_failover_state)
03281 return DHCP_R_INVALIDARG;
03282 s = (dhcp_failover_state_t *)h;
03283
03284 status = omapi_connection_put_name (c, "name");
03285 if (status != ISC_R_SUCCESS)
03286 return status;
03287 status = omapi_connection_put_string (c, s -> name);
03288 if (status != ISC_R_SUCCESS)
03289 return status;
03290
03291 status = omapi_connection_put_name (c, "partner-address");
03292 if (status != ISC_R_SUCCESS)
03293 return status;
03294 status = omapi_connection_put_uint32 (c, sizeof s -> partner.address);
03295 if (status != ISC_R_SUCCESS)
03296 return status;
03297 status = omapi_connection_copyin (c, (u_int8_t *)&s -> partner.address,
03298 sizeof s -> partner.address);
03299 if (status != ISC_R_SUCCESS)
03300 return status;
03301
03302 status = omapi_connection_put_name (c, "partner-port");
03303 if (status != ISC_R_SUCCESS)
03304 return status;
03305 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03306 if (status != ISC_R_SUCCESS)
03307 return status;
03308 status = omapi_connection_put_uint32 (c, (u_int32_t)s -> partner.port);
03309 if (status != ISC_R_SUCCESS)
03310 return status;
03311
03312 status = omapi_connection_put_name (c, "local-address");
03313 if (status != ISC_R_SUCCESS)
03314 return status;
03315 status = omapi_connection_put_uint32 (c, sizeof s -> me.address);
03316 if (status != ISC_R_SUCCESS)
03317 return status;
03318 status = omapi_connection_copyin (c, (u_int8_t *)&s -> me.address,
03319 sizeof s -> me.address);
03320 if (status != ISC_R_SUCCESS)
03321 return status;
03322
03323 status = omapi_connection_put_name (c, "local-port");
03324 if (status != ISC_R_SUCCESS)
03325 return status;
03326 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03327 if (status != ISC_R_SUCCESS)
03328 return status;
03329 status = omapi_connection_put_uint32 (c, (u_int32_t)s -> me.port);
03330 if (status != ISC_R_SUCCESS)
03331 return status;
03332
03333 status = omapi_connection_put_name (c, "max-outstanding-updates");
03334 if (status != ISC_R_SUCCESS)
03335 return status;
03336 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03337 if (status != ISC_R_SUCCESS)
03338 return status;
03339 status = omapi_connection_put_uint32 (c,
03340 s -> me.max_flying_updates);
03341 if (status != ISC_R_SUCCESS)
03342 return status;
03343
03344 status = omapi_connection_put_name (c, "mclt");
03345 if (status != ISC_R_SUCCESS)
03346 return status;
03347 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03348 if (status != ISC_R_SUCCESS)
03349 return status;
03350 status = omapi_connection_put_uint32 (c, s -> mclt);
03351 if (status != ISC_R_SUCCESS)
03352 return status;
03353
03354 status = omapi_connection_put_name (c, "load-balance-max-secs");
03355 if (status != ISC_R_SUCCESS)
03356 return status;
03357 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03358 if (status != ISC_R_SUCCESS)
03359 return status;
03360 status = (omapi_connection_put_uint32
03361 (c, (u_int32_t)s -> load_balance_max_secs));
03362 if (status != ISC_R_SUCCESS)
03363 return status;
03364
03365
03366 if (s -> hba) {
03367 status = omapi_connection_put_name (c, "load-balance-hba");
03368 if (status != ISC_R_SUCCESS)
03369 return status;
03370 status = omapi_connection_put_uint32 (c, 32);
03371 if (status != ISC_R_SUCCESS)
03372 return status;
03373 status = omapi_connection_copyin (c, s -> hba, 32);
03374 if (status != ISC_R_SUCCESS)
03375 return status;
03376 }
03377
03378 status = omapi_connection_put_name (c, "partner-state");
03379 if (status != ISC_R_SUCCESS)
03380 return status;
03381 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03382 if (status != ISC_R_SUCCESS)
03383 return status;
03384 status = omapi_connection_put_uint32 (c, s -> partner.state);
03385 if (status != ISC_R_SUCCESS)
03386 return status;
03387
03388 status = omapi_connection_put_name (c, "local-state");
03389 if (status != ISC_R_SUCCESS)
03390 return status;
03391 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03392 if (status != ISC_R_SUCCESS)
03393 return status;
03394 status = omapi_connection_put_uint32 (c, s -> me.state);
03395 if (status != ISC_R_SUCCESS)
03396 return status;
03397
03398 status = omapi_connection_put_name (c, "partner-stos");
03399 if (status != ISC_R_SUCCESS)
03400 return status;
03401 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03402 if (status != ISC_R_SUCCESS)
03403 return status;
03404 status = omapi_connection_put_uint32 (c,
03405 (u_int32_t)s -> partner.stos);
03406 if (status != ISC_R_SUCCESS)
03407 return status;
03408
03409 status = omapi_connection_put_name (c, "local-stos");
03410 if (status != ISC_R_SUCCESS)
03411 return status;
03412 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03413 if (status != ISC_R_SUCCESS)
03414 return status;
03415 status = omapi_connection_put_uint32 (c, (u_int32_t)s -> me.stos);
03416 if (status != ISC_R_SUCCESS)
03417 return status;
03418
03419 status = omapi_connection_put_name (c, "hierarchy");
03420 if (status != ISC_R_SUCCESS)
03421 return status;
03422 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03423 if (status != ISC_R_SUCCESS)
03424 return status;
03425 status = omapi_connection_put_uint32 (c, s -> i_am);
03426 if (status != ISC_R_SUCCESS)
03427 return status;
03428
03429 status = omapi_connection_put_name (c, "last-packet-sent");
03430 if (status != ISC_R_SUCCESS)
03431 return status;
03432 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03433 if (status != ISC_R_SUCCESS)
03434 return status;
03435 status = (omapi_connection_put_uint32
03436 (c, (u_int32_t)s -> last_packet_sent));
03437 if (status != ISC_R_SUCCESS)
03438 return status;
03439
03440 status = omapi_connection_put_name (c, "last-timestamp-received");
03441 if (status != ISC_R_SUCCESS)
03442 return status;
03443 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03444 if (status != ISC_R_SUCCESS)
03445 return status;
03446 status = (omapi_connection_put_uint32
03447 (c, (u_int32_t)s -> last_timestamp_received));
03448 if (status != ISC_R_SUCCESS)
03449 return status;
03450
03451 status = omapi_connection_put_name (c, "skew");
03452 if (status != ISC_R_SUCCESS)
03453 return status;
03454 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03455 if (status != ISC_R_SUCCESS)
03456 return status;
03457 status = omapi_connection_put_uint32 (c, (u_int32_t)s -> skew);
03458 if (status != ISC_R_SUCCESS)
03459 return status;
03460
03461 status = omapi_connection_put_name (c, "max-response-delay");
03462 if (status != ISC_R_SUCCESS)
03463 return status;
03464 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03465 if (status != ISC_R_SUCCESS)
03466 return status;
03467 status = (omapi_connection_put_uint32
03468 (c, (u_int32_t)s -> me.max_response_delay));
03469 if (status != ISC_R_SUCCESS)
03470 return status;
03471
03472 status = omapi_connection_put_name (c, "cur-unacked-updates");
03473 if (status != ISC_R_SUCCESS)
03474 return status;
03475 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
03476 if (status != ISC_R_SUCCESS)
03477 return status;
03478 status = (omapi_connection_put_uint32
03479 (c, (u_int32_t)s -> cur_unacked_updates));
03480 if (status != ISC_R_SUCCESS)
03481 return status;
03482
03483 if (h -> inner && h -> inner -> type -> stuff_values)
03484 return (*(h -> inner -> type -> stuff_values)) (c, id,
03485 h -> inner);
03486 return ISC_R_SUCCESS;
03487 }
03488
03489 isc_result_t dhcp_failover_state_lookup (omapi_object_t **sp,
03490 omapi_object_t *id,
03491 omapi_object_t *ref)
03492 {
03493 omapi_value_t *tv = (omapi_value_t *)0;
03494 isc_result_t status;
03495 dhcp_failover_state_t *s;
03496
03497 if (!ref)
03498 return DHCP_R_NOKEYS;
03499
03500
03501 status = omapi_get_value_str (ref, id, "handle", &tv);
03502 if (status == ISC_R_SUCCESS) {
03503 status = omapi_handle_td_lookup (sp, tv -> value);
03504
03505 omapi_value_dereference (&tv, MDL);
03506 if (status != ISC_R_SUCCESS)
03507 return status;
03508
03509
03510 if ((*sp) -> type != dhcp_type_failover_state) {
03511 omapi_object_dereference (sp, MDL);
03512 return DHCP_R_INVALIDARG;
03513 }
03514 }
03515
03516
03517 status = omapi_get_value_str (ref, id, "name", &tv);
03518 if (status == ISC_R_SUCCESS) {
03519 for (s = failover_states; s; s = s -> next) {
03520 unsigned l = strlen (s -> name);
03521 if (l == tv -> value -> u.buffer.len &&
03522 !memcmp (s -> name,
03523 tv -> value -> u.buffer.value, l))
03524 break;
03525 }
03526 omapi_value_dereference (&tv, MDL);
03527
03528
03529
03530 if (*sp && *sp != (omapi_object_t *)s) {
03531 omapi_object_dereference (sp, MDL);
03532 return DHCP_R_KEYCONFLICT;
03533 } else if (!s) {
03534 if (*sp)
03535 omapi_object_dereference (sp, MDL);
03536 return ISC_R_NOTFOUND;
03537 } else if (!*sp)
03538
03539
03540 omapi_object_reference (sp, (omapi_object_t *)s, MDL);
03541 }
03542
03543
03544
03545 if (!*sp)
03546 return DHCP_R_NOKEYS;
03547 return ISC_R_SUCCESS;
03548 }
03549
03550 isc_result_t dhcp_failover_state_create (omapi_object_t **sp,
03551 omapi_object_t *id)
03552 {
03553 return ISC_R_NOTIMPLEMENTED;
03554 }
03555
03556 isc_result_t dhcp_failover_state_remove (omapi_object_t *sp,
03557 omapi_object_t *id)
03558 {
03559 return ISC_R_NOTIMPLEMENTED;
03560 }
03561
03562 int dhcp_failover_state_match (dhcp_failover_state_t *state,
03563 u_int8_t *addr, unsigned addrlen)
03564 {
03565 struct data_string ds;
03566 int i;
03567
03568 memset (&ds, 0, sizeof ds);
03569 if (evaluate_option_cache (&ds, (struct packet *)0,
03570 (struct lease *)0,
03571 (struct client_state *)0,
03572 (struct option_state *)0,
03573 (struct option_state *)0,
03574 &global_scope,
03575 state -> partner.address, MDL)) {
03576 for (i = 0; i + addrlen - 1 < ds.len; i += addrlen) {
03577 if (!memcmp (&ds.data [i],
03578 addr, addrlen)) {
03579 data_string_forget (&ds, MDL);
03580 return 1;
03581 }
03582 }
03583 data_string_forget (&ds, MDL);
03584 }
03585 return 0;
03586 }
03587
03588 int
03589 dhcp_failover_state_match_by_name(state, name)
03590 dhcp_failover_state_t *state;
03591 failover_option_t *name;
03592 {
03593 if ((strlen(state->name) == name->count) &&
03594 (memcmp(state->name, name->data, name->count) == 0))
03595 return 1;
03596
03597 return 0;
03598 }
03599
03600 const char *dhcp_failover_reject_reason_print (int reason)
03601 {
03602 static char resbuf[sizeof("Undefined-255: This reason code is not defined "
03603 "in the protocol standard.")];
03604
03605 if ((reason > 0xff) || (reason < 0))
03606 return "Reason code out of range.";
03607
03608 switch (reason) {
03609 case FTR_ILLEGAL_IP_ADDR:
03610 return "Illegal IP address (not part of any address pool).";
03611
03612 case FTR_FATAL_CONFLICT:
03613 return "Fatal conflict exists: address in use by other client.";
03614
03615 case FTR_MISSING_BINDINFO:
03616 return "Missing binding information.";
03617
03618 case FTR_TIMEMISMATCH:
03619 return "Connection rejected, time mismatch too great.";
03620
03621 case FTR_INVALID_MCLT:
03622 return "Connection rejected, invalid MCLT.";
03623
03624 case FTR_MISC_REJECT:
03625 return "Connection rejected, unknown reason.";
03626
03627 case FTR_DUP_CONNECTION:
03628 return "Connection rejected, duplicate connection.";
03629
03630 case FTR_INVALID_PARTNER:
03631 return "Connection rejected, invalid failover partner.";
03632
03633 case FTR_TLS_UNSUPPORTED:
03634 return "TLS not supported.";
03635
03636 case FTR_TLS_UNCONFIGURED:
03637 return "TLS supported but not configured.";
03638
03639 case FTR_TLS_REQUIRED:
03640 return "TLS required but not supported by partner.";
03641
03642 case FTR_DIGEST_UNSUPPORTED:
03643 return "Message digest not supported.";
03644
03645 case FTR_DIGEST_UNCONFIGURED:
03646 return "Message digest not configured.";
03647
03648 case FTR_VERSION_MISMATCH:
03649 return "Protocol version mismatch.";
03650
03651 case FTR_OUTDATED_BIND_INFO:
03652 return "Outdated binding information.";
03653
03654 case FTR_LESS_CRIT_BIND_INFO:
03655 return "Less critical binding information.";
03656
03657 case FTR_NO_TRAFFIC:
03658 return "No traffic within sufficient time.";
03659
03660 case FTR_HBA_CONFLICT:
03661 return "Hash bucket assignment conflict.";
03662
03663 case FTR_IP_NOT_RESERVED:
03664 return "IP not reserved on this server.";
03665
03666 case FTR_IP_DIGEST_FAILURE:
03667 return "Message digest failed to compare.";
03668
03669 case FTR_IP_MISSING_DIGEST:
03670 return "Missing message digest.";
03671
03672 case FTR_UNKNOWN:
03673 return "Unknown Error.";
03674
03675 default:
03676 sprintf(resbuf, "Undefined-%d: This reason code is not defined in the "
03677 "protocol standard.", reason);
03678 return resbuf;
03679 }
03680 }
03681
03682 const char *dhcp_failover_state_name_print (enum failover_state state)
03683 {
03684 switch (state) {
03685 default:
03686 case unknown_state:
03687 return "unknown-state";
03688
03689 case partner_down:
03690 return "partner-down";
03691
03692 case normal:
03693 return "normal";
03694
03695 case conflict_done:
03696 return "conflict-done";
03697
03698 case communications_interrupted:
03699 return "communications-interrupted";
03700
03701 case resolution_interrupted:
03702 return "resolution-interrupted";
03703
03704 case potential_conflict:
03705 return "potential-conflict";
03706
03707 case recover:
03708 return "recover";
03709
03710 case recover_done:
03711 return "recover-done";
03712
03713 case recover_wait:
03714 return "recover-wait";
03715
03716 case shut_down:
03717 return "shutdown";
03718
03719 case paused:
03720 return "paused";
03721
03722 case startup:
03723 return "startup";
03724 }
03725 }
03726
03727 const char *dhcp_failover_message_name (unsigned type)
03728 {
03729 static char messbuf[sizeof("unknown-message-255")];
03730
03731 if (type > 0xff)
03732 return "invalid-message";
03733
03734 switch (type) {
03735 case FTM_POOLREQ:
03736 return "pool-request";
03737
03738 case FTM_POOLRESP:
03739 return "pool-response";
03740
03741 case FTM_BNDUPD:
03742 return "bind-update";
03743
03744 case FTM_BNDACK:
03745 return "bind-ack";
03746
03747 case FTM_CONNECT:
03748 return "connect";
03749
03750 case FTM_CONNECTACK:
03751 return "connect-ack";
03752
03753 case FTM_UPDREQ:
03754 return "update-request";
03755
03756 case FTM_UPDDONE:
03757 return "update-done";
03758
03759 case FTM_UPDREQALL:
03760 return "update-request-all";
03761
03762 case FTM_STATE:
03763 return "state";
03764
03765 case FTM_CONTACT:
03766 return "contact";
03767
03768 case FTM_DISCONNECT:
03769 return "disconnect";
03770
03771 default:
03772 sprintf(messbuf, "unknown-message-%u", type);
03773 return messbuf;
03774 }
03775 }
03776
03777 const char *dhcp_failover_option_name (unsigned type)
03778 {
03779 static char optbuf[sizeof("unknown-option-65535")];
03780
03781 if (type > 0xffff)
03782 return "invalid-option";
03783
03784 switch (type) {
03785 case FTO_ADDRESSES_TRANSFERRED:
03786 return "addresses-transferred";
03787
03788 case FTO_ASSIGNED_IP_ADDRESS:
03789 return "assigned-ip-address";
03790
03791 case FTO_BINDING_STATUS:
03792 return "binding-status";
03793
03794 case FTO_CLIENT_IDENTIFIER:
03795 return "client-identifier";
03796
03797 case FTO_CHADDR:
03798 return "chaddr";
03799
03800 case FTO_CLTT:
03801 return "cltt";
03802
03803 case FTO_DDNS:
03804 return "ddns";
03805
03806 case FTO_DELAYED_SERVICE:
03807 return "delayed-service";
03808
03809 case FTO_HBA:
03810 return "hba";
03811
03812 case FTO_IP_FLAGS:
03813 return "ip-flags";
03814
03815 case FTO_LEASE_EXPIRY:
03816 return "lease-expiry";
03817
03818 case FTO_MAX_UNACKED:
03819 return "max-unacked";
03820
03821 case FTO_MCLT:
03822 return "mclt";
03823
03824 case FTO_MESSAGE:
03825 return "message";
03826
03827 case FTO_MESSAGE_DIGEST:
03828 return "message-digest";
03829
03830 case FTO_POTENTIAL_EXPIRY:
03831 return "potential-expiry";
03832
03833 case FTO_PROTOCOL_VERSION:
03834 return "protocol-version";
03835
03836 case FTO_RECEIVE_TIMER:
03837 return "receive-timer";
03838
03839 case FTO_REJECT_REASON:
03840 return "reject-reason";
03841
03842 case FTO_RELATIONSHIP_NAME:
03843 return "relationship-name";
03844
03845 case FTO_REPLY_OPTIONS:
03846 return "reply-options";
03847
03848 case FTO_REQUEST_OPTIONS:
03849 return "request-options";
03850
03851 case FTO_SERVER_FLAGS:
03852 return "server-flags";
03853
03854 case FTO_SERVER_STATE:
03855 return "server-state";
03856
03857 case FTO_STOS:
03858 return "stos";
03859
03860 case FTO_TLS_REPLY:
03861 return "tls-reply";
03862
03863 case FTO_TLS_REQUEST:
03864 return "tls-request";
03865
03866 case FTO_VENDOR_CLASS:
03867 return "vendor-class";
03868
03869 case FTO_VENDOR_OPTIONS:
03870 return "vendor-options";
03871
03872 default:
03873 sprintf(optbuf, "unknown-option-%u", type);
03874 return optbuf;
03875 }
03876 }
03877
03878 failover_option_t *dhcp_failover_option_printf (unsigned code,
03879 char *obuf,
03880 unsigned *obufix,
03881 unsigned obufmax,
03882 const char *fmt, ...)
03883 {
03884 va_list va;
03885 char tbuf [256];
03886
03887
03888
03889
03890
03891
03892
03893
03894 va_start (va, fmt);
03895 if (vsnprintf (tbuf, sizeof tbuf, fmt, va) >= sizeof tbuf)
03896 log_fatal ("%s: vsnprintf would truncate",
03897 "dhcp_failover_make_option");
03898 va_end (va);
03899
03900 return dhcp_failover_make_option (code, obuf, obufix, obufmax,
03901 strlen (tbuf), tbuf);
03902 }
03903
03904 failover_option_t *dhcp_failover_make_option (unsigned code,
03905 char *obuf, unsigned *obufix,
03906 unsigned obufmax, ...)
03907 {
03908 va_list va;
03909 struct failover_option_info *info;
03910 int i;
03911 unsigned size, count;
03912 unsigned val;
03913 u_int8_t *iaddr;
03914 unsigned ilen = 0;
03915 u_int8_t *bval;
03916 char *txt = NULL;
03917 #if defined (DEBUG_FAILOVER_MESSAGES)
03918 char tbuf [256];
03919 #endif
03920
03921
03922
03923
03924
03925 failover_option_t option, *op;
03926
03927
03928
03929 if (code < 1 || code > FTO_MAX || ft_options [code].type == FT_UNDEF) {
03930 return &null_failover_option;
03931 }
03932 info = &ft_options [code];
03933
03934 va_start (va, obufmax);
03935
03936
03937
03938 if (info -> type == FT_DDNS || info -> type == FT_DDNS1) {
03939 count = info -> type == FT_DDNS ? 1 : 2;
03940 size = va_arg (va, int) + count;
03941 } else {
03942
03943 if (info -> num_present)
03944 count = info -> num_present;
03945 else
03946 count = va_arg (va, int);
03947
03948
03949 switch (info -> type) {
03950 case FT_UINT8:
03951 case FT_BYTES:
03952 case FT_DIGEST:
03953 size = count;
03954 break;
03955
03956 case FT_TEXT_OR_BYTES:
03957 case FT_TEXT:
03958 txt = va_arg (va, char *);
03959 size = count;
03960 break;
03961
03962 case FT_IPADDR:
03963 ilen = va_arg (va, unsigned);
03964 size = count * ilen;
03965 break;
03966
03967 case FT_UINT32:
03968 size = count * 4;
03969 break;
03970
03971 case FT_UINT16:
03972 size = count * 2;
03973 break;
03974
03975 default:
03976
03977 log_fatal ("bogus type in failover_make_option: %d",
03978 info -> type);
03979 return &null_failover_option;
03980 }
03981 }
03982
03983 size += 4;
03984
03985
03986 option.count = size;
03987 option.data = dmalloc (option.count, MDL);
03988 if (!option.data) {
03989 va_end (va);
03990 return &null_failover_option;
03991 }
03992
03993
03994 putUShort (option.data, code);
03995 putUShort (&option.data [2], size - 4);
03996
03997 #if defined (DEBUG_FAILOVER_MESSAGES)
03998
03999
04000
04001
04002
04003
04004
04005 if (snprintf (tbuf, sizeof tbuf, " (%s<%d>", info -> name,
04006 option.count) >= sizeof tbuf)
04007 log_fatal ("dhcp_failover_make_option: tbuf overflow");
04008 failover_print (obuf, obufix, obufmax, tbuf);
04009 #endif
04010
04011
04012 switch (info -> type) {
04013 case FT_UINT8:
04014 for (i = 0; i < count; i++) {
04015 val = va_arg (va, unsigned);
04016 #if defined (DEBUG_FAILOVER_MESSAGES)
04017
04018 sprintf (tbuf, " %d", val);
04019 failover_print (obuf, obufix, obufmax, tbuf);
04020 #endif
04021 option.data [i + 4] = val;
04022 }
04023 break;
04024
04025 case FT_IPADDR:
04026 for (i = 0; i < count; i++) {
04027 iaddr = va_arg (va, u_int8_t *);
04028 if (ilen != 4) {
04029 dfree (option.data, MDL);
04030 log_error ("IP addrlen=%d, should be 4.",
04031 ilen);
04032 va_end (va);
04033 return &null_failover_option;
04034 }
04035
04036 #if defined (DEBUG_FAILOVER_MESSAGES)
04037
04038 sprintf (tbuf, " %u.%u.%u.%u",
04039 iaddr [0], iaddr [1], iaddr [2], iaddr [3]);
04040 failover_print (obuf, obufix, obufmax, tbuf);
04041 #endif
04042 memcpy (&option.data [4 + i * ilen], iaddr, ilen);
04043 }
04044 break;
04045
04046 case FT_UINT32:
04047 for (i = 0; i < count; i++) {
04048 val = va_arg (va, unsigned);
04049 #if defined (DEBUG_FAILOVER_MESSAGES)
04050
04051 sprintf (tbuf, " %d", val);
04052 failover_print (obuf, obufix, obufmax, tbuf);
04053 #endif
04054 putULong (&option.data [4 + i * 4], val);
04055 }
04056 break;
04057
04058 case FT_BYTES:
04059 case FT_DIGEST:
04060 bval = va_arg (va, u_int8_t *);
04061 #if defined (DEBUG_FAILOVER_MESSAGES)
04062 for (i = 0; i < count; i++) {
04063
04064 sprintf (tbuf, " %d", bval [i]);
04065 failover_print (obuf, obufix, obufmax, tbuf);
04066 }
04067 #endif
04068 memcpy (&option.data [4], bval, count);
04069 break;
04070
04071
04072
04073
04074
04075 case FT_TEXT_OR_BYTES:
04076 case FT_TEXT:
04077 #if defined (DEBUG_FAILOVER_MESSAGES)
04078
04079
04080
04081
04082
04083
04084
04085 if (snprintf (tbuf, sizeof tbuf, "\"%s\"", txt) >= sizeof tbuf)
04086 log_fatal ("dhcp_failover_make_option: tbuf overflow");
04087 failover_print (obuf, obufix, obufmax, tbuf);
04088 #endif
04089 memcpy (&option.data [4], txt, count);
04090 break;
04091
04092 case FT_DDNS:
04093 case FT_DDNS1:
04094 option.data [4] = va_arg (va, unsigned);
04095 if (count == 2)
04096 option.data [5] = va_arg (va, unsigned);
04097 bval = va_arg (va, u_int8_t *);
04098 memcpy (&option.data [4 + count], bval, size - count - 4);
04099 #if defined (DEBUG_FAILOVER_MESSAGES)
04100 for (i = 4; i < size; i++) {
04101
04102 sprintf (tbuf, " %d", option.data [i]);
04103 failover_print (obuf, obufix, obufmax, tbuf);
04104 }
04105 #endif
04106 break;
04107
04108 case FT_UINT16:
04109 for (i = 0; i < count; i++) {
04110 val = va_arg (va, u_int32_t);
04111 #if defined (DEBUG_FAILOVER_MESSAGES)
04112
04113 sprintf (tbuf, " %d", val);
04114 failover_print (obuf, obufix, obufmax, tbuf);
04115 #endif
04116 putUShort (&option.data [4 + i * 2], val);
04117 }
04118 break;
04119
04120 case FT_UNDEF:
04121 default:
04122 break;
04123 }
04124
04125 #if defined DEBUG_FAILOVER_MESSAGES
04126 failover_print (obuf, obufix, obufmax, ")");
04127 #endif
04128 va_end (va);
04129
04130
04131 op = dmalloc (sizeof (failover_option_t), MDL);
04132 if (!op) {
04133 dfree (option.data, MDL);
04134 return &null_failover_option;
04135 }
04136
04137 *op = option;
04138 return op;
04139 }
04140
04141
04142
04143 isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *link,
04144 omapi_object_t *connection,
04145 int msg_type, u_int32_t xid, ...)
04146 {
04147 unsigned size = 0;
04148 int bad_option = 0;
04149 int opix = 0;
04150 va_list list;
04151 failover_option_t *option;
04152 unsigned char *opbuf;
04153 isc_result_t status = ISC_R_SUCCESS;
04154 unsigned char cbuf;
04155 struct timeval tv;
04156
04157
04158
04159 va_start (list, xid);
04160 while ((option = va_arg (list, failover_option_t *))) {
04161 if (option != &skip_failover_option)
04162 size += option -> count;
04163 if (option == &null_failover_option)
04164 bad_option = 1;
04165 }
04166 va_end (list);
04167
04168
04169 if (!bad_option && size) {
04170 opbuf = dmalloc (size, MDL);
04171 if (!opbuf)
04172 status = ISC_R_NOMEMORY;
04173 } else
04174 opbuf = (unsigned char *)0;
04175
04176 va_start (list, xid);
04177 while ((option = va_arg (list, failover_option_t *))) {
04178 if (option == &skip_failover_option)
04179 continue;
04180 if (!bad_option && opbuf)
04181 memcpy (&opbuf [opix],
04182 option -> data, option -> count);
04183 if (option != &null_failover_option &&
04184 option != &skip_failover_option) {
04185 opix += option -> count;
04186 dfree (option -> data, MDL);
04187 dfree (option, MDL);
04188 }
04189 }
04190 va_end(list);
04191
04192 if (bad_option)
04193 return DHCP_R_INVALIDARG;
04194
04195
04196
04197
04198 status = omapi_connection_put_uint16 (connection, size + 12);
04199 if (status != ISC_R_SUCCESS)
04200 goto err;
04201
04202
04203 cbuf = msg_type;
04204 status = omapi_connection_copyin (connection, &cbuf, 1);
04205 if (status != ISC_R_SUCCESS)
04206 goto err;
04207
04208
04209 cbuf = 12;
04210 status = omapi_connection_copyin (connection, &cbuf, 1);
04211 if (status != ISC_R_SUCCESS)
04212 goto err;
04213
04214
04215 status = omapi_connection_put_uint32 (connection, (u_int32_t)cur_time);
04216 if (status != ISC_R_SUCCESS)
04217 goto err;
04218
04219
04220 status = omapi_connection_put_uint32(connection, xid);
04221 if (status != ISC_R_SUCCESS)
04222 goto err;
04223
04224
04225 if (opbuf) {
04226 status = omapi_connection_copyin (connection, opbuf, size);
04227 if (status != ISC_R_SUCCESS)
04228 goto err;
04229 dfree (opbuf, MDL);
04230 }
04231 if (link -> state_object &&
04232 link -> state_object -> link_to_peer == link) {
04233 #if defined (DEBUG_FAILOVER_CONTACT_TIMING)
04234 log_info ("add_timeout +%d %s",
04235 (int)(link -> state_object ->
04236 partner.max_response_delay) / 3,
04237 "dhcp_failover_send_contact");
04238 #endif
04239 tv . tv_sec = cur_time +
04240 (int)(link -> state_object ->
04241 partner.max_response_delay) / 3;
04242 tv . tv_usec = 0;
04243 add_timeout (&tv,
04244 dhcp_failover_send_contact, link -> state_object,
04245 (tvref_t)dhcp_failover_state_reference,
04246 (tvunref_t)dhcp_failover_state_dereference);
04247 }
04248 return status;
04249
04250 err:
04251 if (opbuf)
04252 dfree (opbuf, MDL);
04253 log_info ("dhcp_failover_put_message: something went wrong.");
04254 omapi_disconnect (connection, 1);
04255 return status;
04256 }
04257
04258 void dhcp_failover_timeout (void *vstate)
04259 {
04260 dhcp_failover_state_t *state = vstate;
04261 dhcp_failover_link_t *link;
04262
04263 #if defined (DEBUG_FAILOVER_TIMING)
04264 log_info ("dhcp_failover_timeout");
04265 #endif
04266
04267 if (!state || state -> type != dhcp_type_failover_state)
04268 return;
04269 link = state -> link_to_peer;
04270 if (!link ||
04271 !link -> outer ||
04272 link -> outer -> type != omapi_type_connection)
04273 return;
04274
04275 log_error ("timeout waiting for failover peer %s", state -> name);
04276
04277
04278
04279 omapi_disconnect (link -> outer, 1);
04280 }
04281
04282 void dhcp_failover_send_contact (void *vstate)
04283 {
04284 dhcp_failover_state_t *state = vstate;
04285 dhcp_failover_link_t *link;
04286 isc_result_t status;
04287
04288 #if defined(DEBUG_FAILOVER_MESSAGES) && \
04289 defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
04290 char obuf [64];
04291 unsigned obufix = 0;
04292
04293 failover_print(obuf, &obufix, sizeof(obuf), "(contact");
04294 #endif
04295
04296 #if defined (DEBUG_FAILOVER_CONTACT_TIMING)
04297 log_info ("dhcp_failover_send_contact");
04298 #endif
04299
04300 if (!state || state -> type != dhcp_type_failover_state)
04301 return;
04302 link = state -> link_to_peer;
04303 if (!link ||
04304 !link -> outer ||
04305 link -> outer -> type != omapi_type_connection)
04306 return;
04307
04308 status = (dhcp_failover_put_message
04309 (link, link -> outer,
04310 FTM_CONTACT, link->xid++,
04311 (failover_option_t *)0));
04312
04313 #if defined(DEBUG_FAILOVER_MESSAGES) && \
04314 defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
04315 if (status != ISC_R_SUCCESS)
04316 failover_print(obuf, &obufix, sizeof(obuf), " (failed)");
04317 failover_print(obuf, &obufix, sizeof(obuf), ")");
04318 if (obufix) {
04319 log_debug ("%s", obuf);
04320 }
04321 #else
04322 IGNORE_UNUSED(status);
04323 #endif
04324 return;
04325 }
04326
04327 isc_result_t dhcp_failover_send_state (dhcp_failover_state_t *state)
04328 {
04329 dhcp_failover_link_t *link;
04330 isc_result_t status;
04331
04332 #if defined (DEBUG_FAILOVER_MESSAGES)
04333 char obuf [64];
04334 unsigned obufix = 0;
04335
04336 # define FMA obuf, &obufix, sizeof obuf
04337 failover_print (FMA, "(state");
04338 #else
04339 # define FMA (char *)0, (unsigned *)0, 0
04340 #endif
04341
04342 if (!state || state -> type != dhcp_type_failover_state)
04343 return DHCP_R_INVALIDARG;
04344 link = state -> link_to_peer;
04345 if (!link ||
04346 !link -> outer ||
04347 link -> outer -> type != omapi_type_connection)
04348 return DHCP_R_INVALIDARG;
04349
04350 status = (dhcp_failover_put_message
04351 (link, link -> outer,
04352 FTM_STATE, link->xid++,
04353 dhcp_failover_make_option (FTO_SERVER_STATE, FMA,
04354 (state -> me.state == startup
04355 ? state -> saved_state
04356 : state -> me.state)),
04357 dhcp_failover_make_option
04358 (FTO_SERVER_FLAGS, FMA,
04359 (state -> service_state == service_startup
04360 ? FTF_SERVER_STARTUP : 0)),
04361 dhcp_failover_make_option (FTO_STOS, FMA, state -> me.stos),
04362 (failover_option_t *)0));
04363
04364 #if defined (DEBUG_FAILOVER_MESSAGES)
04365 if (status != ISC_R_SUCCESS)
04366 failover_print (FMA, " (failed)");
04367 failover_print (FMA, ")");
04368 if (obufix) {
04369 log_debug ("%s", obuf);
04370 }
04371 #else
04372 IGNORE_UNUSED(status);
04373 #endif
04374 return ISC_R_SUCCESS;
04375 }
04376
04377
04378
04379 isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
04380 {
04381 dhcp_failover_link_t *link;
04382 dhcp_failover_state_t *state;
04383 isc_result_t status;
04384 #if defined (DEBUG_FAILOVER_MESSAGES)
04385 char obuf [64];
04386 unsigned obufix = 0;
04387
04388 # define FMA obuf, &obufix, sizeof obuf
04389 failover_print (FMA, "(connect");
04390 #else
04391 # define FMA (char *)0, (unsigned *)0, 0
04392 #endif
04393
04394 if (!l || l -> type != dhcp_type_failover_link)
04395 return DHCP_R_INVALIDARG;
04396 link = (dhcp_failover_link_t *)l;
04397 state = link -> state_object;
04398 if (!l -> outer || l -> outer -> type != omapi_type_connection)
04399 return DHCP_R_INVALIDARG;
04400
04401 status =
04402 (dhcp_failover_put_message
04403 (link, l -> outer,
04404 FTM_CONNECT, link->xid++,
04405 dhcp_failover_make_option(FTO_RELATIONSHIP_NAME, FMA,
04406 strlen(state->name), state->name),
04407 dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
04408 state -> me.max_flying_updates),
04409 dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA,
04410 state -> me.max_response_delay),
04411 dhcp_failover_option_printf(FTO_VENDOR_CLASS, FMA,
04412 "isc-%s", PACKAGE_VERSION),
04413 dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA,
04414 DHCP_FAILOVER_VERSION),
04415 dhcp_failover_make_option (FTO_TLS_REQUEST, FMA,
04416 0, 0),
04417 dhcp_failover_make_option (FTO_MCLT, FMA,
04418 state -> mclt),
04419 (state -> hba
04420 ? dhcp_failover_make_option (FTO_HBA, FMA, 32, state -> hba)
04421 : &skip_failover_option),
04422 (failover_option_t *)0));
04423
04424 #if defined (DEBUG_FAILOVER_MESSAGES)
04425 if (status != ISC_R_SUCCESS)
04426 failover_print (FMA, " (failed)");
04427 failover_print (FMA, ")");
04428 if (obufix) {
04429 log_debug ("%s", obuf);
04430 }
04431 #endif
04432 return status;
04433 }
04434
04435 isc_result_t dhcp_failover_send_connectack (omapi_object_t *l,
04436 dhcp_failover_state_t *state,
04437 int reason, const char *errmsg)
04438 {
04439 dhcp_failover_link_t *link;
04440 isc_result_t status;
04441 #if defined (DEBUG_FAILOVER_MESSAGES)
04442 char obuf [64];
04443 unsigned obufix = 0;
04444
04445 # define FMA obuf, &obufix, sizeof obuf
04446 failover_print (FMA, "(connectack");
04447 #else
04448 # define FMA (char *)0, (unsigned *)0, 0
04449 #endif
04450
04451 if (!l || l -> type != dhcp_type_failover_link)
04452 return DHCP_R_INVALIDARG;
04453 link = (dhcp_failover_link_t *)l;
04454 if (!l -> outer || l -> outer -> type != omapi_type_connection)
04455 return DHCP_R_INVALIDARG;
04456
04457 status =
04458 (dhcp_failover_put_message
04459 (link, l -> outer,
04460 FTM_CONNECTACK, link->imsg->xid,
04461 state
04462 ? dhcp_failover_make_option(FTO_RELATIONSHIP_NAME, FMA,
04463 strlen(state->name), state->name)
04464 : (link->imsg->options_present & FTB_RELATIONSHIP_NAME)
04465 ? dhcp_failover_make_option(FTO_RELATIONSHIP_NAME, FMA,
04466 link->imsg->relationship_name.count,
04467 link->imsg->relationship_name.data)
04468 : &skip_failover_option,
04469 state
04470 ? dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
04471 state -> me.max_flying_updates)
04472 : &skip_failover_option,
04473 state
04474 ? dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA,
04475 state -> me.max_response_delay)
04476 : &skip_failover_option,
04477 dhcp_failover_option_printf(FTO_VENDOR_CLASS, FMA,
04478 "isc-%s", PACKAGE_VERSION),
04479 dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA,
04480 DHCP_FAILOVER_VERSION),
04481 (link->imsg->options_present & FTB_TLS_REQUEST)
04482 ? dhcp_failover_make_option(FTO_TLS_REPLY, FMA,
04483 0, 0)
04484 : &skip_failover_option,
04485 reason
04486 ? dhcp_failover_make_option (FTO_REJECT_REASON,
04487 FMA, reason)
04488 : &skip_failover_option,
04489 (reason && errmsg)
04490 ? dhcp_failover_make_option (FTO_MESSAGE, FMA,
04491 strlen (errmsg), errmsg)
04492 : &skip_failover_option,
04493 (failover_option_t *)0));
04494
04495 #if defined (DEBUG_FAILOVER_MESSAGES)
04496 if (status != ISC_R_SUCCESS)
04497 failover_print (FMA, " (failed)");
04498 failover_print (FMA, ")");
04499 if (obufix) {
04500 log_debug ("%s", obuf);
04501 }
04502 #endif
04503 return status;
04504 }
04505
04506 isc_result_t dhcp_failover_send_disconnect (omapi_object_t *l,
04507 int reason,
04508 const char *message)
04509 {
04510 dhcp_failover_link_t *link;
04511 isc_result_t status;
04512 #if defined (DEBUG_FAILOVER_MESSAGES)
04513 char obuf [64];
04514 unsigned obufix = 0;
04515
04516 # define FMA obuf, &obufix, sizeof obuf
04517 failover_print (FMA, "(disconnect");
04518 #else
04519 # define FMA (char *)0, (unsigned *)0, 0
04520 #endif
04521
04522 if (!l || l -> type != dhcp_type_failover_link)
04523 return DHCP_R_INVALIDARG;
04524 link = (dhcp_failover_link_t *)l;
04525 if (!l -> outer || l -> outer -> type != omapi_type_connection)
04526 return DHCP_R_INVALIDARG;
04527
04528 if (!message && reason)
04529 message = dhcp_failover_reject_reason_print (reason);
04530
04531 status = (dhcp_failover_put_message
04532 (link, l -> outer,
04533 FTM_DISCONNECT, link->xid++,
04534 dhcp_failover_make_option (FTO_REJECT_REASON,
04535 FMA, reason),
04536 (message
04537 ? dhcp_failover_make_option (FTO_MESSAGE, FMA,
04538 strlen (message), message)
04539 : &skip_failover_option),
04540 (failover_option_t *)0));
04541
04542 #if defined (DEBUG_FAILOVER_MESSAGES)
04543 if (status != ISC_R_SUCCESS)
04544 failover_print (FMA, " (failed)");
04545 failover_print (FMA, ")");
04546 if (obufix) {
04547 log_debug ("%s", obuf);
04548 }
04549 #endif
04550 return status;
04551 }
04552
04553
04554
04555 isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
04556 struct lease *lease)
04557 {
04558 dhcp_failover_link_t *link;
04559 isc_result_t status;
04560 int flags = 0;
04561 binding_state_t transmit_state;
04562 #if defined (DEBUG_FAILOVER_MESSAGES)
04563 char obuf [64];
04564 unsigned obufix = 0;
04565
04566 # define FMA obuf, &obufix, sizeof obuf
04567 failover_print (FMA, "(bndupd");
04568 #else
04569 # define FMA (char *)0, (unsigned *)0, 0
04570 #endif
04571
04572 if (!state -> link_to_peer ||
04573 state -> link_to_peer -> type != dhcp_type_failover_link)
04574 return DHCP_R_INVALIDARG;
04575 link = (dhcp_failover_link_t *)state -> link_to_peer;
04576
04577 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04578 return DHCP_R_INVALIDARG;
04579
04580 transmit_state = lease->desired_binding_state;
04581 if (lease->flags & RESERVED_LEASE) {
04582
04583
04584
04585
04586
04587 if ((state->i_am == primary) && (transmit_state == FTS_FREE))
04588 transmit_state = FTS_BACKUP;
04589 else if ((state->i_am == secondary) &&
04590 (transmit_state == FTS_BACKUP))
04591 transmit_state = FTS_FREE;
04592
04593 flags |= FTF_IP_FLAG_RESERVE;
04594 }
04595 if (lease->flags & BOOTP_LEASE)
04596 flags |= FTF_IP_FLAG_BOOTP;
04597
04598
04599 if (link->xid == 0)
04600 link->xid = 1;
04601
04602 lease->last_xid = link->xid++;
04603
04604
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615
04616
04617
04618
04619
04620
04621
04622
04623
04624
04625
04626
04627 if (lease->rewind_binding_state != lease->binding_state) {
04628 lease->rewind_binding_state = lease->binding_state;
04629
04630 write_lease(lease);
04631 commit_leases();
04632 }
04633
04634
04635 status = (dhcp_failover_put_message
04636 (link, link -> outer,
04637 FTM_BNDUPD, lease->last_xid,
04638 dhcp_failover_make_option (FTO_ASSIGNED_IP_ADDRESS, FMA,
04639 lease -> ip_addr.len,
04640 lease -> ip_addr.iabuf),
04641 dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
04642 lease -> desired_binding_state),
04643 lease -> uid_len
04644 ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
04645 lease -> uid_len,
04646 lease -> uid)
04647 : &skip_failover_option,
04648 lease -> hardware_addr.hlen
04649 ? dhcp_failover_make_option (FTO_CHADDR, FMA,
04650 lease -> hardware_addr.hlen,
04651 lease -> hardware_addr.hbuf)
04652 : &skip_failover_option,
04653 dhcp_failover_make_option (FTO_LEASE_EXPIRY, FMA,
04654 lease -> ends),
04655 dhcp_failover_make_option (FTO_POTENTIAL_EXPIRY, FMA,
04656 lease -> tstp),
04657 dhcp_failover_make_option (FTO_STOS, FMA,
04658 lease -> starts),
04659 (lease->cltt != 0) ?
04660 dhcp_failover_make_option(FTO_CLTT, FMA, lease->cltt) :
04661 &skip_failover_option,
04662 flags ? dhcp_failover_make_option(FTO_IP_FLAGS, FMA,
04663 flags) :
04664 &skip_failover_option,
04665 &skip_failover_option,
04666 &skip_failover_option,
04667 &skip_failover_option,
04668 (failover_option_t *)0));
04669
04670 #if defined (DEBUG_FAILOVER_MESSAGES)
04671 if (status != ISC_R_SUCCESS)
04672 failover_print (FMA, " (failed)");
04673 failover_print (FMA, ")");
04674 if (obufix) {
04675 log_debug ("%s", obuf);
04676 }
04677 #endif
04678 return status;
04679 }
04680
04681
04682
04683 isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
04684 failover_message_t *msg,
04685 int reason, const char *message)
04686 {
04687 dhcp_failover_link_t *link;
04688 isc_result_t status;
04689 #if defined (DEBUG_FAILOVER_MESSAGES)
04690 char obuf [64];
04691 unsigned obufix = 0;
04692
04693 # define FMA obuf, &obufix, sizeof obuf
04694 failover_print (FMA, "(bndack");
04695 #else
04696 # define FMA (char *)0, (unsigned *)0, 0
04697 #endif
04698
04699 if (!state -> link_to_peer ||
04700 state -> link_to_peer -> type != dhcp_type_failover_link)
04701 return DHCP_R_INVALIDARG;
04702 link = (dhcp_failover_link_t *)state -> link_to_peer;
04703
04704 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04705 return DHCP_R_INVALIDARG;
04706
04707 if (!message && reason)
04708 message = dhcp_failover_reject_reason_print (reason);
04709
04710
04711 status = (dhcp_failover_put_message
04712 (link, link -> outer,
04713 FTM_BNDACK, msg->xid,
04714 dhcp_failover_make_option (FTO_ASSIGNED_IP_ADDRESS, FMA,
04715 sizeof msg -> assigned_addr,
04716 &msg -> assigned_addr),
04717 #ifdef DO_BNDACK_SHOULD_NOT
04718 dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
04719 msg -> binding_status),
04720 (msg -> options_present & FTB_CLIENT_IDENTIFIER)
04721 ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
04722 msg -> client_identifier.count,
04723 msg -> client_identifier.data)
04724 : &skip_failover_option,
04725 (msg -> options_present & FTB_CHADDR)
04726 ? dhcp_failover_make_option (FTO_CHADDR, FMA,
04727 msg -> chaddr.count,
04728 msg -> chaddr.data)
04729 : &skip_failover_option,
04730 dhcp_failover_make_option (FTO_LEASE_EXPIRY, FMA,
04731 msg -> expiry),
04732 dhcp_failover_make_option (FTO_POTENTIAL_EXPIRY, FMA,
04733 msg -> potential_expiry),
04734 dhcp_failover_make_option (FTO_STOS, FMA,
04735 msg -> stos),
04736 (msg->options_present & FTB_CLTT) ?
04737 dhcp_failover_make_option(FTO_CLTT, FMA, msg->cltt) :
04738 &skip_failover_option,
04739 ((msg->options_present & FTB_IP_FLAGS) && msg->ip_flags) ?
04740 dhcp_failover_make_option(FTO_IP_FLAGS, FMA,
04741 msg->ip_flags)
04742 : &skip_failover_option,
04743 #endif
04744 reason
04745 ? dhcp_failover_make_option(FTO_REJECT_REASON, FMA, reason)
04746 : &skip_failover_option,
04747 (reason && message)
04748 ? dhcp_failover_make_option (FTO_MESSAGE, FMA,
04749 strlen (message), message)
04750 : &skip_failover_option,
04751 #ifdef DO_BNDACK_SHOULD_NOT
04752 &skip_failover_option,
04753 &skip_failover_option,
04754 &skip_failover_option,
04755 #endif
04756 (failover_option_t *)0));
04757
04758 #if defined (DEBUG_FAILOVER_MESSAGES)
04759 if (status != ISC_R_SUCCESS)
04760 failover_print (FMA, " (failed)");
04761 failover_print (FMA, ")");
04762 if (obufix) {
04763 log_debug ("%s", obuf);
04764 }
04765 #endif
04766 return status;
04767 }
04768
04769 isc_result_t dhcp_failover_send_poolreq (dhcp_failover_state_t *state)
04770 {
04771 dhcp_failover_link_t *link;
04772 isc_result_t status;
04773 #if defined (DEBUG_FAILOVER_MESSAGES)
04774 char obuf [64];
04775 unsigned obufix = 0;
04776
04777 # define FMA obuf, &obufix, sizeof obuf
04778 failover_print (FMA, "(poolreq");
04779 #else
04780 # define FMA (char *)0, (unsigned *)0, 0
04781 #endif
04782
04783 if (!state -> link_to_peer ||
04784 state -> link_to_peer -> type != dhcp_type_failover_link)
04785 return DHCP_R_INVALIDARG;
04786 link = (dhcp_failover_link_t *)state -> link_to_peer;
04787
04788 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04789 return DHCP_R_INVALIDARG;
04790
04791 status = (dhcp_failover_put_message
04792 (link, link -> outer,
04793 FTM_POOLREQ, link->xid++,
04794 (failover_option_t *)0));
04795
04796 #if defined (DEBUG_FAILOVER_MESSAGES)
04797 if (status != ISC_R_SUCCESS)
04798 failover_print (FMA, " (failed)");
04799 failover_print (FMA, ")");
04800 if (obufix) {
04801 log_debug ("%s", obuf);
04802 }
04803 #endif
04804 return status;
04805 }
04806
04807 isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *state,
04808 int leases)
04809 {
04810 dhcp_failover_link_t *link;
04811 isc_result_t status;
04812 #if defined (DEBUG_FAILOVER_MESSAGES)
04813 char obuf [64];
04814 unsigned obufix = 0;
04815
04816 # define FMA obuf, &obufix, sizeof obuf
04817 failover_print (FMA, "(poolresp");
04818 #else
04819 # define FMA (char *)0, (unsigned *)0, 0
04820 #endif
04821
04822 if (!state -> link_to_peer ||
04823 state -> link_to_peer -> type != dhcp_type_failover_link)
04824 return DHCP_R_INVALIDARG;
04825 link = (dhcp_failover_link_t *)state -> link_to_peer;
04826
04827 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04828 return DHCP_R_INVALIDARG;
04829
04830 status = (dhcp_failover_put_message
04831 (link, link -> outer,
04832 FTM_POOLRESP, link->imsg->xid,
04833 dhcp_failover_make_option (FTO_ADDRESSES_TRANSFERRED, FMA,
04834 leases),
04835 (failover_option_t *)0));
04836
04837 #if defined (DEBUG_FAILOVER_MESSAGES)
04838 if (status != ISC_R_SUCCESS)
04839 failover_print (FMA, " (failed)");
04840 failover_print (FMA, ")");
04841 if (obufix) {
04842 log_debug ("%s", obuf);
04843 }
04844 #endif
04845 return status;
04846 }
04847
04848 isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *state)
04849 {
04850 dhcp_failover_link_t *link;
04851 isc_result_t status;
04852 #if defined (DEBUG_FAILOVER_MESSAGES)
04853 char obuf [64];
04854 unsigned obufix = 0;
04855
04856 # define FMA obuf, &obufix, sizeof obuf
04857 failover_print (FMA, "(updreq");
04858 #else
04859 # define FMA (char *)0, (unsigned *)0, 0
04860 #endif
04861
04862 if (!state -> link_to_peer ||
04863 state -> link_to_peer -> type != dhcp_type_failover_link)
04864 return DHCP_R_INVALIDARG;
04865 link = (dhcp_failover_link_t *)state -> link_to_peer;
04866
04867 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04868 return DHCP_R_INVALIDARG;
04869
04870 if (state -> curUPD)
04871 return ISC_R_ALREADYRUNNING;
04872
04873 status = (dhcp_failover_put_message
04874 (link, link -> outer,
04875 FTM_UPDREQ, link->xid++,
04876 (failover_option_t *)0));
04877
04878 if (status == ISC_R_SUCCESS)
04879 state -> curUPD = FTM_UPDREQ;
04880
04881 #if defined (DEBUG_FAILOVER_MESSAGES)
04882 if (status != ISC_R_SUCCESS)
04883 failover_print (FMA, " (failed)");
04884 failover_print (FMA, ")");
04885 if (obufix) {
04886 log_debug ("%s", obuf);
04887 }
04888 #endif
04889 log_info ("Sent update request message to %s", state -> name);
04890 return status;
04891 }
04892
04893 isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t
04894 *state)
04895 {
04896 dhcp_failover_link_t *link;
04897 isc_result_t status;
04898 #if defined (DEBUG_FAILOVER_MESSAGES)
04899 char obuf [64];
04900 unsigned obufix = 0;
04901
04902 # define FMA obuf, &obufix, sizeof obuf
04903 failover_print (FMA, "(updreqall");
04904 #else
04905 # define FMA (char *)0, (unsigned *)0, 0
04906 #endif
04907
04908 if (!state -> link_to_peer ||
04909 state -> link_to_peer -> type != dhcp_type_failover_link)
04910 return DHCP_R_INVALIDARG;
04911 link = (dhcp_failover_link_t *)state -> link_to_peer;
04912
04913 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04914 return DHCP_R_INVALIDARG;
04915
04916
04917 if (state -> curUPD && (state -> curUPD != FTM_UPDREQ))
04918 return ISC_R_ALREADYRUNNING;
04919
04920 status = (dhcp_failover_put_message
04921 (link, link -> outer,
04922 FTM_UPDREQALL, link->xid++,
04923 (failover_option_t *)0));
04924
04925 if (status == ISC_R_SUCCESS)
04926 state -> curUPD = FTM_UPDREQALL;
04927
04928 #if defined (DEBUG_FAILOVER_MESSAGES)
04929 if (status != ISC_R_SUCCESS)
04930 failover_print (FMA, " (failed)");
04931 failover_print (FMA, ")");
04932 if (obufix) {
04933 log_debug ("%s", obuf);
04934 }
04935 #endif
04936 log_info ("Sent update request all message to %s", state -> name);
04937 return status;
04938 }
04939
04940 isc_result_t dhcp_failover_send_update_done (dhcp_failover_state_t *state)
04941 {
04942 dhcp_failover_link_t *link;
04943 isc_result_t status;
04944 #if defined (DEBUG_FAILOVER_MESSAGES)
04945 char obuf [64];
04946 unsigned obufix = 0;
04947
04948 # define FMA obuf, &obufix, sizeof obuf
04949 failover_print (FMA, "(upddone");
04950 #else
04951 # define FMA (char *)0, (unsigned *)0, 0
04952 #endif
04953
04954 if (!state -> link_to_peer ||
04955 state -> link_to_peer -> type != dhcp_type_failover_link)
04956 return DHCP_R_INVALIDARG;
04957 link = (dhcp_failover_link_t *)state -> link_to_peer;
04958
04959 if (!link -> outer || link -> outer -> type != omapi_type_connection)
04960 return DHCP_R_INVALIDARG;
04961
04962 status = (dhcp_failover_put_message
04963 (link, link -> outer,
04964 FTM_UPDDONE, state->updxid,
04965 (failover_option_t *)0));
04966
04967 #if defined (DEBUG_FAILOVER_MESSAGES)
04968 if (status != ISC_R_SUCCESS)
04969 failover_print (FMA, " (failed)");
04970 failover_print (FMA, ")");
04971 if (obufix) {
04972 log_debug ("%s", obuf);
04973 }
04974 #endif
04975
04976 log_info ("Sent update done message to %s", state -> name);
04977
04978 state->updxid--;
04979
04980
04981
04982
04983 commit_leases();
04984
04985 return status;
04986 }
04987
04988
04989
04990
04991
04992
04993
04994
04995
04996
04997
04998
04999
05000 static isc_boolean_t
05001 failover_lease_is_better(dhcp_failover_state_t *state, struct lease *lease,
05002 failover_message_t *msg)
05003 {
05004 binding_state_t local_state;
05005 TIME msg_cltt;
05006
05007 if (lease->binding_state != lease->desired_binding_state)
05008 local_state = lease->desired_binding_state;
05009 else
05010 local_state = lease->binding_state;
05011
05012 if ((msg->options_present & FTB_CLTT) != 0)
05013 msg_cltt = msg->cltt;
05014 else
05015 msg_cltt = 0;
05016
05017 switch(local_state) {
05018 case FTS_ACTIVE:
05019 if (msg->binding_status == FTS_ACTIVE) {
05020 if (msg_cltt < lease->cltt)
05021 return ISC_TRUE;
05022 else if (msg_cltt > lease->cltt)
05023 return ISC_FALSE;
05024 else if (state->i_am == primary)
05025 return ISC_TRUE;
05026 else
05027 return ISC_FALSE;
05028 } else if (msg->binding_status == FTS_EXPIRED) {
05029 return ISC_FALSE;
05030 }
05031
05032
05033 case FTS_FREE:
05034 case FTS_BACKUP:
05035 case FTS_EXPIRED:
05036 case FTS_RELEASED:
05037 case FTS_ABANDONED:
05038 case FTS_RESET:
05039 if (msg->binding_status == FTS_ACTIVE)
05040 return ISC_FALSE;
05041 else if (state->i_am == primary)
05042 return ISC_TRUE;
05043 else
05044 return ISC_FALSE;
05045
05046
05047 default:
05048 log_fatal("Impossible condition at %s:%d.", MDL);
05049 }
05050
05051 log_fatal("Impossible condition at %s:%d.", MDL);
05052
05053 return ISC_FALSE;
05054 }
05055
05056 isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state,
05057 failover_message_t *msg)
05058 {
05059 struct lease *lt = NULL, *lease = NULL;
05060 struct iaddr ia;
05061 int reason = FTR_MISC_REJECT;
05062 const char *message;
05063 int new_binding_state;
05064 int send_to_backup = 0;
05065 int required_options;
05066 isc_boolean_t chaddr_changed = ISC_FALSE;
05067 isc_boolean_t ident_changed = ISC_FALSE;
05068
05069
05070 required_options = FTB_ASSIGNED_IP_ADDRESS | FTB_BINDING_STATUS;
05071 if ((msg->options_present & required_options) != required_options) {
05072 message = "binding update lacks required options";
05073 reason = FTR_MISSING_BINDINFO;
05074 goto bad;
05075 }
05076
05077 ia.len = sizeof msg -> assigned_addr;
05078 memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
05079
05080 if (!find_lease_by_ip_addr (&lease, ia, MDL)) {
05081 message = "unknown IP address";
05082 reason = FTR_ILLEGAL_IP_ADDR;
05083 goto bad;
05084 }
05085
05086
05087
05088
05089
05090 if ((lease->pool == NULL) || (lease->pool->failover_peer == NULL) ||
05091 (lease->pool->failover_peer != state)) {
05092 message = "IP address is covered by a different failover "
05093 "relationship state";
05094 reason = FTR_ILLEGAL_IP_ADDR;
05095 goto bad;
05096 }
05097
05098
05099
05100
05101
05102
05103
05104
05105
05106
05107
05108 if ((lease->flags & ON_ACK_QUEUE) != 0) {
05109 if (failover_lease_is_better(state, lease, msg)) {
05110 message = "incoming update is less critical than "
05111 "outgoing update";
05112 reason = FTR_LESS_CRIT_BIND_INFO;
05113 goto bad;
05114 } else {
05115
05116 dhcp_failover_ack_queue_remove(state, lease);
05117 }
05118 }
05119
05120
05121 if (!lease_copy (<, lease, MDL)) {
05122 message = "no memory";
05123 goto bad;
05124 }
05125
05126 if (msg -> options_present & FTB_CHADDR) {
05127 if (msg->binding_status == FTS_ABANDONED) {
05128 message = "BNDUPD to ABANDONED with a CHADDR";
05129 goto bad;
05130 }
05131 if (msg -> chaddr.count > sizeof lt -> hardware_addr.hbuf) {
05132 message = "chaddr too long";
05133 goto bad;
05134 }
05135
05136 if ((lt->hardware_addr.hlen != msg->chaddr.count) ||
05137 (memcmp(lt->hardware_addr.hbuf, msg->chaddr.data,
05138 msg->chaddr.count) != 0))
05139 chaddr_changed = ISC_TRUE;
05140
05141 lt -> hardware_addr.hlen = msg -> chaddr.count;
05142 memcpy (lt -> hardware_addr.hbuf, msg -> chaddr.data,
05143 msg -> chaddr.count);
05144 } else if (msg->binding_status == FTS_ACTIVE ||
05145 msg->binding_status == FTS_EXPIRED ||
05146 msg->binding_status == FTS_RELEASED) {
05147 message = "BNDUPD without CHADDR";
05148 reason = FTR_MISSING_BINDINFO;
05149 goto bad;
05150 } else if (msg->binding_status == FTS_ABANDONED) {
05151 chaddr_changed = ISC_TRUE;
05152 lt->hardware_addr.hlen = 0;
05153 if (lt->scope)
05154 binding_scope_dereference(<->scope, MDL);
05155 }
05156
05157
05158
05159
05160
05161 if (msg->options_present & FTB_CLIENT_IDENTIFIER) {
05162 if (msg->binding_status == FTS_ABANDONED) {
05163 message = "BNDUPD to ABANDONED with client-id";
05164 goto bad;
05165 }
05166
05167 if ((lt->uid_len != msg->client_identifier.count) ||
05168 (lt->uid == NULL) ||
05169 (memcmp(lt->uid, msg->client_identifier.data,
05170 lt->uid_len) != 0))
05171 ident_changed = ISC_TRUE;
05172
05173 lt->uid_len = msg->client_identifier.count;
05174
05175
05176
05177
05178
05179 if (!lt->uid || lt->uid == lt->uid_buf ||
05180 lt->uid_len > lt->uid_max) {
05181 if (lt->uid && lt->uid != lt->uid_buf)
05182 dfree(lt->uid, MDL);
05183
05184 if (lt->uid_len > sizeof(lt->uid_buf)) {
05185 lt->uid_max = lt->uid_len;
05186 lt->uid = dmalloc(lt->uid_len, MDL);
05187 if (!lt->uid) {
05188 message = "no memory";
05189 goto bad;
05190 }
05191 } else {
05192 lt->uid_max = sizeof(lt->uid_buf);
05193 lt->uid = lt->uid_buf;
05194 }
05195 }
05196 memcpy (lt -> uid,
05197 msg -> client_identifier.data, lt -> uid_len);
05198 } else if (lt->uid && msg->binding_status != FTS_RESET &&
05199 msg->binding_status != FTS_FREE &&
05200 msg->binding_status != FTS_BACKUP) {
05201 ident_changed = ISC_TRUE;
05202 if (lt->uid != lt->uid_buf)
05203 dfree (lt->uid, MDL);
05204 lt->uid = NULL;
05205 lt->uid_max = lt->uid_len = 0;
05206 }
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218
05219
05220
05221
05222
05223
05224
05225
05226
05227
05228
05229
05230
05231
05232
05233 if (msg->binding_status == FTS_ACTIVE &&
05234 (chaddr_changed || ident_changed)) {
05235 (void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
05236
05237 if (lease->scope != NULL)
05238 binding_scope_dereference(&lease->scope, MDL);
05239 }
05240
05241
05242 if (msg -> options_present & FTB_STOS) {
05243 lt -> starts = msg -> stos;
05244 }
05245 if (msg -> options_present & FTB_LEASE_EXPIRY) {
05246 lt -> ends = msg -> expiry;
05247 }
05248 if (msg->options_present & FTB_POTENTIAL_EXPIRY) {
05249 lt->atsfp = lt->tsfp = msg->potential_expiry;
05250 }
05251 if (msg->options_present & FTB_IP_FLAGS) {
05252 if (msg->ip_flags & FTF_IP_FLAG_RESERVE) {
05253 if ((((state->i_am == primary) &&
05254 (lease->binding_state == FTS_FREE)) ||
05255 ((state->i_am == secondary) &&
05256 (lease->binding_state == FTS_BACKUP))) &&
05257 !(lease->flags & RESERVED_LEASE)) {
05258 message = "Address is not reserved.";
05259 reason = FTR_IP_NOT_RESERVED;
05260 goto bad;
05261 }
05262
05263 lt->flags |= RESERVED_LEASE;
05264 } else
05265 lt->flags &= ~RESERVED_LEASE;
05266
05267 if (msg->ip_flags & FTF_IP_FLAG_BOOTP) {
05268 if ((((state->i_am == primary) &&
05269 (lease->binding_state == FTS_FREE)) ||
05270 ((state->i_am == secondary) &&
05271 (lease->binding_state == FTS_BACKUP))) &&
05272 !(lease->flags & BOOTP_LEASE)) {
05273 message = "Address is not allocated to BOOTP.";
05274 goto bad;
05275 }
05276 lt->flags |= BOOTP_LEASE;
05277 } else
05278 lt->flags &= ~BOOTP_LEASE;
05279
05280 if (msg->ip_flags & ~(FTF_IP_FLAG_RESERVE | FTF_IP_FLAG_BOOTP))
05281 log_info("Unknown IP-flags set in BNDUPD (0x%x).",
05282 msg->ip_flags);
05283 } else
05284 lt->flags &= ~(RESERVED_LEASE | BOOTP_LEASE);
05285
05286 #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
05287 log_info ("processing state transition for %s: %s to %s",
05288 piaddr (lease -> ip_addr),
05289 binding_state_print (lease -> binding_state),
05290 binding_state_print (msg -> binding_status));
05291 #endif
05292
05293
05294
05295 if (state -> me.state == normal) {
05296 new_binding_state =
05297 (normal_binding_state_transition_check
05298 (lease, state, msg -> binding_status,
05299 msg -> potential_expiry));
05300
05301
05302
05303 } else {
05304 new_binding_state =
05305 (conflict_binding_state_transition_check
05306 (lease, state, msg -> binding_status,
05307 msg -> potential_expiry));
05308 }
05309 if (new_binding_state != msg -> binding_status) {
05310 char outbuf [100];
05311
05312 if (snprintf (outbuf, sizeof outbuf,
05313 "%s: invalid state transition: %s to %s",
05314 piaddr (lease -> ip_addr),
05315 binding_state_print (lease -> binding_state),
05316 binding_state_print (msg -> binding_status))
05317 >= sizeof outbuf)
05318 log_fatal ("%s: impossible outbuf overflow",
05319 "dhcp_failover_process_bind_update");
05320
05321 dhcp_failover_send_bind_ack (state, msg,
05322 FTR_FATAL_CONFLICT,
05323 outbuf);
05324 goto out;
05325 }
05326 if (new_binding_state == FTS_EXPIRED ||
05327 new_binding_state == FTS_RELEASED ||
05328 new_binding_state == FTS_RESET) {
05329 lt -> next_binding_state = FTS_FREE;
05330
05331
05332
05333
05334
05335
05336 if ((state->i_am == primary) &&
05337 !(lt->flags & (RESERVED_LEASE | BOOTP_LEASE)))
05338 send_to_backup = peer_wants_lease(lt);
05339 } else {
05340 lt -> next_binding_state = new_binding_state;
05341 }
05342 msg -> binding_status = lt -> next_binding_state;
05343
05344
05345
05346
05347
05348 lease->rewind_binding_state = lt->next_binding_state;
05349
05350
05351 if (!supersede_lease (lease, lt, 0, 0, 0) ||
05352 !write_lease (lease)) {
05353 message = "database update failed";
05354 bad:
05355 dhcp_failover_send_bind_ack (state, msg, reason, message);
05356 goto out;
05357 } else {
05358 dhcp_failover_queue_ack (state, msg);
05359 }
05360
05361
05362
05363
05364 if (send_to_backup && secondary_not_hoarding(state, lease->pool)) {
05365 lease->next_binding_state = FTS_BACKUP;
05366 lease->tstp = cur_time;
05367 lease->starts = cur_time;
05368
05369 if (!supersede_lease(lease, NULL, 0, 1, 0) ||
05370 !write_lease(lease))
05371 log_error("can't commit lease %s for mac addr "
05372 "affinity", piaddr(lease->ip_addr));
05373
05374 dhcp_failover_send_updates(state);
05375 }
05376
05377 out:
05378 if (lt)
05379 lease_dereference (<, MDL);
05380 if (lease)
05381 lease_dereference (&lease, MDL);
05382
05383 return ISC_R_SUCCESS;
05384 }
05385
05386
05387
05388
05389
05390
05391 static inline int
05392 secondary_not_hoarding(dhcp_failover_state_t *state, struct pool *p) {
05393 int total;
05394 int hold;
05395 int lts;
05396
05397 total = p->free_leases + p->backup_leases;
05398
05399
05400 hold = ((total * state->max_lease_ownership) + 50) / 100;
05401
05402
05403
05404
05405 lts = (p->free_leases - p->backup_leases) / 2;
05406
05407
05408
05409
05410
05411 return(lts > -hold);
05412 }
05413
05414 isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *state,
05415 failover_message_t *msg)
05416 {
05417 struct lease *lt = (struct lease *)0;
05418 struct lease *lease = (struct lease *)0;
05419 struct iaddr ia;
05420 const char *message = "no memory";
05421 u_int32_t pot_expire;
05422 int send_to_backup = ISC_FALSE;
05423 struct timeval tv;
05424
05425 ia.len = sizeof msg -> assigned_addr;
05426 memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
05427
05428 if (!find_lease_by_ip_addr (&lease, ia, MDL)) {
05429 message = "no such lease";
05430 goto bad;
05431 }
05432
05433
05434 if (msg -> options_present & FTB_REJECT_REASON) {
05435 log_error ("bind update on %s from %s rejected: %.*s",
05436 piaddr (ia), state -> name,
05437 (int)((msg -> options_present & FTB_MESSAGE)
05438 ? msg -> message.count
05439 : strlen (dhcp_failover_reject_reason_print
05440 (msg -> reject_reason))),
05441 (msg -> options_present & FTB_MESSAGE)
05442 ? (const char *)(msg -> message.data)
05443 : (dhcp_failover_reject_reason_print
05444 (msg -> reject_reason)));
05445 goto unqueue;
05446 }
05447
05448
05449
05450
05451 if (!lease->last_xid)
05452 goto unqueue;
05453
05454 if (lease->last_xid != msg->xid) {
05455 message = "xid mismatch";
05456 goto bad;
05457 }
05458
05459
05460 if (msg->options_present & FTO_POTENTIAL_EXPIRY)
05461 pot_expire = msg->potential_expiry;
05462 else
05463 pot_expire = lease->tstp;
05464
05465
05466
05467
05468
05469
05470
05471
05472
05473
05474
05475 if (lease->desired_binding_state == FTS_EXPIRED ||
05476 lease->desired_binding_state == FTS_RESET ||
05477 lease->desired_binding_state == FTS_RELEASED)
05478 {
05479
05480
05481
05482
05483 lease->atsfp = lease->tsfp = pot_expire;
05484 if ((state->i_am == secondary) &&
05485 (lease->flags & RESERVED_LEASE))
05486 lease->next_binding_state = FTS_BACKUP;
05487 else
05488 lease->next_binding_state = FTS_FREE;
05489
05490
05491 lease->desired_binding_state = lease->next_binding_state;
05492
05493
05494 lease->rewind_binding_state = lease->next_binding_state;
05495
05496 supersede_lease(lease, (struct lease *)0, 0, 0, 0);
05497 write_lease(lease);
05498
05499
05500
05501
05502
05503
05504
05505
05506 if (state->i_am == primary &&
05507 !(lease->flags & (RESERVED_LEASE | BOOTP_LEASE)) &&
05508 peer_wants_lease(lease))
05509 send_to_backup = ISC_TRUE;
05510
05511 if (!send_to_backup && state->me.state == normal)
05512 commit_leases();
05513 } else {
05514
05515
05516
05517 lease->atsfp = lease->tsfp = pot_expire;
05518 if (lease->desired_binding_state != lease->binding_state) {
05519 lease->next_binding_state =
05520 lease->desired_binding_state;
05521 supersede_lease(lease,
05522 (struct lease *)0, 0, 0, 0);
05523 }
05524 write_lease(lease);
05525
05526
05527
05528
05529
05530 tv.tv_sec = cur_time + 2;
05531 tv.tv_usec = 0;
05532 add_timeout(&tv, commit_leases_timeout, (void *)0, 0, 0);
05533 }
05534
05535 unqueue:
05536 dhcp_failover_ack_queue_remove (state, lease);
05537
05538
05539
05540 if (state -> send_update_done == lease) {
05541 lease_dereference (&state -> send_update_done, MDL);
05542 dhcp_failover_send_update_done (state);
05543 }
05544
05545
05546
05547
05548 if (send_to_backup && secondary_not_hoarding(state, lease->pool)) {
05549 lease->next_binding_state = FTS_BACKUP;
05550 lease->tstp = lease->starts = cur_time;
05551
05552 if (!supersede_lease(lease, NULL, 0, 1, 0) ||
05553 !write_lease(lease))
05554 log_error("can't commit lease %s for "
05555 "client affinity", piaddr(lease->ip_addr));
05556
05557 if (state->me.state == normal)
05558 commit_leases();
05559 }
05560
05561
05562
05563 dhcp_failover_send_updates (state);
05564
05565 out:
05566 lease_dereference (&lease, MDL);
05567 if (lt)
05568 lease_dereference (<, MDL);
05569
05570 return ISC_R_SUCCESS;
05571
05572 bad:
05573 log_info ("bind update on %s got ack from %s: %s.",
05574 piaddr (ia), state -> name, message);
05575 goto out;
05576 }
05577
05578 isc_result_t dhcp_failover_generate_update_queue (dhcp_failover_state_t *state,
05579 int everythingp)
05580 {
05581 struct shared_network *s;
05582 struct pool *p;
05583 struct lease *l;
05584 int i;
05585 #define FREE_LEASES 0
05586 #define ACTIVE_LEASES 1
05587 #define EXPIRED_LEASES 2
05588 #define ABANDONED_LEASES 3
05589 #define BACKUP_LEASES 4
05590 #define RESERVED_LEASES 5
05591 struct lease **lptr[RESERVED_LEASES+1];
05592
05593
05594
05595 for (s = shared_networks; s; s = s -> next) {
05596 for (p = s -> pools; p; p = p -> next) {
05597 if (p->failover_peer != state)
05598 continue;
05599
05600 lptr[FREE_LEASES] = &p->free;
05601 lptr[ACTIVE_LEASES] = &p->active;
05602 lptr[EXPIRED_LEASES] = &p->expired;
05603 lptr[ABANDONED_LEASES] = &p->abandoned;
05604 lptr[BACKUP_LEASES] = &p->backup;
05605 lptr[RESERVED_LEASES] = &p->reserved;
05606
05607 for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
05608 for (l = *(lptr [i]); l; l = l -> next) {
05609 if ((l->flags & ON_QUEUE) == 0 &&
05610 (everythingp ||
05611 (l->tstp > l->atsfp) ||
05612 (i == EXPIRED_LEASES))) {
05613 l -> desired_binding_state = l -> binding_state;
05614 dhcp_failover_queue_update (l, 0);
05615 }
05616 }
05617 }
05618 }
05619 }
05620 return ISC_R_SUCCESS;
05621 }
05622
05623 isc_result_t
05624 dhcp_failover_process_update_request (dhcp_failover_state_t *state,
05625 failover_message_t *msg)
05626 {
05627 if (state->send_update_done) {
05628 log_info("Received update request while old update still "
05629 "flying! Silently discarding old request.");
05630 lease_dereference(&state->send_update_done, MDL);
05631 }
05632
05633
05634 dhcp_failover_generate_update_queue (state, 0);
05635
05636 state->updxid = msg->xid;
05637
05638
05639
05640
05641 if (state -> update_queue_tail) {
05642 lease_reference (&state -> send_update_done,
05643 state -> update_queue_tail, MDL);
05644 dhcp_failover_send_updates (state);
05645 log_info ("Update request from %s: sending update",
05646 state -> name);
05647 } else {
05648
05649
05650 dhcp_failover_send_update_done (state);
05651 log_info ("Update request from %s: nothing pending",
05652 state -> name);
05653 }
05654
05655 return ISC_R_SUCCESS;
05656 }
05657
05658 isc_result_t
05659 dhcp_failover_process_update_request_all (dhcp_failover_state_t *state,
05660 failover_message_t *msg)
05661 {
05662 if (state->send_update_done) {
05663 log_info("Received update request while old update still "
05664 "flying! Silently discarding old request.");
05665 lease_dereference(&state->send_update_done, MDL);
05666 }
05667
05668
05669 dhcp_failover_generate_update_queue (state, 1);
05670
05671 state->updxid = msg->xid;
05672
05673 if (state -> update_queue_tail) {
05674 lease_reference (&state -> send_update_done,
05675 state -> update_queue_tail, MDL);
05676 dhcp_failover_send_updates (state);
05677 log_info ("Update request all from %s: sending update",
05678 state -> name);
05679 } else {
05680
05681
05682 dhcp_failover_send_update_done (state);
05683 log_info ("Update request all from %s: nothing pending",
05684 state -> name);
05685 }
05686
05687 return ISC_R_SUCCESS;
05688 }
05689
05690 isc_result_t
05691 dhcp_failover_process_update_done (dhcp_failover_state_t *state,
05692 failover_message_t *msg)
05693 {
05694 struct timeval tv;
05695
05696 log_info ("failover peer %s: peer update completed.",
05697 state -> name);
05698
05699 state -> curUPD = 0;
05700
05701 switch (state -> me.state) {
05702 case unknown_state:
05703 case partner_down:
05704 case normal:
05705 case communications_interrupted:
05706 case resolution_interrupted:
05707 case shut_down:
05708 case paused:
05709 case recover_done:
05710 case startup:
05711 case recover_wait:
05712 break;
05713
05714
05715 case potential_conflict:
05716 if (state->partner.state == conflict_done) {
05717 if (state->i_am == secondary) {
05718 dhcp_failover_set_state (state, normal);
05719 } else {
05720 log_error("Secondary is in conflict_done "
05721 "state after conflict resolution, "
05722 "this is illegal.");
05723 dhcp_failover_set_state (state, shut_down);
05724 }
05725 } else {
05726 if (state->i_am == primary)
05727 dhcp_failover_set_state (state, conflict_done);
05728 else
05729 log_error("Spurious update-done message.");
05730 }
05731
05732 break;
05733
05734 case conflict_done:
05735 log_error("Spurious update-done message.");
05736 break;
05737
05738 case recover:
05739
05740
05741
05742
05743
05744 if (state -> me.stos + state -> mclt > cur_time &&
05745 state -> partner.state != recover &&
05746 state -> partner.state != recover_done) {
05747 dhcp_failover_set_state (state, recover_wait);
05748 #if defined (DEBUG_FAILOVER_TIMING)
05749 log_info ("add_timeout +%d %s",
05750 (int)(cur_time -
05751 state -> me.stos + state -> mclt),
05752 "dhcp_failover_recover_done");
05753 #endif
05754 tv . tv_sec = (int)(state -> me.stos + state -> mclt);
05755 tv . tv_usec = 0;
05756 add_timeout (&tv,
05757 dhcp_failover_recover_done,
05758 state,
05759 (tvref_t)omapi_object_reference,
05760 (tvunref_t)
05761 omapi_object_dereference);
05762 } else
05763 dhcp_failover_recover_done (state);
05764 }
05765
05766 return ISC_R_SUCCESS;
05767 }
05768
05769 void dhcp_failover_recover_done (void *sp)
05770 {
05771 dhcp_failover_state_t *state = sp;
05772
05773 #if defined (DEBUG_FAILOVER_TIMING)
05774 log_info ("dhcp_failover_recover_done");
05775 #endif
05776
05777 dhcp_failover_set_state (state, recover_done);
05778 }
05779
05780 #if defined (DEBUG_FAILOVER_MESSAGES)
05781
05782
05783
05784
05785
05786 void failover_print (char *obuf,
05787 unsigned *obufix, unsigned obufmax, const char *s)
05788 {
05789 int len = strlen (s);
05790
05791 while (len + *obufix + 1 >= obufmax) {
05792 log_debug ("%s", obuf);
05793 if (!*obufix) {
05794 log_debug ("%s", s);
05795 *obufix = 0;
05796 return;
05797 }
05798 *obufix = 0;
05799 }
05800 strcpy (&obuf [*obufix], s);
05801 *obufix += len;
05802 }
05803 #endif
05804
05805
05806
05807 unsigned char loadb_mx_tbl[256] = {
05808 251, 175, 119, 215, 81, 14, 79, 191, 103, 49,
05809 181, 143, 186, 157, 0, 232, 31, 32, 55, 60,
05810 152, 58, 17, 237, 174, 70, 160, 144, 220, 90,
05811 57, 223, 59, 3, 18, 140, 111, 166, 203, 196,
05812 134, 243, 124, 95, 222, 179, 197, 65, 180, 48,
05813 36, 15, 107, 46, 233, 130, 165, 30, 123, 161,
05814 209, 23, 97, 16, 40, 91, 219, 61, 100, 10,
05815 210, 109, 250, 127, 22, 138, 29, 108, 244, 67,
05816 207, 9, 178, 204, 74, 98, 126, 249, 167, 116,
05817 34, 77, 193, 200, 121, 5, 20, 113, 71, 35,
05818 128, 13, 182, 94, 25, 226, 227, 199, 75, 27,
05819 41, 245, 230, 224, 43, 225, 177, 26, 155, 150,
05820 212, 142, 218, 115, 241, 73, 88, 105, 39, 114,
05821 62, 255, 192, 201, 145, 214, 168, 158, 221, 148,
05822 154, 122, 12, 84, 82, 163, 44, 139, 228, 236,
05823 205, 242, 217, 11, 187, 146, 159, 64, 86, 239,
05824 195, 42, 106, 198, 118, 112, 184, 172, 87, 2,
05825 173, 117, 176, 229, 247, 253, 137, 185, 99, 164,
05826 102, 147, 45, 66, 231, 52, 141, 211, 194, 206,
05827 246, 238, 56, 110, 78, 248, 63, 240, 189, 93,
05828 92, 51, 53, 183, 19, 171, 72, 50, 33, 104,
05829 101, 69, 8, 252, 83, 120, 76, 135, 85, 54,
05830 202, 125, 188, 213, 96, 235, 136, 208, 162, 129,
05831 190, 132, 156, 38, 47, 1, 7, 254, 24, 4,
05832 216, 131, 89, 21, 28, 133, 37, 153, 149, 80,
05833 170, 68, 6, 169, 234, 151 };
05834
05835 static unsigned char loadb_p_hash (const unsigned char *, unsigned);
05836 static unsigned char loadb_p_hash (const unsigned char *key, unsigned len)
05837 {
05838 unsigned char hash = len;
05839 int i;
05840 for(i = len; i > 0; )
05841 hash = loadb_mx_tbl [hash ^ (key [--i])];
05842 return hash;
05843 }
05844
05845 int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
05846 {
05847 struct option_cache *oc;
05848 struct data_string ds;
05849 unsigned char hbaix;
05850 int hm;
05851 u_int16_t ec;
05852
05853 ec = ntohs(packet->raw->secs);
05854
05855 #if defined(SECS_BYTEORDER)
05856
05857
05858
05859
05860
05861
05862 if ((ec > 255) && ((ec & 0xff) == 0)) {
05863 ec = (ec >> 8) | (ec << 8);
05864 }
05865 #endif
05866
05867 if (state->load_balance_max_secs < ec) {
05868 return (1);
05869 }
05870
05871
05872
05873 if (!state->hba)
05874 return (0);
05875
05876 oc = lookup_option(&dhcp_universe, packet->options,
05877 DHO_DHCP_CLIENT_IDENTIFIER);
05878 memset(&ds, 0, sizeof ds);
05879 if (oc &&
05880 evaluate_option_cache(&ds, packet, NULL, NULL,
05881 packet->options, NULL,
05882 &global_scope, oc, MDL)) {
05883 hbaix = loadb_p_hash(ds.data, ds.len);
05884
05885 data_string_forget(&ds, MDL);
05886 } else {
05887 hbaix = loadb_p_hash(packet->raw->chaddr,
05888 packet->raw->hlen);
05889 }
05890
05891 hm = state->hba[(hbaix >> 3) & 0x1F] & (1 << (hbaix & 0x07));
05892
05893 if (state->i_am == primary)
05894 return (hm);
05895 else
05896 return (!hm);
05897 }
05898
05899
05900
05901
05902
05903
05904 int
05905 peer_wants_lease(struct lease *lp)
05906 {
05907 dhcp_failover_state_t *state;
05908 unsigned char hbaix;
05909 int hm;
05910
05911 if (!lp->pool)
05912 return 0;
05913
05914 state = lp->pool->failover_peer;
05915
05916 if (!state || !state->hba)
05917 return 0;
05918
05919 if (lp->uid_len)
05920 hbaix = loadb_p_hash(lp->uid, lp->uid_len);
05921 else if (lp->hardware_addr.hlen > 1)
05922
05923
05924
05925
05926
05927
05928 hbaix = loadb_p_hash(lp->hardware_addr.hbuf + 1,
05929 lp->hardware_addr.hlen - 1);
05930 else
05931 return 0;
05932
05933 hm = state->hba[(hbaix >> 3) & 0x1F] & (1 << (hbaix & 0x07));
05934
05935 if (state->i_am == primary)
05936 return !hm;
05937 else
05938 return hm;
05939 }
05940
05941
05942
05943
05944
05945
05946
05947 binding_state_t
05948 normal_binding_state_transition_check (struct lease *lease,
05949 dhcp_failover_state_t *state,
05950 binding_state_t binding_state,
05951 u_int32_t tsfp)
05952 {
05953 binding_state_t new_state;
05954
05955
05956 if (binding_state == lease -> binding_state)
05957 return binding_state;
05958
05959 switch (lease -> binding_state) {
05960 case FTS_FREE:
05961 case FTS_ABANDONED:
05962 switch (binding_state) {
05963 case FTS_ACTIVE:
05964 case FTS_ABANDONED:
05965 case FTS_BACKUP:
05966 case FTS_EXPIRED:
05967 case FTS_RELEASED:
05968 case FTS_RESET:
05969
05970
05971
05972
05973 if (state -> i_am == secondary)
05974 return binding_state;
05975
05976
05977
05978
05979
05980
05981 case FTS_FREE:
05982 new_state = binding_state;
05983 goto out;
05984
05985 default:
05986 log_fatal ("Impossible case at %s:%d.", MDL);
05987 return FTS_RESET;
05988 }
05989 case FTS_ACTIVE:
05990
05991
05992 if (state -> i_am == primary) {
05993
05994
05995 if (binding_state == FTS_RELEASED)
05996 return binding_state;
05997 new_state = lease -> binding_state;
05998 goto out;
05999 }
06000
06001
06002 switch (binding_state) {
06003 case FTS_FREE:
06004 case FTS_BACKUP:
06005
06006
06007 if (tsfp > cur_time) {
06008 new_state = lease -> binding_state;
06009 goto out;
06010 }
06011 return binding_state;
06012
06013 case FTS_EXPIRED:
06014
06015
06016
06017
06018
06019 if (lease -> ends - 65 > cur_time) {
06020 new_state = lease -> binding_state;
06021 goto out;
06022 }
06023
06024 case FTS_RELEASED:
06025 case FTS_ABANDONED:
06026 case FTS_RESET:
06027 case FTS_ACTIVE:
06028 return binding_state;
06029
06030 default:
06031 log_fatal ("Impossible case at %s:%d.", MDL);
06032 return FTS_RESET;
06033 }
06034 break;
06035 case FTS_EXPIRED:
06036 switch (binding_state) {
06037 case FTS_BACKUP:
06038 case FTS_FREE:
06039
06040
06041 if (tsfp > cur_time) {
06042 new_state = lease -> binding_state;
06043 goto out;
06044 }
06045 return binding_state;
06046
06047 case FTS_ACTIVE:
06048 case FTS_RELEASED:
06049 case FTS_ABANDONED:
06050 case FTS_RESET:
06051 case FTS_EXPIRED:
06052 return binding_state;
06053
06054 default:
06055 log_fatal ("Impossible case at %s:%d.", MDL);
06056 return FTS_RESET;
06057 }
06058 case FTS_RELEASED:
06059 switch (binding_state) {
06060 case FTS_FREE:
06061 case FTS_BACKUP:
06062
06063
06064
06065 case FTS_EXPIRED:
06066 case FTS_ABANDONED:
06067 case FTS_RESET:
06068 case FTS_ACTIVE:
06069 case FTS_RELEASED:
06070 return binding_state;
06071
06072 default:
06073 log_fatal ("Impossible case at %s:%d.", MDL);
06074 return FTS_RESET;
06075 }
06076 case FTS_RESET:
06077 switch (binding_state) {
06078 case FTS_FREE:
06079 case FTS_BACKUP:
06080
06081
06082 if (tsfp > cur_time) {
06083 new_state = lease -> binding_state;
06084 goto out;
06085 }
06086 return binding_state;
06087
06088 case FTS_ACTIVE:
06089 case FTS_EXPIRED:
06090 case FTS_RELEASED:
06091 case FTS_ABANDONED:
06092 case FTS_RESET:
06093 return binding_state;
06094
06095 default:
06096 log_fatal ("Impossible case at %s:%d.", MDL);
06097 return FTS_RESET;
06098 }
06099 case FTS_BACKUP:
06100 switch (binding_state) {
06101 case FTS_ACTIVE:
06102 case FTS_ABANDONED:
06103 case FTS_EXPIRED:
06104 case FTS_RELEASED:
06105 case FTS_RESET:
06106
06107
06108
06109 if (state -> i_am == primary)
06110 return binding_state;
06111
06112
06113
06114
06115 case FTS_FREE:
06116 return binding_state;
06117
06118 case FTS_BACKUP:
06119 new_state = lease -> binding_state;
06120 goto out;
06121
06122 default:
06123 log_fatal ("Impossible case at %s:%d.", MDL);
06124 return FTS_RESET;
06125 }
06126
06127 default:
06128 log_fatal ("Impossible case at %s:%d.", MDL);
06129 return FTS_RESET;
06130 }
06131 out:
06132 return new_state;
06133 }
06134
06135
06136
06137 binding_state_t
06138 conflict_binding_state_transition_check (struct lease *lease,
06139 dhcp_failover_state_t *state,
06140 binding_state_t binding_state,
06141 u_int32_t tsfp)
06142 {
06143 binding_state_t new_state;
06144
06145
06146 if (binding_state == lease -> binding_state)
06147 new_state = binding_state;
06148 else {
06149 switch (lease -> binding_state) {
06150
06151
06152
06153 case FTS_FREE:
06154 case FTS_ABANDONED:
06155 case FTS_EXPIRED:
06156 case FTS_RELEASED:
06157 case FTS_RESET:
06158 case FTS_BACKUP:
06159 new_state = binding_state;
06160 break;
06161
06162
06163
06164
06165 case FTS_ACTIVE:
06166 switch (binding_state) {
06167 case FTS_FREE:
06168 case FTS_BACKUP:
06169 new_state = lease -> binding_state;
06170 break;
06171
06172 case FTS_EXPIRED:
06173
06174
06175
06176
06177
06178 if ((lease->ends - 65) > cur_time)
06179 new_state = lease->binding_state;
06180 else
06181 new_state = binding_state;
06182 break;
06183
06184
06185
06186
06187
06188
06189 case FTS_RELEASED:
06190 case FTS_RESET:
06191 case FTS_ABANDONED:
06192 new_state = binding_state;
06193 break;
06194
06195 default:
06196 log_fatal ("Impossible case at %s:%d.", MDL);
06197 return FTS_RESET;
06198 }
06199 break;
06200
06201 default:
06202 log_fatal ("Impossible case at %s:%d.", MDL);
06203 return FTS_RESET;
06204 }
06205 }
06206 return new_state;
06207 }
06208
06209
06210
06211
06212
06213
06214
06215
06216
06217
06218
06219
06220
06221
06222
06223
06224
06225 int lease_mine_to_reallocate (struct lease *lease)
06226 {
06227 dhcp_failover_state_t *peer;
06228
06229 if (lease && lease->pool &&
06230 (peer = lease->pool->failover_peer)) {
06231
06232
06233
06234
06235
06236
06237 switch (lease->binding_state) {
06238 case FTS_ACTIVE:
06239
06240 return 0;
06241
06242 case FTS_FREE:
06243 case FTS_ABANDONED:
06244
06245
06246
06247
06248
06249
06250
06251
06252
06253 if (peer -> i_am == primary)
06254 return 1;
06255
06256 return(peer->service_state == service_partner_down &&
06257 ((lease->tsfp < peer->me.stos) ?
06258 (peer->me.stos + peer->mclt < cur_time) :
06259 (lease->tsfp + peer->mclt < cur_time)));
06260
06261 case FTS_RELEASED:
06262 case FTS_EXPIRED:
06263
06264
06265
06266
06267
06268
06269
06270
06271
06272
06273
06274
06275
06276
06277 if ((peer->i_am == primary) &&
06278 (lease->rewind_binding_state == FTS_FREE))
06279 return 1;
06280 if ((peer->i_am == secondary) &&
06281 (lease->rewind_binding_state == FTS_BACKUP))
06282 return 1;
06283
06284
06285 case FTS_RESET:
06286
06287
06288
06289
06290
06291
06292
06293
06294
06295
06296
06297
06298
06299
06300
06301
06302 return((peer->service_state == service_partner_down) &&
06303 (lease->tsfp < cur_time));
06304
06305 case FTS_BACKUP:
06306
06307
06308
06309
06310
06311 if (peer->i_am == secondary)
06312 return 1;
06313
06314 return((peer->service_state == service_partner_down) &&
06315 ((lease->tsfp < peer->me.stos) ?
06316 (peer->me.stos + peer->mclt < cur_time) :
06317 (lease->tsfp + peer->mclt < cur_time)));
06318
06319 default:
06320
06321 log_fatal("Impossible case at %s:%d.", MDL);
06322 break;
06323 }
06324 return 0;
06325 }
06326 if (lease)
06327 return(lease->binding_state == FTS_FREE ||
06328 lease->binding_state == FTS_BACKUP);
06329 else
06330 return 0;
06331 }
06332
06333 static isc_result_t failover_message_reference (failover_message_t **mp,
06334 failover_message_t *m,
06335 const char *file, int line)
06336 {
06337 *mp = m;
06338 m -> refcnt++;
06339 return ISC_R_SUCCESS;
06340 }
06341
06342 static isc_result_t failover_message_dereference (failover_message_t **mp,
06343 const char *file, int line)
06344 {
06345 failover_message_t *m;
06346 m = (*mp);
06347 m -> refcnt--;
06348 if (m -> refcnt == 0) {
06349 if (m -> next)
06350 failover_message_dereference (&m -> next,
06351 file, line);
06352 if (m -> chaddr.data)
06353 dfree (m -> chaddr.data, file, line);
06354 if (m -> client_identifier.data)
06355 dfree (m -> client_identifier.data, file, line);
06356 if (m -> hba.data)
06357 dfree (m -> hba.data, file, line);
06358 if (m -> message.data)
06359 dfree (m -> message.data, file, line);
06360 if (m -> relationship_name.data)
06361 dfree (m -> relationship_name.data, file, line);
06362 if (m -> reply_options.data)
06363 dfree (m -> reply_options.data, file, line);
06364 if (m -> request_options.data)
06365 dfree (m -> request_options.data, file, line);
06366 if (m -> vendor_class.data)
06367 dfree (m -> vendor_class.data, file, line);
06368 if (m -> vendor_options.data)
06369 dfree (m -> vendor_options.data, file, line);
06370 if (m -> ddns.data)
06371 dfree (m -> ddns.data, file, line);
06372 dfree (*mp, file, line);
06373 }
06374 *mp = 0;
06375 return ISC_R_SUCCESS;
06376 }
06377
06378 OMAPI_OBJECT_ALLOC (dhcp_failover_state, dhcp_failover_state_t,
06379 dhcp_type_failover_state)
06380 OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t,
06381 dhcp_type_failover_listener)
06382 OMAPI_OBJECT_ALLOC (dhcp_failover_link, dhcp_failover_link_t,
06383 dhcp_type_failover_link)
06384 #endif
06385
06386 const char *binding_state_print (enum failover_state state)
06387 {
06388 switch (state) {
06389 case FTS_FREE:
06390 return "free";
06391 break;
06392
06393 case FTS_ACTIVE:
06394 return "active";
06395 break;
06396
06397 case FTS_EXPIRED:
06398 return "expired";
06399 break;
06400
06401 case FTS_RELEASED:
06402 return "released";
06403 break;
06404
06405 case FTS_ABANDONED:
06406 return "abandoned";
06407 break;
06408
06409 case FTS_RESET:
06410 return "reset";
06411 break;
06412
06413 case FTS_BACKUP:
06414 return "backup";
06415 break;
06416
06417 default:
06418 return "unknown";
06419 break;
06420 }
06421 }