33#if defined (FAILOVER_PROTOCOL)
36 dhcp_failover_link_t *);
39static isc_result_t failover_message_reference (failover_message_t **,
42static isc_result_t failover_message_dereference (failover_message_t **,
45static void dhcp_failover_pool_balance(dhcp_failover_state_t *state);
46static void dhcp_failover_pool_reqbalance(dhcp_failover_state_t *state);
47static int dhcp_failover_pool_dobalance(dhcp_failover_state_t *state,
49static inline int secondary_not_hoarding(dhcp_failover_state_t *state,
53int check_secs_byte_order = 0;
69 dhcp_failover_state_t *state;
73 if (state->pool_count == 0) {
74 log_error (
"ERROR: Failover peer, %s, has no referring"
75 " pools. You must refer to each peer in at"
76 " least one pool declaration.",
81 if (state->load_balance_max_secs == 0) {
82 log_info (
"WARNING: load balancing will be disabled "
83 "for failover peer, %s, "
84 "because its load balance max secs is 0",
90 log_fatal (
"Failover configuration sanity check failed");
97 dhcp_failover_state_t *state;
107#if defined (DEBUG_FAILOVER_TIMING)
108 log_info (
"add_timeout +90 dhcp_failover_reconnect");
115 dhcp_failover_state_reference,
117 dhcp_failover_state_dereference);
118 log_error (
"failover peer %s: %s", state -> name,
119 isc_result_totext (status));
125#if defined (DEBUG_FAILOVER_TIMING)
127 "dhcp_failover_listener_restart");
142 dhcp_failover_state_t *state;
152 dhcp_failover_state_t *peer;
154 dhcp_failover_state_t *dup = (dhcp_failover_state_t *)0;
158 if (status == ISC_R_NOTFOUND) {
160 dhcp_failover_state_reference (&peer -> next,
168 dhcp_failover_state_dereference (&dup,
MDL);
175 dhcp_failover_state_t **peer;
180 dhcp_failover_state_t *p;
183 if (!strcmp (name, p -> name))
186 return dhcp_failover_state_reference (peer, p,
file,
line);
187 return ISC_R_NOTFOUND;
209 dhcp_failover_link_t *obj;
210 dhcp_failover_state_t *state;
218 for (o = h; o -> outer; o = o -> outer)
220 for (; o; o = o -> inner) {
226 state = (dhcp_failover_state_t *)o;
228 obj = (dhcp_failover_link_t *)0;
229 status = dhcp_failover_link_allocate (&obj,
MDL);
233 state -> partner.address,
MDL);
234 obj -> peer_port = state -> partner.port;
235 dhcp_failover_state_reference (&obj -> state_object, state,
MDL);
237 memset (&ds, 0,
sizeof ds);
243 dhcp_failover_link_dereference (&obj,
MDL);
244 return ISC_R_UNEXPECTED;
251 dhcp_failover_link_dereference (&obj,
MDL);
255 for (i = 0; i < addrs -> count; i++) {
256 addrs -> addresses [i].addrtype = AF_INET;
257 addrs -> addresses [i].addrlen =
sizeof (
struct in_addr);
258 memcpy (addrs -> addresses [i].address,
259 &ds.data [i * 4], sizeof (
struct in_addr));
260 addrs -> addresses [i].port = obj -> peer_port;
265 if (!state -> me.address ||
273 memset (&local_addr, 0,
sizeof local_addr);
275 local_addr.
addrlen =
sizeof (
struct in_addr);
277 log_fatal (
"failover peer %s: no local address.",
281 if (ds.len != sizeof (
struct in_addr)) {
282 log_error(
"failover peer %s: 'address' parameter "
283 "fails to resolve to an IPv4 address",
286 dhcp_failover_link_dereference (&obj,
MDL);
292 memcpy (local_addr.
address, ds.data, ds.len);
304 dhcp_failover_link_dereference (&obj,
MDL);
309 const char *name, va_list ap)
312 dhcp_failover_link_t *link;
314 dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0;
321 return ISC_R_UNEXPECTED;
323 link = (dhcp_failover_link_t *)h;
325 if (!strcmp (name,
"connect")) {
326 if (link -> state_object -> i_am == primary) {
329 log_info (
"dhcp_failover_send_connect: %s",
330 isc_result_totext (status));
337#if defined (DEBUG_FAILOVER_TIMING)
339 "dhcp_failover_link_startup_timeout");
346 (
tvref_t)dhcp_failover_link_reference,
347 (
tvunref_t)dhcp_failover_link_dereference);
351 if (!strcmp (name,
"disconnect")) {
352 if (link -> state_object) {
353 dhcp_failover_state_reference (&state,
354 link -> state_object,
MDL);
355 link -> state = dhcp_flink_disconnected;
358 if (state->link_to_peer == link)
362#if defined (DEBUG_FAILOVER_TIMING)
363 log_info(
"add_timeout +5 dhcp_failover_reconnect");
366 tv.tv_usec =
cur_tv.tv_usec;
368 (
tvref_t)dhcp_failover_state_reference,
369 (
tvunref_t)dhcp_failover_state_dereference);
371 dhcp_failover_state_dereference (&state,
MDL);
376 if (!strcmp (name,
"status")) {
377 if (link -> state_object) {
380 status = va_arg(ap, isc_result_t);
382 if ((status == ISC_R_HOSTUNREACH) || (status == ISC_R_TIMEDOUT)) {
383 dhcp_failover_state_reference (&state,
384 link -> state_object,
MDL);
385 link -> state = dhcp_flink_disconnected;
392#if defined (DEBUG_FAILOVER_TIMING)
394 "dhcp_failover_reconnect");
400 (
tvref_t)dhcp_failover_state_reference,
401 (
tvunref_t)dhcp_failover_state_dereference);
403 dhcp_failover_state_dereference (&state,
MDL);
409 if (strcmp (name,
"ready")) {
410 if (h -> inner && h -> inner -> type -> signal_handler)
411 return (*(h -> inner -> type -> signal_handler))
412 (h -> inner, name, ap);
413 return ISC_R_NOTFOUND;
423 switch (link -> state) {
424 case dhcp_flink_start:
425 link -> state = dhcp_flink_message_length_wait;
428 case dhcp_flink_message_length_wait:
430 link -> state = dhcp_flink_message_wait;
431 link -> imsg =
dmalloc (
sizeof (failover_message_t),
MDL);
433 status = ISC_R_NOMEMORY;
436 failover_message_dereference (&link->imsg,
439 link -> state = dhcp_flink_disconnected;
440 log_info (
"message length wait: %s",
441 isc_result_totext (status));
445 return ISC_R_UNEXPECTED;
447 memset (link -> imsg, 0,
sizeof (failover_message_t));
448 link -> imsg -> refcnt = 1;
451 link -> imsg_count = 0;
454 if (link->imsg_len < DHCP_FAILOVER_MIN_MESSAGE_SIZE ||
455 link->imsg_len > DHCP_FAILOVER_MAX_MESSAGE_SIZE) {
456 status = ISC_R_UNEXPECTED;
457 goto dhcp_flink_fail;
463 case dhcp_flink_message_wait:
473 link -> imsg_count += 2;
477 link -> imsg_count++;
481 link -> imsg_count++;
485 link -> imsg_count += 4;
489 link -> imsg_count += 4;
491#if defined (DEBUG_FAILOVER_MESSAGES)
492# if !defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
493 if (link->imsg->type == FTM_CONTACT)
496 log_info (
"link: message %s payoff %d time %ld xid %ld",
499 (
unsigned long)link -> imsg -> time,
500 (
unsigned long)link -> imsg -> xid);
501# if !defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
507 if (link -> imsg_payoff - link -> imsg_count) {
509 (link -> imsg_payoff -
510 link -> imsg_count));
511 link -> imsg_count = link -> imsg_payoff;
515 while (link -> imsg_count < link -> imsg_len) {
516 status = do_a_failover_option (c, link);
518 goto dhcp_flink_fail;
524 if (link -> imsg -> type == FTM_CONNECT) {
528 if (!(link->imsg->options_present &
529 FTB_RELATIONSHIP_NAME)) {
530 errmsg =
"missing relationship-name";
531 reason = FTR_INVALID_PARTNER;
540 &link->imsg->relationship_name))
547 errmsg =
"unknown failover relationship name";
548 reason = FTR_INVALID_PARTNER;
556 slen = strlen(sname);
557 }
else if (link->imsg->options_present &
558 FTB_RELATIONSHIP_NAME) {
559 sname = (
char *)link->imsg->
560 relationship_name.data;
561 slen = link->imsg->relationship_name.count;
564 slen = strlen(sname);
567 log_error(
"Failover CONNECT from %.*s: %s",
568 slen, sname, errmsg);
572 log_info (
"failover: disconnect: %s", errmsg);
574 link -> state = dhcp_flink_disconnected;
578 if ((
cur_time > link -> imsg -> time &&
579 cur_time - link -> imsg -> time > 60) ||
581 link -> imsg -> time -
cur_time > 60)) {
582 errmsg =
"time offset too large";
583 reason = FTR_TIMEMISMATCH;
587 if (!(link -> imsg -> options_present & FTB_HBA) ||
588 link -> imsg -> hba.count != 32) {
589 errmsg =
"invalid HBA";
590 reason = FTR_HBA_CONFLICT;
597 errmsg =
"no memory";
598 reason = FTR_MISC_REJECT;
601 memcpy (state -> hba, link -> imsg -> hba.data, 32);
603 if (!link -> state_object)
604 dhcp_failover_state_reference
605 (&link -> state_object, state,
MDL);
606 if (!link -> peer_address)
608 (&link -> peer_address,
609 state -> partner.address,
MDL);
615 if (!link -> state_object) {
616 log_info (
"failover: connect: no matching state.");
618 link -> state = dhcp_flink_disconnected;
626 link -> state = dhcp_flink_message_length_wait;
628 failover_message_dereference (&link -> imsg,
MDL);
645static isc_result_t do_a_failover_option (c, link)
647 dhcp_failover_link_t *link;
649 u_int16_t option_code;
650 u_int16_t option_len;
656 if (link -> imsg_count + 2 > link -> imsg_len) {
657 log_error (
"FAILOVER: message overflow at option code.");
661 if (link->imsg->type > FTM_MAX) {
662 log_error (
"FAILOVER: invalid message type: %d",
669 link -> imsg_count += 2;
671 if (link -> imsg_count + 2 > link -> imsg_len) {
672 log_error (
"FAILOVER: message overflow at length.");
678 link -> imsg_count += 2;
680 if (link -> imsg_count + option_len > link -> imsg_len) {
681 log_error (
"FAILOVER: message overflow at data.");
686 if ((option_code > FTO_MAX) ||
688#if defined (DEBUG_FAILOVER_MESSAGES)
689 log_debug (
" option code %d (%s) len %d (not recognized)",
695 link -> imsg_count += option_len;
700 if (
ft_options [option_code].type == FT_DIGEST) {
701 link -> imsg_count += option_len;
702 if (link -> imsg_count != link -> imsg_len) {
703 log_error (
"FAILOVER: digest not at end of message");
706#if defined (DEBUG_FAILOVER_MESSAGES)
716 if (link -> imsg -> options_present &
ft_options [option_code].bit) {
717 log_error (
"FAILOVER: duplicate option %s",
732 link -> imsg_count += option_len;
743 op = ((
unsigned char *)link -> imsg) +
746 op_count =
ft_options [option_code].num_present;
748 if (option_len != op_size * op_count) {
749 log_error (
"FAILOVER: option size (%d:%d), option %s",
757 failover_option_t *fo;
764 if (
ft_options [option_code].type == FT_DDNS ||
768 (((
char *)link -> imsg) +
771 op_count = (
ft_options [option_code].type == FT_DDNS1
776 link -> imsg_count += op_count;
778 ddns -> codes [1] = 0;
780 op_count = option_len - op_count;
782 ddns -> length = op_count;
785 log_error (
"FAILOVER: no memory getting%s(%d)",
786 " DNS data ", op_count);
805 if (op_size > 1 && option_len % op_size) {
806 log_error (
"FAILOVER: option_len %d not %s%d",
807 option_len,
"multiple of ", op_size);
811 op_count = option_len / op_size;
813 fo = ((failover_option_t *)
814 (((
char *)link -> imsg) +
817 fo -> count = op_count;
820 log_error (
"FAILOVER: no memory getting %s (%d)",
821 "option data", op_count);
830 if (op_size == 1 ||
ft_options [option_code].type == FT_IPADDR) {
832 link -> imsg_count += option_len;
855 if ((option_code == 11) && (option_len > 9) &&
856 (strncmp((
const char *)op,
"isc-V3.0.", 9) == 0)) {
857 log_error(
"WARNING: failover as of versions 3.1.0 and "
858 "on are not reverse compatible with "
867 for (i = 0; i < op_count; i++) {
872 link -> imsg_count += 4;
878 link -> imsg_count += 2;
884 log_error (
"FAILOVER: option %s: bad type %d",
892 link -> imsg -> options_present |=
ft_options [option_code].bit;
910 if (h -> inner && h -> inner -> type -> set_value)
911 return (*(h -> inner -> type -> set_value))
912 (h -> inner, id, name,
value);
913 return ISC_R_NOTFOUND;
921 dhcp_failover_link_t *link;
925 link = (dhcp_failover_link_t *)h;
929 (
int)link -> peer_port,
MDL);
931 if (link -> state >= dhcp_flink_state_max)
933 "invalid link state",
940 if (h -> inner && h -> inner -> type -> get_value)
941 return (*(h -> inner -> type -> get_value))
942 (h -> inner, id, name,
value);
943 return ISC_R_NOTFOUND;
949 dhcp_failover_link_t *link;
952 link = (dhcp_failover_link_t *)h;
954 if (link -> peer_address)
957 failover_message_dereference (&link -> imsg,
file,
line);
958 if (link -> state_object)
959 dhcp_failover_state_dereference (&link -> state_object,
971 dhcp_failover_link_t *link;
976 link = (dhcp_failover_link_t *)l;
991 if (link -> state >= dhcp_flink_state_max)
999 if (link -> inner && link -> inner -> type -> stuff_values)
1000 return (*(link -> inner -> type -> stuff_values)) (c, id,
1010 isc_result_t status;
1017 "local-port", &
value);
1029 local_addr.
port = port;
1032 "local-address", &
value);
1042 value ->
value -> u.buffer.len != sizeof (
struct in_addr))
1053 for (l = failover_listeners; l; l = l -> next) {
1054 if (l -> address.port == local_addr.
port &&
1055 l -> address.addrtype == local_addr.
addrtype &&
1056 l -> address.addrlen == local_addr.
addrlen &&
1057 !memcmp (l -> address.address, local_addr.
address,
1066 status = dhcp_failover_listener_allocate (&obj,
MDL);
1069 obj -> address = local_addr;
1078 dhcp_failover_listener_dereference (&obj,
MDL);
1083 dhcp_failover_listener_dereference (&obj,
MDL);
1088 if (failover_listeners) {
1089 dhcp_failover_listener_reference (&obj -> next,
1090 failover_listeners,
MDL);
1091 dhcp_failover_listener_dereference (&failover_listeners,
MDL);
1093 dhcp_failover_listener_reference (&failover_listeners, obj,
MDL);
1095 return dhcp_failover_listener_dereference (&obj,
MDL);
1102 const char *name, va_list ap)
1104 isc_result_t status;
1106 dhcp_failover_link_t *obj;
1108 dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0;
1115 if (strcmp (name,
"connect")) {
1116 if (p -> inner && p -> inner -> type -> signal_handler)
1117 return (*(p -> inner -> type -> signal_handler))
1118 (p -> inner, name, ap);
1119 return ISC_R_NOTFOUND;
1130 (s, (u_int8_t *)&c -> remote_addr.sin_addr,
1131 sizeof c -> remote_addr.sin_addr)) {
1137 log_info (
"failover: listener: no matching state");
1139 return(ISC_R_NOTFOUND);
1142 obj = (dhcp_failover_link_t *)0;
1143 status = dhcp_failover_link_allocate (&obj,
MDL);
1146 obj -> peer_port = ntohs (c -> remote_addr.sin_port);
1152 dhcp_failover_link_dereference (&obj,
MDL);
1153 log_info (
"failover: listener: picayune failure.");
1163 status = dhcp_failover_state_reference (&obj -> state_object,
1170 return dhcp_failover_link_dereference (&obj,
MDL);
1181 if (h -> inner && h -> inner -> type -> set_value)
1182 return (*(h -> inner -> type -> set_value))
1183 (h -> inner, id, name,
value);
1184 return ISC_R_NOTFOUND;
1195 if (h -> inner && h -> inner -> type -> get_value)
1196 return (*(h -> inner -> type -> get_value))
1197 (h -> inner, id, name,
value);
1198 return ISC_R_NOTFOUND;
1210 dhcp_failover_listener_dereference (&l -> next,
file,
line);
1225 if (p -> inner && p -> inner -> type -> stuff_values)
1226 return (*(p -> inner -> type -> stuff_values)) (c, id,
1235 isc_result_t status;
1236 dhcp_failover_state_t *obj;
1241 "local-port", &
value);
1254 obj = (dhcp_failover_state_t *)0;
1255 dhcp_failover_state_allocate (&obj,
MDL);
1256 obj -> me.port = port;
1260 dhcp_failover_state_dereference (&obj,
MDL);
1267 dhcp_failover_state_dereference (&obj,
MDL);
1271 dhcp_failover_state_dereference (&obj,
MDL);
1278 const char *name, va_list ap)
1280 isc_result_t status;
1281 dhcp_failover_state_t *state;
1282 dhcp_failover_link_t *link;
1287 state = (dhcp_failover_state_t *)o;
1290 if (strcmp (name,
"disconnect") &&
1291 strcmp (name,
"message")) {
1292 if (state -> inner && state -> inner -> type -> signal_handler)
1293 return (*(state -> inner -> type -> signal_handler))
1294 (state -> inner, name, ap);
1295 return ISC_R_NOTFOUND;
1300 if (!strcmp (name,
"disconnect")) {
1301 link = va_arg (ap, dhcp_failover_link_t *);
1303 dhcp_failover_link_dereference (&state -> link_to_peer,
MDL);
1305 if (state -> i_am == primary) {
1306#if defined (DEBUG_FAILOVER_TIMING)
1308 "dhcp_failover_reconnect");
1314 (
tvref_t)dhcp_failover_state_reference,
1316 dhcp_failover_state_dereference);
1318 }
else if (!strcmp (name,
"message")) {
1319 link = va_arg (ap, dhcp_failover_link_t *);
1321 if (link -> imsg -> type == FTM_CONNECT) {
1327 if (state -> link_to_peer) {
1331 "already connected");
1335 if (!(link -> imsg -> options_present & FTB_MCLT)) {
1339 "no MCLT provided");
1344 dhcp_failover_link_reference (&state -> link_to_peer,
1349 dhcp_failover_link_dereference
1350 (&state -> link_to_peer,
MDL);
1351 log_info (
"dhcp_failover_send_connectack: %s",
1352 isc_result_totext (status));
1356 if (link -> imsg -> options_present & FTB_MAX_UNACKED)
1357 state -> partner.max_flying_updates =
1358 link -> imsg -> max_unacked;
1359 if (link -> imsg -> options_present & FTB_RECEIVE_TIMER)
1360 state -> partner.max_response_delay =
1361 link -> imsg -> receive_timer;
1362 state -> mclt = link -> imsg -> mclt;
1366 }
else if (link -> imsg -> type == FTM_CONNECTACK) {
1374 if (!(link->imsg->options_present &
1375 FTB_RELATIONSHIP_NAME)) {
1376 errmsg =
"missing relationship-name";
1377 reason = FTR_INVALID_PARTNER;
1381 if (link->imsg->options_present & FTB_REJECT_REASON) {
1383 log_error (
"Failover CONNECT to %s rejected: %s",
1384 state ? state->name :
"unknown",
1386 (link -> imsg -> reject_reason)));
1393 &link->imsg->relationship_name)) {
1395 snprintf(errbuf,
sizeof(errbuf),
"remote failover "
1396 "relationship name %.*s does not match",
1397 (
int)link->imsg->relationship_name.count,
1398 link->imsg->relationship_name.data);
1400 reason = FTR_INVALID_PARTNER;
1402 log_error(
"Failover CONNECTACK from %s: %s",
1403 state->name, errmsg);
1410 if (state -> link_to_peer) {
1411 errmsg =
"already connected";
1412 reason = FTR_DUP_CONNECTION;
1416 if ((
cur_time > link -> imsg -> time &&
1417 cur_time - link -> imsg -> time > 60) ||
1419 link -> imsg -> time -
cur_time > 60)) {
1420 errmsg =
"time offset too large";
1421 reason = FTR_TIMEMISMATCH;
1425 dhcp_failover_link_reference (&state -> link_to_peer,
1432 if (state -> me.state ==
startup)
1434 state -> saved_state);
1439 if (link -> imsg -> options_present & FTB_MAX_UNACKED)
1440 state -> partner.max_flying_updates =
1441 link -> imsg -> max_unacked;
1442 if (link -> imsg -> options_present & FTB_RECEIVE_TIMER)
1443 state -> partner.max_response_delay =
1444 link -> imsg -> receive_timer;
1445#if defined (DEBUG_FAILOVER_CONTACT_TIMING)
1447 (
int)state -> partner.max_response_delay / 3,
1448 "dhcp_failover_send_contact");
1451 (
int)state -> partner.max_response_delay / 3;
1455 (
tvref_t)dhcp_failover_state_reference,
1456 (
tvunref_t)dhcp_failover_state_dereference);
1457#if defined (DEBUG_FAILOVER_CONTACT_TIMING)
1459 (
int)state -> me.max_response_delay,
1460 "dhcp_failover_timeout");
1463 (
int)state -> me.max_response_delay;
1467 (
tvref_t)dhcp_failover_state_reference,
1468 (
tvunref_t)dhcp_failover_state_dereference);
1469 }
else if (link -> imsg -> type == FTM_DISCONNECT) {
1470 if (link -> imsg -> reject_reason) {
1471 log_error (
"Failover DISCONNECT from %s: %s",
1472 state ? state->name :
"unknown",
1474 (link -> imsg -> reject_reason)));
1477 }
else if (link -> imsg -> type == FTM_BNDUPD) {
1480 }
else if (link -> imsg -> type == FTM_BNDACK) {
1482 }
else if (link -> imsg -> type == FTM_UPDREQ) {
1485 }
else if (link -> imsg -> type == FTM_UPDREQALL) {
1487 (state, link -> imsg);
1488 }
else if (link -> imsg -> type == FTM_UPDDONE) {
1491 }
else if (link -> imsg -> type == FTM_POOLREQ) {
1492 dhcp_failover_pool_reqbalance(state);
1493 }
else if (link -> imsg -> type == FTM_POOLRESP) {
1494 log_info (
"pool response: %ld leases",
1496 link -> imsg -> addresses_transferred);
1497 }
else if (link -> imsg -> type == FTM_STATE) {
1506 if (state -> link_to_peer &&
1507 state -> link_to_peer == link &&
1508 state -> link_to_peer -> state != dhcp_flink_disconnected)
1510#if defined (DEBUG_FAILOVER_CONTACT_TIMING)
1512 (
int)state -> me.max_response_delay,
1513 "dhcp_failover_timeout");
1516 (
int)state -> me.max_response_delay;
1520 (
tvref_t)dhcp_failover_state_reference,
1521 (
tvunref_t)dhcp_failover_state_dereference);
1533 isc_result_t status;
1536 if (!strcmp (name,
"disconnect")) {
1537 if (state -> link_to_peer) {
1538 log_info (
"peer %s: disconnected", state -> name);
1539 if (state -> link_to_peer -> state_object)
1540 dhcp_failover_state_dereference
1541 (&state -> link_to_peer -> state_object,
MDL);
1542 dhcp_failover_link_dereference (&state -> link_to_peer,
1549 switch (state -> me.state ==
startup ?
1550 state -> saved_state : state -> me.state) {
1572 if (state -> me.state ==
startup)
1574 (state, state -> saved_state));
1593 }
else if (!strcmp (name,
"connect")) {
1594 switch (state -> me.state) {
1621 }
else if (!strcmp (name,
"startup")) {
1624 }
else if (!strcmp (name,
"connect-timeout")) {
1625 switch (state -> me.state) {
1657 switch (state -> me.state) {
1660 state -> nrr =
" (my state unknown)";
1682 state -> nrr =
" (resolving conflicts)";
1687 state -> nrr =
" (recovering)";
1692 state -> nrr =
" (shut down)";
1697 state -> nrr =
" (paused)";
1702 state -> nrr =
" (recover wait)";
1707 state -> nrr =
" (recover done)";
1712 state -> nrr =
" (startup)";
1724 switch (state -> partner.state) {
1727 state -> nrr =
" (peer demands: recovering)";
1734 state -> nrr =
" (peer demands: resolving conflicts)";
1762 if (
state->ack_queue_tail == NULL)
1770 if (
state->update_queue_head) {
1771 lease_reference(&
state->ack_queue_tail->next_pending,
1773 lease_dereference(&
state->update_queue_head,
MDL);
1775 lease_reference(&
state->update_queue_head,
state->ack_queue_head,
MDL);
1777 if (!
state->update_queue_tail) {
1778#if defined (POINTER_DEBUG)
1779 if (
state->ack_queue_tail->next_pending) {
1780 log_error(
"next pending on ack queue tail.");
1784 lease_reference(&
state->update_queue_tail,
1787 lease_dereference(&
state->ack_queue_tail,
MDL);
1788 lease_dereference(&
state->ack_queue_head,
MDL);
1789 state->cur_unacked_updates = 0;
1806 switch (state -> me.state) {
1822 saved_state = state -> me.
state;
1823 saved_stos = state -> me.stos;
1838 !state -> update_queue_head && !state -> ack_queue_head)
1839 state -> me.stos =
cur_time - state -> mclt;
1841 state -> me.state = new_state;
1843 state -> saved_state = saved_state;
1847 log_error (
"Unable to record current failover state for %s",
1849 state -> me.state = saved_state;
1850 state -> me.stos = saved_stos;
1851 return ISC_R_IOERROR;
1854 log_info (
"failover peer %s: I move from %s to %s",
1859 if ((state->me.state ==
normal) && (state->partner.state ==
normal))
1860 log_info(
"failover peer %s: Both servers normal", state->name);
1876 if (state -> link_to_peer)
1879 switch (new_state) {
1889 if (state->auto_partner_down == 0)
1892#if defined (DEBUG_FAILOVER_TIMING)
1893 log_info(
"add_timeout +%lu dhcp_failover_auto_partner_down",
1894 (
unsigned long)state->auto_partner_down);
1896 tv.tv_sec =
cur_time + state->auto_partner_down;
1909 dhcp_failover_pool_balance(state);
1912 if (state->update_queue_tail != NULL) {
1914 log_info(
"Sending updates to %s.", state->name);
1920 if ((state->i_am == primary) ||
1921 ((state->i_am == secondary) &&
1927#if defined (DEBUG_FAILOVER_TIMING)
1929 "dhcp_failover_startup_timeout");
1944 if (state -> me.stos + state -> mclt >
cur_time) {
1945#if defined (DEBUG_FAILOVER_TIMING)
1948 state -> me.stos + state -> mclt),
1949 "dhcp_failover_startup_timeout");
1951 tv . tv_sec = (
int)(state -> me.stos + state -> mclt);
1968 if (state -> link_to_peer)
1976#if defined (BINARY_LEASES)
1977 long int tiebreaker = 0;
1983 l->
tsfp = state->me.stos + state->mclt;
1986#if defined (BINARY_LEASES)
1991 if (tiebreaker != LONG_MAX)
2001#if defined (DEBUG_FAILOVER_TIMING)
2025 failover_message_t *msg)
2031 new_state = msg -> server_state;
2032 startupp = (msg -> server_flags & FTF_SERVER_STARTUP) ? 1 : 0;
2034 if (state -> partner.state == new_state && state -> me.state) {
2035 switch (state -> me.state) {
2048 state->saved_state);
2075 state -> partner.state = new_state;
2078 log_info (
"failover peer %s: peer moves from %s to %s",
2084 if ((state->me.state ==
normal) && (state->partner.state ==
normal))
2085 log_info(
"failover peer %s: Both servers normal", state->name);
2091 log_error (
"Unable to record current failover state for %s",
2098 switch (new_state) {
2115 log_error(
"failover peer %s: Invalid state: %d", state->name,
2124 switch (state -> me.state ==
startup ?
2125 state -> saved_state : state -> me.state) {
2127 switch (new_state) {
2133 if (state -> me.state ==
startup)
2144 log_error(
"Peer %s: Invalid state transition %s "
2145 "to %s.", state->name,
2170 switch (new_state) {
2172 log_info (
"failover peer %s: requesting %s",
2173 state -> name,
"full update from peer");
2177 if (state -> me.state ==
recover)
2203 if (state -> me.state ==
recover)
2224 switch (new_state) {
2227 log_error(
"Peer %s moves to normal during conflict "
2228 "resolution - panic, shutting down.",
2237 log_error(
"Peer %s: Unexpected move to "
2238 "conflict-done.", state->name);
2265 switch (new_state) {
2283 log_fatal(
"Peer %s: Invalid attempt to move from %s "
2284 "to %s while local state is conflict-done.",
2296 switch (new_state) {
2322 switch (new_state) {
2362 switch (new_state) {
2390 switch (new_state) {
2392 log_error(
"Both servers have entered recover-done!");
2433 if (state -> me.state ==
startup && state -> saved_state !=
startup)
2449dhcp_failover_pool_balance(dhcp_failover_state_t *state)
2453 state->sched_balance = 0;
2455 dhcp_failover_pool_dobalance(state, NULL);
2466 dhcp_failover_state_t *state;
2472 state->sched_balance = 0;
2474 if (dhcp_failover_pool_dobalance(state, &sendreq))
2486dhcp_failover_pool_reqbalance(dhcp_failover_state_t *state)
2492 state->sched_balance = 0;
2494 queued = dhcp_failover_pool_dobalance(state, NULL);
2501 log_info(
"peer %s: Got POOLREQ, answering negatively! "
2502 "Peer may be out of leases or database inconsistent.",
2514dhcp_failover_pool_dobalance(dhcp_failover_state_t *state,
2517 int lts, total, thresh, hold, panic,
pass;
2518 int leases_queued = 0;
2519 struct lease *lp = NULL;
2521 struct lease *ltemp = NULL;
2528 int (*log_func)(
const char *, ...);
2529 const char *result, *reqlog;
2531 if (state -> me.state !=
normal)
2561 thresh = ((total * state->max_lease_misbalance) + 50) / 100;
2562 hold = ((total * state->max_lease_ownership) + 50) / 100;
2577 panic = thresh * -2;
2582 if ((sendreq != NULL) && (lts < panic)) {
2583 reqlog =
" (requesting peer rebalance!)";
2588 log_info(
"balancing pool %lx %s total %d free %d "
2589 "backup %d lts %d max-own (+/-)%d%s",
2591 (p->shared_network ?
2592 p->shared_network->name :
""), p->lease_count,
2593 p->free_leases, p->backup_leases, lts, hold,
2613 lease_dereference(&
next,
MDL);
2616 lease_reference(&
next, ltemp,
MDL);
2643 }
else if (lts <= -hold)
2660 lease_dereference(&lp,
MDL);
2662 lease_reference(&lp,
next,
MDL);
2670 lease_dereference(&
next,
MDL);
2672 lease_dereference(&lp,
MDL);
2675 result =
"IMBALANCED";
2678 result =
"balanced";
2682 log_func(
"%s pool %lx %s total %d free %d backup %d "
2683 "lts %d max-misbal %d", result, (
unsigned long)p,
2684 (p->shared_network ?
2685 p->shared_network->name :
""), p->lease_count,
2686 p->free_leases, p->backup_leases, lts, thresh);
2696 return leases_queued;
2706 dhcp_failover_state_t *peer;
2709 struct lease *ltemp;
2713 if(!peer || peer->me.state !=
normal)
2742 est1 = ((est1 * peer->max_lease_misbalance) + 50) / 100;
2743 est2 = ((est2 * peer->max_lease_misbalance) + 50) / 100;
2748 if(peer->i_am == primary)
2758 if(est1 > peer->max_balance)
2759 est1 = peer->max_balance;
2765 est2 = peer->last_balance + peer->min_balance;
2766 if(peer->last_balance && (est1 < est2))
2770 est1 += random() % 5;
2773 if(peer->sched_balance) {
2774 if (est1 >= peer->sched_balance)
2784 peer->sched_balance = est1;
2786#if defined(DEBUG_FAILOVER_TIMING)
2787 log_info(
"add_timeout +%d dhcp_failover_pool_rebalance",
2793 (
tvref_t)dhcp_failover_state_reference,
2794 (
tvunref_t)dhcp_failover_state_dereference);
2803 for (p = s ->
pools; p; p = p ->
next) {
2815 isc_result_t status;
2818 if (!
state -> link_to_peer)
2824 if (
state->toack_queue_head != NULL)
2827 while ((
state -> partner.max_flying_updates >
2828 state -> cur_unacked_updates) &&
state -> update_queue_head) {
2830 lease_reference (&lp,
state -> update_queue_head,
MDL);
2835 lease_dereference (&lp,
MDL);
2842 lease_dereference (&
state -> update_queue_head,
MDL);
2844 lease_reference (&
state -> update_queue_head,
2848 lease_dereference (&
state -> update_queue_tail,
MDL);
2851 if (
state -> ack_queue_head) {
2855 lease_dereference (&
state -> ack_queue_tail,
MDL);
2857 lease_reference (&
state -> ack_queue_head, lp,
MDL);
2859#if defined (POINTER_DEBUG)
2861 log_error (
"ack_queue_tail: lp -> next_pending");
2865 lease_reference (&
state -> ack_queue_tail, lp,
MDL);
2867 lease_dereference (&lp,
MDL);
2870 state -> cur_unacked_updates++;
2881 dhcp_failover_state_t *
state;
2898 if (
state -> update_queue_head) {
2901 lease_dereference (&
state -> update_queue_tail,
MDL);
2905#if defined (POINTER_DEBUG)
2907 log_error (
"next pending on update queue lease.");
2908#if defined (DEBUG_RC_HISTORY)
2909 dump_rc_history (
lease);
2923 failover_message_t *msg = (failover_message_t *)0;
2929 while (
state -> toack_queue_head) {
2930 failover_message_reference
2931 (&msg,
state -> toack_queue_head,
MDL);
2932 failover_message_dereference
2935 failover_message_reference
2941 failover_message_dereference (&msg,
MDL);
2944 if (
state -> toack_queue_tail)
2945 failover_message_dereference (&
state -> toack_queue_tail,
MDL);
2946 state -> pending_acks = 0;
2953 dhcp_failover_state_t *
state = vs;
2955#if defined (DEBUG_FAILOVER_TIMING)
2956 log_info (
"dhcp_failover_toack_queue_timeout");
2966 failover_message_t *msg)
2970 if (state -> toack_queue_head) {
2971 failover_message_reference
2972 (&state -> toack_queue_tail -> next, msg,
MDL);
2973 failover_message_dereference (&state -> toack_queue_tail,
MDL);
2975 failover_message_reference (&state -> toack_queue_head,
2978 failover_message_reference (&state -> toack_queue_tail, msg,
MDL);
2980 state -> pending_acks++;
2984 if (state -> pending_acks >= state -> partner.max_flying_updates / 2) {
2989 if (state -> pending_acks > 0) {
2990#if defined (DEBUG_FAILOVER_TIMING)
2992 "dhcp_failover_toack_queue_timeout");
2998 (
tvref_t)dhcp_failover_state_reference,
2999 (
tvunref_t)dhcp_failover_state_dereference);
3014 lease_dereference (&
state -> ack_queue_head,
MDL);
3016 lease_reference (&
state -> ack_queue_head,
3020 lease_dereference (&
state -> ack_queue_tail,
MDL);
3023 for (lp =
state -> ack_queue_head;
3037 lease_dereference (&
state -> ack_queue_tail,
MDL);
3042 lease_reference (&
state -> ack_queue_tail, lp,
MDL);
3053 state -> cur_unacked_updates--;
3060 if (
state -> cur_unacked_updates == 0) {
3070 isc_result_t status;
3123 if (h -> inner && h -> inner -> type -> set_value)
3124 return (*(h -> inner -> type -> set_value))
3125 (h -> inner, id, name,
value);
3126 return ISC_R_NOTFOUND;
3135 dhcp_failover_state_t *
state = vs;
3136 isc_result_t status;
3139#if defined (DEBUG_FAILOVER_TIMING)
3140 log_info (
"dhcp_failover_reconnect");
3144 if (state -> link_to_peer)
3149 log_info (
"failover peer %s: %s", state -> name,
3150 isc_result_totext (status));
3151#if defined (DEBUG_FAILOVER_TIMING)
3152 log_info(
"add_timeout +90 dhcp_failover_reconnect");
3157 (
tvref_t)dhcp_failover_state_reference,
3158 (
tvunref_t)dhcp_failover_state_dereference);
3164 dhcp_failover_state_t *state = vs;
3166#if defined (DEBUG_FAILOVER_TIMING)
3167 log_info (
"dhcp_failover_startup_timeout");
3175 dhcp_failover_link_t *link = vl;
3180 for (; p; p = p -> outer)
3184 log_info (
"failover: link startup timeout");
3191 dhcp_failover_state_t *state = vs;
3192 isc_result_t status;
3195#if defined (DEBUG_FAILOVER_TIMING)
3196 log_info (
"dhcp_failover_listener_restart");
3201 log_info (
"failover peer %s: %s", state -> name,
3202 isc_result_totext (status));
3203#if defined (DEBUG_FAILOVER_TIMING)
3205 "dhcp_failover_listener_restart");
3211 (
tvref_t)dhcp_failover_state_reference,
3212 (
tvunref_t)dhcp_failover_state_dereference);
3219 dhcp_failover_state_t *state = vs;
3221#if defined (DEBUG_FAILOVER_TIMING)
3222 log_info(
"dhcp_failover_auto_partner_down");
3233 dhcp_failover_state_t *s;
3236 isc_result_t status;
3240 s = (dhcp_failover_state_t *)h;
3245 name, s -> name,
MDL);
3246 return ISC_R_NOTFOUND;
3248 oc = s -> partner.address;
3250 memset (&ds, 0,
sizeof ds);
3257 return ISC_R_NOTFOUND;
3260 name, ds.data, ds.len,
MDL);
3267 oc = s -> me.address;
3271 s -> partner.port,
MDL);
3274 name, s -> me.port,
MDL);
3277 s -> me.max_flying_updates,
3283 s -> load_balance_max_secs,
MDL);
3288 return ISC_R_NOTFOUND;
3291 s -> partner.state,
MDL);
3294 s -> me.state,
MDL);
3297 s -> partner.stos,
MDL);
3305 s -> last_packet_sent,
MDL);
3308 s -> last_timestamp_received,
3314 s -> me.max_response_delay,
3318 s -> cur_unacked_updates,
MDL);
3321 if (h -> inner && h -> inner -> type -> get_value)
3322 return (*(h -> inner -> type -> get_value))
3323 (h -> inner, id, name,
value);
3324 return ISC_R_NOTFOUND;
3330 dhcp_failover_state_t *s;
3334 s = (dhcp_failover_state_t *)h;
3336 if (s -> link_to_peer)
3337 dhcp_failover_link_dereference (&s -> link_to_peer,
file,
line);
3340 s -> name = (
char *)0;
3342 if (s -> partner.address)
3344 if (s -> me.address)
3348 s -> hba = (u_int8_t *)0;
3350 if (s -> update_queue_head)
3351 lease_dereference (&s -> update_queue_head,
file,
line);
3352 if (s -> update_queue_tail)
3353 lease_dereference (&s -> update_queue_tail,
file,
line);
3354 if (s -> ack_queue_head)
3355 lease_dereference (&s -> ack_queue_head,
file,
line);
3356 if (s -> ack_queue_tail)
3357 lease_dereference (&s -> ack_queue_tail,
file,
line);
3358 if (s -> send_update_done)
3359 lease_dereference (&s -> send_update_done,
file,
line);
3360 if (s -> toack_queue_head)
3361 failover_message_dereference (&s -> toack_queue_head,
3363 if (s -> toack_queue_tail)
3364 failover_message_dereference (&s -> toack_queue_tail,
3378 dhcp_failover_state_t *s;
3379 isc_result_t status;
3386 s = (dhcp_failover_state_t *)h;
3402 sizeof s -> partner.address);
3423 sizeof s -> me.address);
3444 s -> me.max_flying_updates);
3465 (c, (u_int32_t)s -> load_balance_max_secs));
3509 (u_int32_t)s -> partner.stos);
3540 (c, (u_int32_t)s -> last_packet_sent));
3551 (c, (u_int32_t)s -> last_timestamp_received));
3572 (c, (u_int32_t)s -> me.max_response_delay));
3583 (c, (u_int32_t)s -> cur_unacked_updates));
3587 if (h -> inner && h -> inner -> type -> stuff_values)
3588 return (*(h -> inner -> type -> stuff_values)) (c, id,
3598 isc_result_t status;
3599 dhcp_failover_state_t *s;
3624 unsigned l = strlen (s -> name);
3625 if (l == tv ->
value -> u.buffer.len &&
3627 tv ->
value -> u.buffer.value, l))
3640 return ISC_R_NOTFOUND;
3667 u_int8_t *addr,
unsigned addrlen)
3672 memset (&ds, 0,
sizeof ds);
3679 state -> partner.address,
MDL)) {
3680 for (i = 0; i + addrlen - 1 < ds.len; i += addrlen) {
3681 if (!memcmp (&ds.data [i],
3694 dhcp_failover_state_t *state;
3695 failover_option_t *name;
3697 if ((strlen(state->name) == name->count) &&
3698 (memcmp(state->name, name->data, name->count) == 0))
3706 static char resbuf[
sizeof(
"Undefined-255: This reason code is not defined "
3707 "in the protocol standard.")];
3709 if ((reason > 0xff) || (reason < 0))
3710 return "Reason code out of range.";
3713 case FTR_ILLEGAL_IP_ADDR:
3714 return "Illegal IP address (not part of any address pool).";
3716 case FTR_FATAL_CONFLICT:
3717 return "Fatal conflict exists: address in use by other client.";
3719 case FTR_MISSING_BINDINFO:
3720 return "Missing binding information.";
3722 case FTR_TIMEMISMATCH:
3723 return "Connection rejected, time mismatch too great.";
3725 case FTR_INVALID_MCLT:
3726 return "Connection rejected, invalid MCLT.";
3728 case FTR_MISC_REJECT:
3729 return "Connection rejected, unknown reason.";
3731 case FTR_DUP_CONNECTION:
3732 return "Connection rejected, duplicate connection.";
3734 case FTR_INVALID_PARTNER:
3735 return "Connection rejected, invalid failover partner.";
3737 case FTR_TLS_UNSUPPORTED:
3738 return "TLS not supported.";
3740 case FTR_TLS_UNCONFIGURED:
3741 return "TLS supported but not configured.";
3743 case FTR_TLS_REQUIRED:
3744 return "TLS required but not supported by partner.";
3746 case FTR_DIGEST_UNSUPPORTED:
3747 return "Message digest not supported.";
3749 case FTR_DIGEST_UNCONFIGURED:
3750 return "Message digest not configured.";
3752 case FTR_VERSION_MISMATCH:
3753 return "Protocol version mismatch.";
3755 case FTR_OUTDATED_BIND_INFO:
3756 return "Outdated binding information.";
3758 case FTR_LESS_CRIT_BIND_INFO:
3759 return "Less critical binding information.";
3761 case FTR_NO_TRAFFIC:
3762 return "No traffic within sufficient time.";
3764 case FTR_HBA_CONFLICT:
3765 return "Hash bucket assignment conflict.";
3767 case FTR_IP_NOT_RESERVED:
3768 return "IP not reserved on this server.";
3770 case FTR_IP_DIGEST_FAILURE:
3771 return "Message digest failed to compare.";
3773 case FTR_IP_MISSING_DIGEST:
3774 return "Missing message digest.";
3777 return "Unknown Error.";
3780 sprintf(resbuf,
"Undefined-%d: This reason code is not defined in the "
3781 "protocol standard.", reason);
3791 return "unknown-state";
3794 return "partner-down";
3800 return "conflict-done";
3803 return "communications-interrupted";
3806 return "resolution-interrupted";
3809 return "potential-conflict";
3815 return "recover-done";
3818 return "recover-wait";
3833 static char messbuf[
sizeof(
"unknown-message-255")];
3836 return "invalid-message";
3840 return "pool-request";
3843 return "pool-response";
3846 return "bind-update";
3854 case FTM_CONNECTACK:
3855 return "connect-ack";
3858 return "update-request";
3861 return "update-done";
3864 return "update-request-all";
3872 case FTM_DISCONNECT:
3873 return "disconnect";
3876 sprintf(messbuf,
"unknown-message-%u", type);
3883 static char optbuf[
sizeof(
"unknown-option-65535")];
3886 return "invalid-option";
3889 case FTO_ADDRESSES_TRANSFERRED:
3890 return "addresses-transferred";
3892 case FTO_ASSIGNED_IP_ADDRESS:
3893 return "assigned-ip-address";
3895 case FTO_BINDING_STATUS:
3896 return "binding-status";
3898 case FTO_CLIENT_IDENTIFIER:
3899 return "client-identifier";
3910 case FTO_DELAYED_SERVICE:
3911 return "delayed-service";
3919 case FTO_LEASE_EXPIRY:
3920 return "lease-expiry";
3922 case FTO_MAX_UNACKED:
3923 return "max-unacked";
3931 case FTO_MESSAGE_DIGEST:
3932 return "message-digest";
3934 case FTO_POTENTIAL_EXPIRY:
3935 return "potential-expiry";
3937 case FTO_PROTOCOL_VERSION:
3938 return "protocol-version";
3940 case FTO_RECEIVE_TIMER:
3941 return "receive-timer";
3943 case FTO_REJECT_REASON:
3944 return "reject-reason";
3946 case FTO_RELATIONSHIP_NAME:
3947 return "relationship-name";
3949 case FTO_REPLY_OPTIONS:
3950 return "reply-options";
3952 case FTO_REQUEST_OPTIONS:
3953 return "request-options";
3955 case FTO_SERVER_FLAGS:
3956 return "server-flags";
3958 case FTO_SERVER_STATE:
3959 return "server-state";
3967 case FTO_TLS_REQUEST:
3968 return "tls-request";
3970 case FTO_VENDOR_CLASS:
3971 return "vendor-class";
3973 case FTO_VENDOR_OPTIONS:
3974 return "vendor-options";
3977 sprintf(optbuf,
"unknown-option-%u", type);
3986 const char *fmt, ...)
3999 if (vsnprintf (tbuf,
sizeof tbuf, fmt, va) >=
sizeof tbuf)
4000 log_fatal (
"%s: vsnprintf would truncate",
4001 "dhcp_failover_make_option");
4005 strlen (tbuf), tbuf);
4009 char *obuf,
unsigned *obufix,
4010 unsigned obufmax, ...)
4013 struct failover_option_info *info;
4015 unsigned size, count;
4021#if defined (DEBUG_FAILOVER_MESSAGES)
4029 failover_option_t
option, *op;
4033 if (code < 1 || code > FTO_MAX ||
ft_options [code].type == FT_UNDEF) {
4038 va_start (va, obufmax);
4042 if (info -> type == FT_DDNS || info -> type == FT_DDNS1) {
4043 count = info -> type == FT_DDNS ? 1 : 2;
4044 size = va_arg (va,
int) + count;
4047 if (info -> num_present)
4048 count = info -> num_present;
4050 count = va_arg (va,
int);
4053 switch (info -> type) {
4060 case FT_TEXT_OR_BYTES:
4062 txt = va_arg (va,
char *);
4067 ilen = va_arg (va,
unsigned);
4068 size = count * ilen;
4081 log_fatal (
"bogus type in failover_make_option: %d",
4101#if defined (DEBUG_FAILOVER_MESSAGES)
4109 if (snprintf (tbuf,
sizeof tbuf,
" (%s<%d>", info -> name,
4110 option.count) >=
sizeof tbuf)
4111 log_fatal (
"dhcp_failover_make_option: tbuf overflow");
4116 switch (info -> type) {
4118 for (i = 0; i < count; i++) {
4119 val = va_arg (va,
unsigned);
4120#if defined (DEBUG_FAILOVER_MESSAGES)
4122 sprintf (tbuf,
" %d", val);
4125 option.data [i + 4] = val;
4130 for (i = 0; i < count; i++) {
4131 iaddr = va_arg (va, u_int8_t *);
4134 log_error (
"IP addrlen=%d, should be 4.",
4140#if defined (DEBUG_FAILOVER_MESSAGES)
4142 sprintf (tbuf,
" %u.%u.%u.%u",
4146 memcpy (&
option.data [4 + i * ilen],
iaddr, ilen);
4151 for (i = 0; i < count; i++) {
4152 val = va_arg (va,
unsigned);
4153#if defined (DEBUG_FAILOVER_MESSAGES)
4155 sprintf (tbuf,
" %d", val);
4164 bval = va_arg (va, u_int8_t *);
4165#if defined (DEBUG_FAILOVER_MESSAGES)
4166 for (i = 0; i < count; i++) {
4168 sprintf (tbuf,
" %d", bval [i]);
4172 memcpy (&
option.data [4], bval, count);
4179 case FT_TEXT_OR_BYTES:
4181#if defined (DEBUG_FAILOVER_MESSAGES)
4189 if (snprintf (tbuf,
sizeof tbuf,
"\"%s\"", txt) >=
sizeof tbuf)
4190 log_fatal (
"dhcp_failover_make_option: tbuf overflow");
4193 memcpy (&
option.data [4], txt, count);
4198 option.data [4] = va_arg (va,
unsigned);
4200 option.data [5] = va_arg (va,
unsigned);
4201 bval = va_arg (va, u_int8_t *);
4202 memcpy (&
option.data [4 + count], bval, size - count - 4);
4203#if defined (DEBUG_FAILOVER_MESSAGES)
4204 for (i = 4; i < size; i++) {
4206 sprintf (tbuf,
" %d",
option.data [i]);
4213 for (i = 0; i < count; i++) {
4214 val = va_arg (va, u_int32_t);
4215#if defined (DEBUG_FAILOVER_MESSAGES)
4217 sprintf (tbuf,
" %d", val);
4229#if defined DEBUG_FAILOVER_MESSAGES
4235 op =
dmalloc (
sizeof (failover_option_t),
MDL);
4249 int msg_type, u_int32_t xid, ...)
4255 failover_option_t *
option;
4256 unsigned char *opbuf;
4263 va_start (list, xid);
4264 while ((
option = va_arg (list, failover_option_t *))) {
4273 if (!bad_option && size) {
4276 status = ISC_R_NOMEMORY;
4278 opbuf = (
unsigned char *)0;
4280 va_start (list, xid);
4281 while ((
option = va_arg (list, failover_option_t *))) {
4284 if (!bad_option && opbuf)
4285 memcpy (&opbuf [opix],
4335 if (link -> state_object &&
4336 link -> state_object -> link_to_peer == link) {
4337#if defined (DEBUG_FAILOVER_CONTACT_TIMING)
4339 (
int)(link -> state_object ->
4340 partner.max_response_delay) / 3,
4341 "dhcp_failover_send_contact");
4344 (
int)(link -> state_object ->
4345 partner.max_response_delay) / 3;
4349 (
tvref_t)dhcp_failover_state_reference,
4350 (
tvunref_t)dhcp_failover_state_dereference);
4357 log_info (
"dhcp_failover_put_message: something went wrong.");
4364 dhcp_failover_state_t *state = vstate;
4365 dhcp_failover_link_t *link;
4367#if defined (DEBUG_FAILOVER_TIMING)
4368 log_info (
"dhcp_failover_timeout");
4373 link = state -> link_to_peer;
4379 log_error (
"timeout waiting for failover peer %s", state -> name);
4388 dhcp_failover_state_t *state = vstate;
4389 dhcp_failover_link_t *link;
4390 isc_result_t status;
4392#if defined(DEBUG_FAILOVER_MESSAGES) && \
4393 defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
4395 unsigned obufix = 0;
4400#if defined (DEBUG_FAILOVER_CONTACT_TIMING)
4401 log_info (
"dhcp_failover_send_contact");
4406 link = state -> link_to_peer;
4413 (link, link -> outer,
4414 FTM_CONTACT, link->xid++,
4415 (failover_option_t *)0));
4417#if defined(DEBUG_FAILOVER_MESSAGES) && \
4418 defined(DEBUG_FAILOVER_CONTACT_MESSAGES)
4433 dhcp_failover_link_t *link;
4434 isc_result_t status;
4436#if defined (DEBUG_FAILOVER_MESSAGES)
4438 unsigned obufix = 0;
4440# define FMA obuf, &obufix, sizeof obuf
4443# define FMA (char *)0, (unsigned *)0, 0
4448 link = state -> link_to_peer;
4455 (link, link -> outer,
4456 FTM_STATE, link->xid++,
4459 ? state -> saved_state
4460 : state -> me.state)),
4462 (FTO_SERVER_FLAGS, FMA,
4464 ? FTF_SERVER_STARTUP : 0)),
4466 (failover_option_t *)0));
4468#if defined (DEBUG_FAILOVER_MESSAGES)
4485 dhcp_failover_link_t *link;
4486 dhcp_failover_state_t *state;
4487 isc_result_t status;
4488#if defined (DEBUG_FAILOVER_MESSAGES)
4490 unsigned obufix = 0;
4492# define FMA obuf, &obufix, sizeof obuf
4495# define FMA (char *)0, (unsigned *)0, 0
4500 link = (dhcp_failover_link_t *)l;
4501 state = link -> state_object;
4508 FTM_CONNECT, link->xid++,
4510 strlen(state->name), state->name),
4512 state -> me.max_flying_updates),
4514 state -> me.max_response_delay),
4518 DHCP_FAILOVER_VERSION),
4526 (failover_option_t *)0));
4528#if defined (DEBUG_FAILOVER_MESSAGES)
4540 dhcp_failover_state_t *state,
4541 int reason,
const char *errmsg)
4543 dhcp_failover_link_t *link;
4544 isc_result_t status;
4545#if defined (DEBUG_FAILOVER_MESSAGES)
4547 unsigned obufix = 0;
4549# define FMA obuf, &obufix, sizeof obuf
4552# define FMA (char *)0, (unsigned *)0, 0
4557 link = (dhcp_failover_link_t *)l;
4564 FTM_CONNECTACK, link->imsg->xid,
4567 strlen(state->name), state->name)
4568 : (link->imsg->options_present & FTB_RELATIONSHIP_NAME)
4570 link->imsg->relationship_name.count,
4571 link->imsg->relationship_name.data)
4575 state -> me.max_flying_updates)
4579 state -> me.max_response_delay)
4584 DHCP_FAILOVER_VERSION),
4585 (link->imsg->options_present & FTB_TLS_REQUEST)
4595 strlen (errmsg), errmsg)
4597 (failover_option_t *)0));
4599#if defined (DEBUG_FAILOVER_MESSAGES)
4612 const char *message)
4614 dhcp_failover_link_t *link;
4615 isc_result_t status;
4616#if defined (DEBUG_FAILOVER_MESSAGES)
4618 unsigned obufix = 0;
4620# define FMA obuf, &obufix, sizeof obuf
4623# define FMA (char *)0, (unsigned *)0, 0
4628 link = (dhcp_failover_link_t *)l;
4632 if (!message && reason)
4637 FTM_DISCONNECT, link->xid++,
4642 strlen (message), message)
4644 (failover_option_t *)0));
4646#if defined (DEBUG_FAILOVER_MESSAGES)
4662 dhcp_failover_link_t *link;
4663 isc_result_t status;
4666#if defined (DEBUG_FAILOVER_MESSAGES)
4668 unsigned obufix = 0;
4670# define FMA obuf, &obufix, sizeof obuf
4673# define FMA (char *)0, (unsigned *)0, 0
4676 if (!state -> link_to_peer ||
4679 link = (dhcp_failover_link_t *)state -> link_to_peer;
4691 if ((state->i_am == primary) && (transmit_state ==
FTS_FREE))
4693 else if ((state->i_am == secondary) &&
4697 flags |= FTF_IP_FLAG_RESERVE;
4700 flags |= FTF_IP_FLAG_BOOTP;
4740 (link, link -> outer,
4746 lease -> desired_binding_state),
4752 lease -> hardware_addr.hlen
4754 lease -> hardware_addr.hlen,
4755 lease -> hardware_addr.hbuf)
4772 (failover_option_t *)0));
4774#if defined (DEBUG_FAILOVER_MESSAGES)
4788 failover_message_t *msg,
4789 int reason,
const char *message)
4791 dhcp_failover_link_t *link;
4792 isc_result_t status;
4793#if defined (DEBUG_FAILOVER_MESSAGES)
4795 unsigned obufix = 0;
4797# define FMA obuf, &obufix, sizeof obuf
4800# define FMA (char *)0, (unsigned *)0, 0
4803 if (!state -> link_to_peer ||
4806 link = (dhcp_failover_link_t *)state -> link_to_peer;
4811 if (!message && reason)
4816 (link, link -> outer,
4817 FTM_BNDACK, msg->xid,
4819 sizeof msg -> assigned_addr,
4820 &msg -> assigned_addr),
4821#ifdef DO_BNDACK_SHOULD_NOT
4823 msg -> binding_status),
4824 (msg -> options_present & FTB_CLIENT_IDENTIFIER)
4826 msg -> client_identifier.count,
4827 msg -> client_identifier.data)
4829 (msg -> options_present & FTB_CHADDR)
4831 msg -> chaddr.count,
4837 msg -> potential_expiry),
4840 (msg->options_present & FTB_CLTT) ?
4843 ((msg->options_present & FTB_IP_FLAGS) && msg->ip_flags) ?
4853 strlen (message), message)
4855#ifdef DO_BNDACK_SHOULD_NOT
4860 (failover_option_t *)0));
4862#if defined (DEBUG_FAILOVER_MESSAGES)
4875 dhcp_failover_link_t *link;
4876 isc_result_t status;
4877#if defined (DEBUG_FAILOVER_MESSAGES)
4879 unsigned obufix = 0;
4881# define FMA obuf, &obufix, sizeof obuf
4884# define FMA (char *)0, (unsigned *)0, 0
4887 if (!state -> link_to_peer ||
4890 link = (dhcp_failover_link_t *)state -> link_to_peer;
4896 (link, link -> outer,
4897 FTM_POOLREQ, link->xid++,
4898 (failover_option_t *)0));
4900#if defined (DEBUG_FAILOVER_MESSAGES)
4914 dhcp_failover_link_t *link;
4915 isc_result_t status;
4916#if defined (DEBUG_FAILOVER_MESSAGES)
4918 unsigned obufix = 0;
4920# define FMA obuf, &obufix, sizeof obuf
4923# define FMA (char *)0, (unsigned *)0, 0
4926 if (!state -> link_to_peer ||
4929 link = (dhcp_failover_link_t *)state -> link_to_peer;
4935 (link, link -> outer,
4936 FTM_POOLRESP, link->imsg->xid,
4939 (failover_option_t *)0));
4941#if defined (DEBUG_FAILOVER_MESSAGES)
4954 dhcp_failover_link_t *link;
4955 isc_result_t status;
4956#if defined (DEBUG_FAILOVER_MESSAGES)
4958 unsigned obufix = 0;
4960# define FMA obuf, &obufix, sizeof obuf
4963# define FMA (char *)0, (unsigned *)0, 0
4966 if (!state->link_to_peer ||
4969 link = (dhcp_failover_link_t *)state->link_to_peer;
4977 if (state->curUPD == FTM_UPDREQALL) {
4982 link->xid++, NULL));
4984 state->curUPD = FTM_UPDREQ;
4986#if defined (DEBUG_FAILOVER_MESSAGES)
4996 log_info(
"Sent update request message to %s", state->name);
4998 log_error(
"Failed to send update request all message to %s: %s",
4999 state->name, isc_result_totext(status));
5007 dhcp_failover_link_t *link;
5008 isc_result_t status;
5009#if defined (DEBUG_FAILOVER_MESSAGES)
5011 unsigned obufix = 0;
5013# define FMA obuf, &obufix, sizeof obuf
5016# define FMA (char *)0, (unsigned *)0, 0
5019 if (!state->link_to_peer ||
5022 link = (dhcp_failover_link_t *)state->link_to_peer;
5032 link->xid++, NULL));
5034 state->curUPD = FTM_UPDREQALL;
5036#if defined (DEBUG_FAILOVER_MESSAGES)
5046 log_info(
"Sent update request all message to %s", state->name);
5048 log_error(
"Failed to send update request all message to %s: %s",
5049 state->name, isc_result_totext(status));
5056 dhcp_failover_link_t *link;
5057 isc_result_t status;
5058#if defined (DEBUG_FAILOVER_MESSAGES)
5060 unsigned obufix = 0;
5062# define FMA obuf, &obufix, sizeof obuf
5065# define FMA (char *)0, (unsigned *)0, 0
5068 if (!state -> link_to_peer ||
5071 link = (dhcp_failover_link_t *)state -> link_to_peer;
5077 (link, link -> outer,
5078 FTM_UPDDONE, state->updxid,
5079 (failover_option_t *)0));
5081#if defined (DEBUG_FAILOVER_MESSAGES)
5090 log_info (
"Sent update done message to %s", state -> name);
5115failover_lease_is_better(dhcp_failover_state_t *state,
struct lease *
lease,
5116 failover_message_t *msg)
5126 if ((msg->options_present & FTB_CLTT) != 0)
5127 msg_cltt = msg->cltt;
5131 switch(local_state) {
5134 if (msg_cltt < lease->cltt)
5138 else if (state->i_am == primary)
5155 else if (state->i_am == primary)
5171 failover_message_t *msg)
5175 int reason = FTR_MISC_REJECT;
5176 const char *message;
5177 int new_binding_state;
5178 int send_to_backup = 0;
5179 int required_options;
5184 required_options = FTB_ASSIGNED_IP_ADDRESS | FTB_BINDING_STATUS;
5185 if ((msg->options_present & required_options) != required_options) {
5186 message =
"binding update lacks required options";
5187 reason = FTR_MISSING_BINDINFO;
5191 ia.len =
sizeof msg -> assigned_addr;
5192 memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
5195 message =
"unknown IP address";
5196 reason = FTR_ILLEGAL_IP_ADDR;
5206 message =
"IP address is covered by a different failover "
5207 "relationship state";
5208 reason = FTR_ILLEGAL_IP_ADDR;
5223 if (failover_lease_is_better(state,
lease, msg)) {
5224 message =
"incoming update is less critical than "
5226 reason = FTR_LESS_CRIT_BIND_INFO;
5236 message =
"no memory";
5240 if (msg -> options_present & FTB_CHADDR) {
5242 message =
"BNDUPD to ABANDONED with a CHADDR";
5245 if (msg -> chaddr.count >
sizeof lt -> hardware_addr.hbuf) {
5246 message =
"chaddr too long";
5252 msg->chaddr.count) != 0))
5255 lt -> hardware_addr.hlen = msg -> chaddr.count;
5256 memcpy (lt -> hardware_addr.hbuf, msg -> chaddr.data,
5257 msg -> chaddr.count);
5258 }
else if (msg->binding_status ==
FTS_ACTIVE ||
5261 message =
"BNDUPD without CHADDR";
5262 reason = FTR_MISSING_BINDINFO;
5275 if (msg->options_present & FTB_CLIENT_IDENTIFIER) {
5277 message =
"BNDUPD to ABANDONED with client-id";
5281 if ((lt->
uid_len != msg->client_identifier.count) ||
5282 (lt->
uid == NULL) ||
5283 (memcmp(lt->
uid, msg->client_identifier.data,
5287 lt->
uid_len = msg->client_identifier.count;
5302 message =
"no memory";
5311 msg -> client_identifier.data, lt -> uid_len);
5312 }
else if (lt->
uid && msg->binding_status !=
FTS_RESET &&
5348 (chaddr_changed || ident_changed)) {
5349#if defined (NSUPDATE)
5358 if (msg -> options_present & FTB_STOS) {
5359 lt -> starts = msg -> stos;
5361 if (msg -> options_present & FTB_LEASE_EXPIRY) {
5362 lt -> ends = msg -> expiry;
5364 if (msg->options_present & FTB_POTENTIAL_EXPIRY) {
5365 lt->
atsfp = lt->
tsfp = msg->potential_expiry;
5367 if (msg->options_present & FTB_IP_FLAGS) {
5368 if (msg->ip_flags & FTF_IP_FLAG_RESERVE) {
5369 if ((((state->i_am == primary) &&
5371 ((state->i_am == secondary) &&
5374 message =
"Address is not reserved.";
5375 reason = FTR_IP_NOT_RESERVED;
5383 if (msg->ip_flags & FTF_IP_FLAG_BOOTP) {
5384 if ((((state->i_am == primary) &&
5386 ((state->i_am == secondary) &&
5389 message =
"Address is not allocated to BOOTP.";
5396 if (msg->ip_flags & ~(FTF_IP_FLAG_RESERVE | FTF_IP_FLAG_BOOTP))
5397 log_info(
"Unknown IP-flags set in BNDUPD (0x%x).",
5402#if defined (DEBUG_LEASE_STATE_TRANSITIONS)
5403 log_info (
"processing state transition for %s: %s to %s",
5411 if (state -> me.state ==
normal) {
5414 (
lease, state, msg -> binding_status,
5415 msg -> potential_expiry));
5422 (
lease, state, msg -> binding_status,
5423 msg -> potential_expiry));
5425 if (new_binding_state != msg -> binding_status) {
5428 if (snprintf (outbuf,
sizeof outbuf,
5429 "%s: invalid state transition: %s to %s",
5434 log_fatal (
"%s: impossible outbuf overflow",
5435 "dhcp_failover_process_bind_update");
5445 lt -> next_binding_state =
FTS_FREE;
5452 if ((state->i_am == primary) &&
5456 lt -> next_binding_state = new_binding_state;
5458 msg -> binding_status = lt -> next_binding_state;
5469 message =
"database update failed";
5480 if (send_to_backup && secondary_not_hoarding(state,
lease->
pool)) {
5487 log_error(
"can't commit lease %s for mac addr "
5495 lease_dereference (<,
MDL);
5508secondary_not_hoarding(dhcp_failover_state_t *state,
struct pool *p) {
5516 hold = ((total * state->max_lease_ownership) + 50) / 100;
5527 return(lts > -hold);
5531 failover_message_t *msg)
5535 const char *message =
"no memory";
5536 u_int32_t pot_expire;
5540 ia.len =
sizeof msg -> assigned_addr;
5541 memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
5544 message =
"no such lease";
5549 if (msg -> options_present & FTB_REJECT_REASON) {
5550 log_error (
"bind update on %s from %s rejected: %.*s",
5551 piaddr (ia), state -> name,
5552 (
int)((msg -> options_present & FTB_MESSAGE)
5553 ? msg -> message.count
5555 (msg -> reject_reason))),
5556 (msg -> options_present & FTB_MESSAGE)
5557 ? (
const char *)(msg -> message.data)
5559 (msg -> reject_reason)));
5570 message =
"xid mismatch";
5575 if (msg->options_present & FTO_POTENTIAL_EXPIRY)
5576 pot_expire = msg->potential_expiry;
5599 if ((state->i_am == secondary) &&
5621 if (state->i_am == primary &&
5626 if (!send_to_backup && state->me.state ==
normal)
5654 if (state -> send_update_done ==
lease) {
5655 lease_dereference (&state -> send_update_done,
MDL);
5662 if (send_to_backup && secondary_not_hoarding(state,
lease->
pool)) {
5671 if (state->me.state ==
normal)
5684 log_info (
"bind update on %s got ack from %s: %s.",
5685 piaddr (ia), state -> name, message);
5696#define FREE_LEASES 0
5697#define ACTIVE_LEASES 1
5698#define EXPIRED_LEASES 2
5699#define ABANDONED_LEASES 3
5700#define BACKUP_LEASES 4
5701#define RESERVED_LEASES 5
5707 for (p = s ->
pools; p; p = p ->
next) {
5738 failover_message_t *msg)
5740 if (
state->send_update_done) {
5741 log_info(
"Received update request while old update still "
5742 "flying! Silently discarding old request.");
5743 lease_dereference(&
state->send_update_done,
MDL);
5754 if (
state -> update_queue_tail) {
5755 lease_reference (&
state -> send_update_done,
5758 log_info (
"Update request from %s: sending update",
5764 log_info (
"Update request from %s: nothing pending",
5773 failover_message_t *msg)
5775 if (
state->send_update_done) {
5776 log_info(
"Received update request while old update still "
5777 "flying! Silently discarding old request.");
5778 lease_dereference(&
state->send_update_done,
MDL);
5786 if (
state -> update_queue_tail) {
5787 lease_reference (&
state -> send_update_done,
5790 log_info (
"Update request all from %s: sending update",
5796 log_info (
"Update request all from %s: nothing pending",
5805 failover_message_t *msg)
5809 log_info (
"failover peer %s: peer update completed.",
5812 state -> curUPD = 0;
5814 switch (state -> me.state) {
5830 if (state->i_am == secondary) {
5833 log_error(
"Secondary is in conflict_done "
5834 "state after conflict resolution, "
5835 "this is illegal.");
5839 if (state->i_am == primary)
5842 log_error(
"Spurious update-done message.");
5848 log_error(
"Spurious update-done message.");
5857 if (state -> me.stos + state -> mclt >
cur_time &&
5858 state -> partner.state !=
recover &&
5861#if defined (DEBUG_FAILOVER_TIMING)
5864 state -> me.stos + state -> mclt),
5865 "dhcp_failover_recover_done");
5867 tv . tv_sec = (
int)(state -> me.stos + state -> mclt);
5884 dhcp_failover_state_t *state = sp;
5886#if defined (DEBUG_FAILOVER_TIMING)
5887 log_info (
"dhcp_failover_recover_done");
5893#if defined (DEBUG_FAILOVER_MESSAGES)
5900 unsigned *obufix,
unsigned obufmax,
const char *s)
5902 int len = strlen (s);
5904 while (len + *obufix + 1 >= obufmax) {
5913 strcpy (&obuf [*obufix], s);
5920unsigned char loadb_mx_tbl[256] = {
5921 251, 175, 119, 215, 81, 14, 79, 191, 103, 49,
5922 181, 143, 186, 157, 0, 232, 31, 32, 55, 60,
5923 152, 58, 17, 237, 174, 70, 160, 144, 220, 90,
5924 57, 223, 59, 3, 18, 140, 111, 166, 203, 196,
5925 134, 243, 124, 95, 222, 179, 197, 65, 180, 48,
5926 36, 15, 107, 46, 233, 130, 165, 30, 123, 161,
5927 209, 23, 97, 16, 40, 91, 219, 61, 100, 10,
5928 210, 109, 250, 127, 22, 138, 29, 108, 244, 67,
5929 207, 9, 178, 204, 74, 98, 126, 249, 167, 116,
5930 34, 77, 193, 200, 121, 5, 20, 113, 71, 35,
5931 128, 13, 182, 94, 25, 226, 227, 199, 75, 27,
5932 41, 245, 230, 224, 43, 225, 177, 26, 155, 150,
5933 212, 142, 218, 115, 241, 73, 88, 105, 39, 114,
5934 62, 255, 192, 201, 145, 214, 168, 158, 221, 148,
5935 154, 122, 12, 84, 82, 163, 44, 139, 228, 236,
5936 205, 242, 217, 11, 187, 146, 159, 64, 86, 239,
5937 195, 42, 106, 198, 118, 112, 184, 172, 87, 2,
5938 173, 117, 176, 229, 247, 253, 137, 185, 99, 164,
5939 102, 147, 45, 66, 231, 52, 141, 211, 194, 206,
5940 246, 238, 56, 110, 78, 248, 63, 240, 189, 93,
5941 92, 51, 53, 183, 19, 171, 72, 50, 33, 104,
5942 101, 69, 8, 252, 83, 120, 76, 135, 85, 54,
5943 202, 125, 188, 213, 96, 235, 136, 208, 162, 129,
5944 190, 132, 156, 38, 47, 1, 7, 254, 24, 4,
5945 216, 131, 89, 21, 28, 133, 37, 153, 149, 80,
5946 170, 68, 6, 169, 234, 151 };
5948static unsigned char loadb_p_hash (
const unsigned char *,
unsigned);
5949static unsigned char loadb_p_hash (
const unsigned char *key,
unsigned len)
5951 unsigned char hash = len;
5953 for(i = len; i > 0; )
5954 hash = loadb_mx_tbl [hash ^ (key [--i])];
5962 unsigned char hbaix;
5974 if ((check_secs_byte_order == 1) &&
5975 ((ec > 255) && ((ec & 0xff) == 0))) {
5976 ec = (ec >> 8) | (ec << 8);
5979 if ((state->load_balance_max_secs == 0) ||
5980 (state->load_balance_max_secs < ec)) {
5994 memset(&ds, 0,
sizeof ds);
5999 hbaix = loadb_p_hash(ds.data, ds.len);
6007 hm = state->hba[(hbaix >> 3) & 0x1F] & (1 << (hbaix & 0x07));
6009 if (state->i_am == primary)
6023 dhcp_failover_state_t *state;
6024 unsigned char hbaix;
6032 if (!state || !state->hba)
6049 hm = state->hba[(hbaix >> 3) & 0x1F] & (1 << (hbaix & 0x07));
6051 if (state->i_am == primary)
6065 dhcp_failover_state_t *state,
6072 if (binding_state ==
lease -> binding_state)
6073 return binding_state;
6075 switch (
lease -> binding_state) {
6078 switch (binding_state) {
6089 if (state -> i_am == secondary)
6090 return binding_state;
6098 new_state = binding_state;
6108 if (state -> i_am == primary) {
6114 return binding_state;
6116 new_state =
lease -> binding_state;
6121 switch (binding_state) {
6127 new_state =
lease -> binding_state;
6130 return binding_state;
6139 new_state =
lease -> binding_state;
6147 return binding_state;
6155 switch (binding_state) {
6161 new_state =
lease -> binding_state;
6164 return binding_state;
6171 return binding_state;
6178 switch (binding_state) {
6189 return binding_state;
6196 switch (binding_state) {
6202 new_state =
lease -> binding_state;
6205 return binding_state;
6212 return binding_state;
6219 switch (binding_state) {
6228 if (state -> i_am == primary)
6229 return binding_state;
6235 return binding_state;
6238 new_state =
lease -> binding_state;
6258 dhcp_failover_state_t *state,
6265 if (binding_state ==
lease -> binding_state)
6266 new_state = binding_state;
6268 switch (
lease -> binding_state) {
6278 new_state = binding_state;
6285 switch (binding_state) {
6288 new_state =
lease -> binding_state;
6300 new_state = binding_state;
6311 new_state = binding_state;
6346 dhcp_failover_state_t *peer;
6372 if (peer -> i_am == primary)
6377 (peer->me.stos + peer->mclt <
cur_time) :
6396 if ((peer->i_am == primary) &&
6399 if ((peer->i_am == secondary) &&
6430 if (peer->i_am == secondary)
6435 (peer->me.stos + peer->mclt <
cur_time) :
6452static isc_result_t failover_message_reference (failover_message_t **mp,
6453 failover_message_t *m,
6461static isc_result_t failover_message_dereference (failover_message_t **mp,
6464 failover_message_t *m;
6467 if (m -> refcnt == 0) {
6469 failover_message_dereference (&m -> next,
6471 if (m -> chaddr.data)
6473 if (m -> client_identifier.data)
6477 if (m -> message.data)
6479 if (m -> relationship_name.data)
6481 if (m -> reply_options.data)
6483 if (m -> request_options.data)
6485 if (m -> vendor_class.data)
6487 if (m -> vendor_options.data)
6556 const char *print_value =
"<none>";
6558 if ((strlen (
value) <= 64) &&
6560 print_value =
value;
6563 print_value =
"<unsuitable for printing>";
6567 return (print_value);
6578#if defined (DEBUG_FAILOVER_MESSAGES)
isc_result_t omapi_connection_get_uint16(omapi_object_t *, u_int16_t *)
isc_result_t omapi_connection_put_uint32(omapi_object_t *, u_int32_t)
isc_result_t omapi_connection_copyout(unsigned char *, omapi_object_t *, unsigned)
isc_result_t omapi_connection_put_uint16(omapi_object_t *, u_int32_t)
isc_result_t omapi_connection_copyin(omapi_object_t *, const unsigned char *, unsigned)
isc_result_t omapi_connection_require(omapi_object_t *, unsigned)
isc_result_t omapi_connection_get_uint32(omapi_object_t *, u_int32_t *)
int option_cache_reference(struct option_cache **ptr, struct option_cache *src, const char *file, int line)
void data_string_forget(struct data_string *data, const char *file, int line)
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
void add_timeout(struct timeval *when, void *where, void *what, tvref_t ref, tvunref_t unref)
void cancel_timeout(void *where, void *what)
int option_cache_dereference(struct option_cache **ptr, const char *file, int line)
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
void putUShort(unsigned char *, u_int32_t)
void putULong(unsigned char *, u_int32_t)
int write_lease(struct lease *lease)
#define DHO_DHCP_CLIENT_IDENTIFIER
#define DHO_PXE_CLIENT_ID
struct iaddr server_identifier
isc_result_t dhcp_failover_link_stuff_values(omapi_object_t *, omapi_object_t *, omapi_object_t *)
void dhcp_failover_startup_timeout(void *)
isc_result_t dhcp_failover_process_update_request(dhcp_failover_state_t *, failover_message_t *)
failover_option_t null_failover_option
binding_state_t normal_binding_state_transition_check(struct lease *, dhcp_failover_state_t *, binding_state_t, u_int32_t)
dhcp_failover_state_t * failover_states
void(* tvunref_t)(void *, const char *, int)
int write_failover_state(dhcp_failover_state_t *)
isc_result_t dhcp_failover_listen(omapi_object_t *)
isc_result_t dhcp_failover_generate_update_queue(dhcp_failover_state_t *, int)
void dhcp_failover_sanity_check(void)
int db_printable(const unsigned char *)
const char * dhcp_failover_message_name(unsigned)
const char * dhcp_flink_state_names[]
isc_result_t dhcp_failover_state_lookup(omapi_object_t **, omapi_object_t *, omapi_object_t *)
isc_result_t find_failover_peer(dhcp_failover_state_t **, const char *, const char *, int)
isc_result_t dhcp_failover_link_signal(omapi_object_t *, const char *, va_list)
isc_result_t dhcp_failover_register(omapi_object_t *)
omapi_object_type_t * dhcp_type_failover_listener
isc_result_t dhcp_failover_peer_state_changed(dhcp_failover_state_t *, failover_message_t *)
isc_result_t dhcp_failover_listener_set_value(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *)
int peer_wants_lease(struct lease *)
struct shared_network * shared_networks
void dhcp_failover_startup(void)
struct failover_option_info ft_options[]
isc_result_t dhcp_failover_send_update_request(dhcp_failover_state_t *)
#define LEASE_GET_NEXT(LQ, LEASE)
void dhcp_failover_ack_queue_remove(dhcp_failover_state_t *, struct lease *)
void(* tvref_t)(void *, void *, const char *, int)
omapi_object_type_t * dhcp_type_failover_state
isc_result_t dhcp_failover_send_connect(omapi_object_t *)
int dhcp_failover_send_acks(dhcp_failover_state_t *)
int dhcp_failover_state_pool_check(dhcp_failover_state_t *)
isc_result_t dhcp_failover_process_bind_update(dhcp_failover_state_t *, failover_message_t *)
isc_result_t dhcp_failover_listener_get_value(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **)
struct ipv6_pool ** pools
isc_result_t dhcp_failover_listener_destroy(omapi_object_t *, const char *, int)
isc_result_t dhcp_failover_state_stuff(omapi_object_t *, omapi_object_t *, omapi_object_t *)
int lease_copy(struct lease **, struct lease *, const char *, int)
isc_result_t enter_failover_peer(dhcp_failover_state_t *)
void dhcp_failover_auto_partner_down(void *vs)
int dhcp_failover_state_match(dhcp_failover_state_t *, u_int8_t *, unsigned)
void dhcp_failover_pool_check(struct pool *)
failover_option_t failover_option_t * dhcp_failover_make_option(unsigned, char *, unsigned *, unsigned,...)
int supersede_lease(struct lease *, struct lease *, int, int, int, int)
isc_result_t dhcp_failover_state_destroy(omapi_object_t *, const char *, int)
void dhcp_failover_toack_queue_timeout(void *)
isc_result_t dhcp_failover_set_service_state(dhcp_failover_state_t *state)
int dhcp_failover_queue_update(struct lease *, int)
isc_result_t dhcp_failover_state_set_value(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *)
isc_result_t dhcp_failover_send_poolreq(dhcp_failover_state_t *)
isc_result_t dhcp_failover_send_connectack(omapi_object_t *, dhcp_failover_state_t *, int, const char *)
int dhcp_failover_state_match_by_name(dhcp_failover_state_t *, failover_option_t *)
void dhcp_failover_recover_done(void *)
failover_option_t skip_failover_option
int dhcp_failover_write_all_states(void)
isc_result_t dhcp_failover_state_create(omapi_object_t **, omapi_object_t *)
isc_result_t dhcp_failover_send_updates(dhcp_failover_state_t *)
struct universe dhcp_universe
void dhcp_failover_rescind_updates(dhcp_failover_state_t *)
isc_result_t dhcp_failover_send_state(dhcp_failover_state_t *)
void dhcp_failover_send_contact(void *)
isc_result_t dhcp_failover_send_update_done(dhcp_failover_state_t *)
isc_result_t dhcp_failover_listener_signal(omapi_object_t *, const char *, va_list)
isc_result_t dhcp_failover_send_bind_update(dhcp_failover_state_t *, struct lease *)
isc_result_t dhcp_failover_link_initiate(omapi_object_t *)
void commit_leases_timeout(void *)
void dhcp_failover_link_startup_timeout(void *)
isc_result_t dhcp_failover_set_state(dhcp_failover_state_t *, enum failover_state)
isc_result_t dhcp_failover_send_disconnect(omapi_object_t *, int, const char *)
const char * dhcp_failover_reject_reason_print(int)
int find_lease_by_ip_addr(struct lease **, struct iaddr, const char *, int)
void dhcp_failover_keepalive(void *)
int dhcp_failover_queue_ack(dhcp_failover_state_t *, failover_message_t *msg)
void dhcp_failover_pool_rebalance(void *)
isc_result_t dhcp_failover_process_bind_ack(dhcp_failover_state_t *, failover_message_t *)
isc_result_t dhcp_failover_link_destroy(omapi_object_t *, const char *, int)
const char * dhcp_failover_state_name_print(enum failover_state)
isc_result_t dhcp_failover_link_get_value(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **)
void dhcp_failover_listener_restart(void *)
void dhcp_failover_reconnect(void *)
isc_result_t ddns_removals(struct lease *, struct iasubopt *, struct dhcp_ddns_cb *, isc_boolean_t)
isc_result_t dhcp_failover_state_transition(dhcp_failover_state_t *, const char *)
void failover_print(char *, unsigned *, unsigned, const char *)
isc_result_t dhcp_failover_send_bind_ack(dhcp_failover_state_t *, failover_message_t *, int, const char *)
isc_result_t dhcp_failover_state_remove(omapi_object_t *, omapi_object_t *)
binding_state_t conflict_binding_state_transition_check(struct lease *, dhcp_failover_state_t *, binding_state_t, u_int32_t)
void dhcp_failover_timeout(void *)
isc_result_t dhcp_failover_state_get_value(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **)
isc_result_t dhcp_failover_listener_stuff(omapi_object_t *, omapi_object_t *, omapi_object_t *)
#define LEASE_GET_FIRSTP(LQ)
int lease_mine_to_reallocate(struct lease *)
isc_result_t dhcp_failover_state_signal(omapi_object_t *, const char *, va_list)
int load_balance_mine(struct packet *, dhcp_failover_state_t *)
isc_result_t dhcp_failover_send_poolresp(dhcp_failover_state_t *, int)
isc_result_t dhcp_failover_link_set_value(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *)
const char * dhcp_failover_option_name(unsigned)
isc_result_t dhcp_failover_process_update_done(dhcp_failover_state_t *, failover_message_t *)
#define LEASE_GET_FIRST(LQ)
omapi_object_type_t * dhcp_type_failover_link
isc_result_t dhcp_failover_send_update_request_all(dhcp_failover_state_t *)
failover_option_t * dhcp_failover_option_printf(unsigned, char *, unsigned *, unsigned, const char *,...) __attribute__((__format__(__printf__
isc_result_t dhcp_failover_put_message(dhcp_failover_link_t *, omapi_object_t *, int, u_int32_t,...)
#define LEASE_GET_NEXTP(LQ, LEASE)
isc_result_t dhcp_failover_process_update_request_all(dhcp_failover_state_t *, failover_message_t *)
void scrub_lease(struct lease *lease, const char *file, int line)
Remove information from a prior use of a lease.
const char * printable(const char *value)
Given a char pointer, return always return a printable value.
const char * binding_state_print(enum failover_state state)
@ communications_interrupted
struct iaddr ip_addr(struct iaddr subnet, struct iaddr mask, u_int32_t host_address)
const char * piaddr(const struct iaddr addr)
#define ISC_R_NOTIMPLEMENTED
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
isc_result_t omapi_connection_put_string(omapi_object_t *, const char *)
isc_result_t omapi_connect_list(omapi_object_t *, omapi_addr_list_t *, omapi_addr_t *)
#define OMAPI_OBJECT_ALLOC(name, stype, type)
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
isc_result_t omapi_listen_addr(omapi_object_t *, omapi_addr_t *, int)
isc_result_t omapi_addr_list_dereference(omapi_addr_list_t **, const char *, int)
struct __omapi_object omapi_object_t
isc_result_t omapi_disconnect(omapi_object_t *, int)
isc_result_t omapi_handle_td_lookup(omapi_object_t **, omapi_typed_data_t *)
isc_result_t omapi_make_uint_value(omapi_value_t **, omapi_data_string_t *, unsigned int, const char *, int)
isc_result_t omapi_make_string_value(omapi_value_t **, omapi_data_string_t *, const char *, const char *, int)
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
omapi_object_type_t * omapi_type_protocol
isc_result_t omapi_signal_in(omapi_object_t *, const char *,...)
isc_result_t omapi_signal(omapi_object_t *, const char *,...)
isc_result_t omapi_addr_list_new(omapi_addr_list_t **, unsigned, const char *, int)
int omapi_ds_strcmp(omapi_data_string_t *, const char *)
omapi_object_type_t * omapi_type_connection
void * dmalloc(size_t, const char *, int)
void dfree(void *, const char *, int)
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
isc_result_t omapi_get_int_value(unsigned long *, omapi_typed_data_t *)
isc_result_t omapi_listen(omapi_object_t *, unsigned, int)
isc_result_t omapi_connection_put_name(omapi_object_t *, const char *)
isc_result_t omapi_make_int_value(omapi_value_t **, omapi_data_string_t *, int, const char *, int)
isc_result_t omapi_make_const_value(omapi_value_t **, omapi_data_string_t *, const unsigned char *, unsigned, const char *, int)
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
struct __omapi_connection_object omapi_connection_object_t
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
#define DHCP_R_INVALIDARG
#define DHCP_R_PROTOCOLERROR
#define DHCP_R_KEYCONFLICT
#define DHCP_R_INCOMPLETE
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
binding_state_t next_binding_state
struct lease_state * state
struct binding_scope * scope
struct hardware hardware_addr
binding_state_t rewind_binding_state
struct lease * next_pending
binding_state_t desired_binding_state
binding_state_t binding_state
unsigned char address[16]
struct option_state * options
dhcp_failover_state_t * failover_peer
struct shared_network * next
int binding_scope_dereference(struct binding_scope **ptr, const char *file, int line)
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
struct binding_scope * global_scope