2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-29 13:28:14 +00:00

Rework DHCP lease state handling to be compatible with failover protocol.

This commit is contained in:
Ted Lemon 2000-06-02 21:27:21 +00:00
parent 7bb809483c
commit 007e3ee4df
15 changed files with 1317 additions and 883 deletions

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: clparse.c,v 1.44 2000/05/16 23:01:57 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: clparse.c,v 1.45 2000/06/02 21:26:55 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -291,7 +291,7 @@ void parse_client_statement (cfile, ip, config)
return; return;
} }
config -> auth_policy = policy; config -> auth_policy = policy;
} else if (token != BOOTP) { } else if (token != TOKEN_BOOTP) {
if (policy != P_PREFER && if (policy != P_PREFER &&
policy != P_IGNORE && policy != P_IGNORE &&
policy != P_ACCEPT) { policy != P_ACCEPT) {
@ -919,7 +919,7 @@ void parse_client_lease_declaration (cfile, lease, ipp, clientp)
parse_warn (cfile, "unknown key %s", val); parse_warn (cfile, "unknown key %s", val);
parse_semi (cfile); parse_semi (cfile);
break; break;
case BOOTP: case TOKEN_BOOTP:
lease -> is_bootp = 1; lease -> is_bootp = 1;
break; break;

View File

@ -41,7 +41,7 @@
#ifndef lint #ifndef lint
static char ocopyright[] = static char ocopyright[] =
"$Id: dhclient.c,v 1.104 2000/05/30 21:43:42 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 Internet Software Consortium. All rights reserved.\n"; "$Id: dhclient.c,v 1.105 2000/06/02 21:26:57 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -779,7 +779,7 @@ void bind_lease (client)
} }
/* Write out the new lease. */ /* Write out the new lease. */
write_client_lease (client, client -> new, 0); write_client_lease (client, client -> new, 0, 0);
/* Replace the old active lease with the new one. */ /* Replace the old active lease with the new one. */
if (client -> active) if (client -> active)
@ -1561,17 +1561,49 @@ void send_release (cpp)
struct client_state *client = cpp; struct client_state *client = cpp;
int result; int result;
struct sockaddr_in destination;
struct in_addr from;
memcpy (&from, client -> active -> address.iabuf,
sizeof from);
memcpy (&destination.sin_addr.s_addr,
client -> destination.iabuf,
sizeof destination.sin_addr.s_addr);
destination.sin_port = remote_port;
destination.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
destination.sin_len = sizeof destination;
#endif
/* Set the lease to end now, so that we don't accidentally
reuse it if we restart before the old expiry time. */
client -> active -> expiry =
client -> active -> renewal =
client -> active -> rebind = cur_time;
if (!write_client_lease (client, client -> active, 1, 1)) {
log_error ("Can't release lease: lease write failed.");
return;
}
log_info ("DHCPRELEASE on %s to %s port %d", log_info ("DHCPRELEASE on %s to %s port %d",
client -> name ? client -> name : client -> interface -> name, client -> name ? client -> name : client -> interface -> name,
inet_ntoa (sockaddr_broadcast.sin_addr), inet_ntoa (destination.sin_addr),
ntohs (sockaddr_broadcast.sin_port)); ntohs (destination.sin_port));
if (fallback_interface)
result = send_packet (fallback_interface,
(struct packet *)0,
&client -> packet,
client -> packet_length,
from, &destination,
(struct hardware *)0);
else
/* Send out a packet. */ /* Send out a packet. */
result = send_packet (client -> interface, (struct packet *)0, result = send_packet (client -> interface, (struct packet *)0,
&client -> packet, &client -> packet,
client -> packet_length, client -> packet_length,
inaddr_any, &sockaddr_broadcast, from, &destination,
(struct hardware *)0); (struct hardware *)0);
} }
@ -1926,11 +1958,11 @@ void rewrite_client_leases ()
for (ip = interfaces; ip; ip = ip -> next) { for (ip = interfaces; ip; ip = ip -> next) {
for (client = ip -> client; client; client = client -> next) { for (client = ip -> client; client; client = client -> next) {
for (lp = client -> leases; lp; lp = lp -> next) { for (lp = client -> leases; lp; lp = lp -> next) {
write_client_lease (client, lp, 1); write_client_lease (client, lp, 1, 0);
} }
if (client -> active) if (client -> active)
write_client_lease (client, write_client_lease (client,
client -> active, 1); client -> active, 1, 0);
} }
} }
@ -1939,20 +1971,21 @@ void rewrite_client_leases ()
for (ip = dummy_interfaces; ip; ip = ip -> next) { for (ip = dummy_interfaces; ip; ip = ip -> next) {
for (client = ip -> client; client; client = client -> next) { for (client = ip -> client; client; client = client -> next) {
for (lp = client -> leases; lp; lp = lp -> next) { for (lp = client -> leases; lp; lp = lp -> next) {
write_client_lease (client, lp, 1); write_client_lease (client, lp, 1, 0);
} }
if (client -> active) if (client -> active)
write_client_lease (client, write_client_lease (client,
client -> active, 1); client -> active, 1, 0);
} }
} }
fflush (leaseFile); fflush (leaseFile);
} }
void write_client_lease (client, lease, rewrite) int write_client_lease (client, lease, rewrite, makesure)
struct client_state *client; struct client_state *client;
struct client_lease *lease; struct client_lease *lease;
int rewrite; int rewrite;
int makesure;
{ {
int i; int i;
struct tm *t; struct tm *t;
@ -1960,6 +1993,7 @@ void write_client_lease (client, lease, rewrite)
struct option_cache *oc; struct option_cache *oc;
struct data_string ds; struct data_string ds;
pair *hash; pair *hash;
int errors = 0;
if (!rewrite) { if (!rewrite) {
if (leases_written++ > 20) { if (leases_written++ > 20) {
@ -1971,7 +2005,7 @@ void write_client_lease (client, lease, rewrite)
/* If the lease came from the config file, we don't need to stash /* If the lease came from the config file, we don't need to stash
a copy in the lease database. */ a copy in the lease database. */
if (lease -> is_static) if (lease -> is_static)
return; return 1;
if (!leaseFile) { /* XXX */ if (!leaseFile) { /* XXX */
leaseFile = fopen (path_dhclient_db, "w"); leaseFile = fopen (path_dhclient_db, "w");
@ -1979,6 +2013,7 @@ void write_client_lease (client, lease, rewrite)
log_fatal ("can't create %s: %m", path_dhclient_db); log_fatal ("can't create %s: %m", path_dhclient_db);
} }
errno = 0;
fprintf (leaseFile, "lease {\n"); fprintf (leaseFile, "lease {\n");
if (lease -> is_bootp) if (lease -> is_bootp)
fprintf (leaseFile, " bootp;\n"); fprintf (leaseFile, " bootp;\n");
@ -1997,6 +2032,10 @@ void write_client_lease (client, lease, rewrite)
if (lease -> medium) if (lease -> medium)
fprintf (leaseFile, " medium \"%s\";\n", fprintf (leaseFile, " medium \"%s\";\n",
lease -> medium -> string); lease -> medium -> string);
if (errno != 0) {
errors++;
errno = 0;
}
memset (&ds, 0, sizeof ds); memset (&ds, 0, sizeof ds);
@ -2018,6 +2057,10 @@ void write_client_lease (client, lease, rewrite)
(oc -> option -> code, (oc -> option -> code,
ds.data, ds.len, 1, 1)); ds.data, ds.len, 1, 1));
data_string_forget (&ds, MDL); data_string_forget (&ds, MDL);
if (errno != 0) {
errors++;
errno = 0;
}
} }
} }
} }
@ -2045,6 +2088,17 @@ void write_client_lease (client, lease, rewrite)
t -> tm_hour, t -> tm_min, t -> tm_sec); t -> tm_hour, t -> tm_min, t -> tm_sec);
fprintf (leaseFile, "}\n"); fprintf (leaseFile, "}\n");
fflush (leaseFile); fflush (leaseFile);
if (errno != 0) {
errors++;
errno = 0;
}
if (!errors && makesure) {
if (fsync (fileno (leaseFile)) < 0) {
log_info ("write_client_lease: %m");
return 0;
}
}
return errors ? 0 : 1;
} }
/* Variables holding name of script and file pointer for writing to /* Variables holding name of script and file pointer for writing to
@ -2357,6 +2411,9 @@ void client_location_changed ()
void do_release(client) void do_release(client)
struct client_state *client; struct client_state *client;
{ {
struct data_string ds;
struct option_cache *oc;
/* make_request doesn't initialize xid because it normally comes /* make_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */ so pick an xid now. */
@ -2367,6 +2424,24 @@ void do_release(client)
/* Make a DHCPRELEASE packet, and set appropriate per-interface /* Make a DHCPRELEASE packet, and set appropriate per-interface
flags. */ flags. */
make_release (client, client -> active); make_release (client, client -> active);
memset (&ds, 0, sizeof ds);
oc = lookup_option (&dhcp_universe,
client -> active -> options,
DHO_DHCP_SERVER_IDENTIFIER);
if (oc &&
evaluate_option_cache (&ds, (struct packet *)0,
(struct lease *)0,
(struct option_state *)0,
client -> active -> options,
&global_scope, oc, MDL)) {
if (ds.len > 3) {
memcpy (client -> destination.iabuf,
ds.data, 4);
client -> destination.len = 4;
} else
client -> destination = iaddr_broadcast;
} else
client -> destination = iaddr_broadcast; client -> destination = iaddr_broadcast;
client -> first_sending = cur_time; client -> first_sending = cur_time;
client -> interval = client -> config -> initial_interval; client -> interval = client -> config -> initial_interval;
@ -2376,13 +2451,8 @@ void do_release(client)
/* Send out the first and only DHCPRELEASE packet. */ /* Send out the first and only DHCPRELEASE packet. */
send_release (client); send_release (client);
}
/* remove the timeouts for this client */ /* Do the client script RELEASE operation. */
cancel_timeout (NULL, client);
/* if there was no lease, nothing to "do" */
if (client -> active) {
script_init (client, script_init (client,
"RELEASE", (struct string_list *)0); "RELEASE", (struct string_list *)0);
if (client -> alias) if (client -> alias)
@ -2390,6 +2460,9 @@ void do_release(client)
client -> alias); client -> alias);
script_go (client); script_go (client);
} }
/* remove the timeouts for this client */
cancel_timeout (0, client);
} }
int dhclient_interface_shutdown_hook (struct interface_info *interface) int dhclient_interface_shutdown_hook (struct interface_info *interface)

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: conflex.c,v 1.75 2000/05/16 23:02:11 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: conflex.c,v 1.76 2000/06/02 21:27:01 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -503,7 +503,7 @@ static enum dhcp_token intern (atom, dfv)
if (!strcasecmp (atom + 1, "lgorithm")) if (!strcasecmp (atom + 1, "lgorithm"))
return ALGORITHM; return ALGORITHM;
if (!strcasecmp (atom + 1, "bandoned")) if (!strcasecmp (atom + 1, "bandoned"))
return ABANDONED; return TOKEN_ABANDONED;
if (!strcasecmp (atom + 1, "dd")) if (!strcasecmp (atom + 1, "dd"))
return TOKEN_ADD; return TOKEN_ADD;
if (!strcasecmp (atom + 1, "ll")) if (!strcasecmp (atom + 1, "ll"))
@ -514,14 +514,20 @@ static enum dhcp_token intern (atom, dfv)
return ARRAY; return ARRAY;
if (!strcasecmp (atom + 1, "ddress")) if (!strcasecmp (atom + 1, "ddress"))
return ADDRESS; return ADDRESS;
if (!strcasecmp (atom + 1, "ctive"))
return TOKEN_ACTIVE;
break; break;
case 'b': case 'b':
if (!strcasecmp (atom + 1, "ackup"))
return TOKEN_BACKUP;
if (!strcasecmp (atom + 1, "ootp"))
return TOKEN_BOOTP;
if (!strcasecmp (atom + 1, "inding"))
return BINDING;
if (!strcasecmp (atom + 1, "inary-to-ascii")) if (!strcasecmp (atom + 1, "inary-to-ascii"))
return BINARY_TO_ASCII; return BINARY_TO_ASCII;
if (!strcasecmp (atom + 1, "ackoff-cutoff")) if (!strcasecmp (atom + 1, "ackoff-cutoff"))
return BACKOFF_CUTOFF; return BACKOFF_CUTOFF;
if (!strcasecmp (atom + 1, "ootp"))
return BOOTP;
if (!strcasecmp (atom + 1, "ooting")) if (!strcasecmp (atom + 1, "ooting"))
return BOOTING; return BOOTING;
if (!strcasecmp (atom + 1, "oot-unknown-clients")) if (!strcasecmp (atom + 1, "oot-unknown-clients"))
@ -575,7 +581,7 @@ static enum dhcp_token intern (atom, dfv)
if (!strcasecmp (atom + 1, "eny")) if (!strcasecmp (atom + 1, "eny"))
return DENY; return DENY;
if (!strcasecmp (atom + 1, "eleted")) if (!strcasecmp (atom + 1, "eleted"))
return DELETED; return TOKEN_DELETED;
if (!strcasecmp (atom + 1, "elete")) if (!strcasecmp (atom + 1, "elete"))
return TOKEN_DELETE; return TOKEN_DELETE;
if (!strncasecmp (atom + 1, "efault", 6)) { if (!strncasecmp (atom + 1, "efault", 6)) {
@ -619,6 +625,8 @@ static enum dhcp_token intern (atom, dfv)
return EXPIRY; return EXPIRY;
if (!strcasecmp (atom + 2, "pire")) if (!strcasecmp (atom + 2, "pire"))
return EXPIRE; return EXPIRE;
if (!strcasecmp (atom + 2, "pired"))
return TOKEN_EXPIRED;
} }
if (!strcasecmp (atom + 1, "ncode-int")) if (!strcasecmp (atom + 1, "ncode-int"))
return ENCODE_INT; return ENCODE_INT;
@ -649,6 +657,8 @@ static enum dhcp_token intern (atom, dfv)
return FUNCTION; return FUNCTION;
if (!strcasecmp (atom + 1, "ailover")) if (!strcasecmp (atom + 1, "ailover"))
return FAILOVER; return FAILOVER;
if (!strcasecmp (atom + 1, "ree"))
return TOKEN_FREE;
break; break;
case 'g': case 'g':
if (!strcasecmp (atom + 1, "iaddr")) if (!strcasecmp (atom + 1, "iaddr"))
@ -779,6 +789,8 @@ static enum dhcp_token intern (atom, dfv)
return NS_NXRRSET; return NS_NXRRSET;
if (!strcasecmp (atom + 1, "ull")) if (!strcasecmp (atom + 1, "ull"))
return TOKEN_NULL; return TOKEN_NULL;
if (!strcasecmp (atom + 1, "ext"))
return TOKEN_NEXT;
break; break;
case 'o': case 'o':
if (!strcasecmp (atom + 1, "r")) if (!strcasecmp (atom + 1, "r"))
@ -850,6 +862,12 @@ static enum dhcp_token intern (atom, dfv)
return RELEASE; return RELEASE;
if (!strcasecmp (atom + 1, "efused")) if (!strcasecmp (atom + 1, "efused"))
return NS_REFUSED; return NS_REFUSED;
if (!strcasecmp (atom + 1, "eleased"))
return TOKEN_RELEASED;
if (!strcasecmp (atom + 1, "eset"))
return TOKEN_RESET;
if (!strcasecmp (atom + 1, "eserved"))
return TOKEN_RESERVED;
break; break;
case 's': case 's':
if (!strcasecmp (atom + 1, "tate")) if (!strcasecmp (atom + 1, "tate"))

View File

@ -238,12 +238,10 @@ struct hardware {
struct lease { struct lease {
OMAPI_OBJECT_PREAMBLE; OMAPI_OBJECT_PREAMBLE;
struct lease *next; struct lease *next;
struct lease *prev;
struct lease *n_uid, *n_hw; struct lease *n_uid, *n_hw;
struct lease *waitq_next;
struct iaddr ip_addr; struct iaddr ip_addr;
TIME starts, ends, timestamp; TIME starts, ends, timestamp, sort_time;
unsigned char *uid; unsigned char *uid;
unsigned uid_len; unsigned uid_len;
unsigned uid_max; unsigned uid_max;
@ -261,18 +259,16 @@ struct lease {
struct executable_statement *on_commit; struct executable_statement *on_commit;
struct executable_statement *on_release; struct executable_statement *on_release;
int flags; u_int16_t flags;
# define STATIC_LEASE 1 # define STATIC_LEASE 1
# define BOOTP_LEASE 2
# define PERSISTENT_FLAGS (0) # define PERSISTENT_FLAGS (0)
# define MS_NULL_TERMINATION 8 # define MS_NULL_TERMINATION 8
# define ABANDONED_LEASE 16 # define ON_UPDATE_QUEUE 16
# define PEER_IS_OWNER 32 # define ON_ACK_QUEUE 32
# define ON_UPDATE_QUEUE 64 # define EPHEMERAL_FLAGS (MS_NULL_TERMINATION | \
# define ON_ACK_QUEUE 128
# define EPHEMERAL_FLAGS (BOOTP_LEASE | MS_NULL_TERMINATION | \
ABANDONED_LEASE | PEER_IS_OWNER | \
ON_ACK_QUEUE | ON_UPDATE_QUEUE) ON_ACK_QUEUE | ON_UPDATE_QUEUE)
binding_state_t binding_state; /* See failover.h, FTS_*. */
binding_state_t next_binding_state; /* See failover.h, FTS_*. */
struct lease_state *state; struct lease_state *state;
@ -500,14 +496,16 @@ struct pool {
struct shared_network *shared_network; struct shared_network *shared_network;
struct permit *permit_list; struct permit *permit_list;
struct permit *prohibit_list; struct permit *prohibit_list;
struct lease *leases; struct lease *active;
struct lease *insertion_point; struct lease *expired;
struct lease *last_lease; struct lease *free;
struct lease *next_expiry; struct lease *backup;
struct lease *abandoned;
TIME next_event_time;
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
int lease_count; int lease_count;
int local_leases; int free_leases;
int peer_leases; int backup_leases;
dhcp_failover_state_t *failover_peer; dhcp_failover_state_t *failover_peer;
#endif #endif
}; };
@ -1550,6 +1548,8 @@ extern u_int32_t fto_allowed [];
extern int ft_sizes []; extern int ft_sizes [];
extern const char *dhcp_flink_state_names []; extern const char *dhcp_flink_state_names [];
#endif #endif
extern const char *binding_state_names [];
extern struct universe agent_universe; extern struct universe agent_universe;
extern struct option agent_options [256]; extern struct option agent_options [256];
extern struct universe server_universe; extern struct universe server_universe;
@ -1617,8 +1617,8 @@ void make_release PROTO ((struct client_state *, struct client_lease *));
void destroy_client_lease PROTO ((struct client_lease *)); void destroy_client_lease PROTO ((struct client_lease *));
void rewrite_client_leases PROTO ((void)); void rewrite_client_leases PROTO ((void));
void write_client_lease PROTO ((struct client_state *, int write_client_lease PROTO ((struct client_state *,
struct client_lease *, int)); struct client_lease *, int, int));
char *dhcp_option_ev_name PROTO ((struct option *)); char *dhcp_option_ev_name PROTO ((struct option *));
void script_init PROTO ((struct client_state *, const char *, void script_init PROTO ((struct client_state *, const char *,
@ -2115,7 +2115,8 @@ void new_shared_network_interface PROTO ((struct parse *,
int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int)); int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int));
void enter_subnet PROTO ((struct subnet *)); void enter_subnet PROTO ((struct subnet *));
void enter_lease PROTO ((struct lease *)); void enter_lease PROTO ((struct lease *));
int supersede_lease PROTO ((struct lease *, struct lease *, int, int)); int supersede_lease PROTO ((struct lease *, struct lease *, int, int, int));
void process_state_transition (struct lease *);
int lease_copy PROTO ((struct lease **, struct lease *, const char *, int)); int lease_copy PROTO ((struct lease **, struct lease *, const char *, int));
void release_lease PROTO ((struct lease *, struct packet *)); void release_lease PROTO ((struct lease *, struct packet *));
void abandon_lease PROTO ((struct lease *, const char *)); void abandon_lease PROTO ((struct lease *, const char *));
@ -2205,7 +2206,7 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *);
int dhcp_failover_pool_check (struct pool *); int dhcp_failover_pool_check (struct pool *);
int dhcp_failover_state_pool_check (dhcp_failover_state_t *); int dhcp_failover_state_pool_check (dhcp_failover_state_t *);
isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *); isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *);
int dhcp_failover_queue_update (struct lease *); int dhcp_failover_queue_update (struct lease *, int);
void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *, struct lease *); void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *, struct lease *);
isc_result_t dhcp_failover_state_set_value PROTO ((omapi_object_t *, isc_result_t dhcp_failover_state_set_value PROTO ((omapi_object_t *,
omapi_object_t *, omapi_object_t *,
@ -2243,7 +2244,9 @@ failover_option_t *dhcp_failover_make_option PROTO ((unsigned, char *,
isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *, isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *,
omapi_object_t *, int, ...); omapi_object_t *, int, ...);
isc_result_t dhcp_failover_send_connect PROTO ((omapi_object_t *)); isc_result_t dhcp_failover_send_connect PROTO ((omapi_object_t *));
isc_result_t dhcp_failover_send_connectack PROTO ((omapi_object_t *, int)); isc_result_t dhcp_failover_send_connectack PROTO ((omapi_object_t *,
dhcp_failover_state_t *,
int, const char *));
isc_result_t dhcp_failover_send_disconnect PROTO ((omapi_object_t *, isc_result_t dhcp_failover_send_disconnect PROTO ((omapi_object_t *,
int, const char *)); int, const char *));
isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *, isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *,
@ -2260,6 +2263,11 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *,
void failover_print PROTO ((char *, unsigned *, unsigned, const char *)); void failover_print PROTO ((char *, unsigned *, unsigned, const char *));
void update_partner PROTO ((struct lease *)); void update_partner PROTO ((struct lease *));
int load_balance_mine (struct packet *, dhcp_failover_state_t *); int load_balance_mine (struct packet *, dhcp_failover_state_t *);
binding_state_t binding_state_transition_check (struct lease *,
dhcp_failover_state_t *,
binding_state_t);
int lease_mine_to_extend (struct lease *);
OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t, OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t,
dhcp_type_failover_state) dhcp_type_failover_state)
OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t, OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t,

View File

@ -114,7 +114,6 @@ enum dhcp_token {
EXPIRE = 308, EXPIRE = 308,
UNKNOWN_CLIENTS = 309, UNKNOWN_CLIENTS = 309,
ALLOW = 310, ALLOW = 310,
BOOTP = 311,
DENY = 312, DENY = 312,
BOOTING = 313, BOOTING = 313,
DEFAULT = 314, DEFAULT = 314,
@ -122,7 +121,7 @@ enum dhcp_token {
MEDIUM = 316, MEDIUM = 316,
ALIAS = 317, ALIAS = 317,
REBOOT = 318, REBOOT = 318,
ABANDONED = 319, TOKEN_ABANDONED = 319,
BACKOFF_CUTOFF = 320, BACKOFF_CUTOFF = 320,
INITIAL_INTERVAL = 321, INITIAL_INTERVAL = 321,
NAMESERVER = 322, NAMESERVER = 322,
@ -216,7 +215,7 @@ enum dhcp_token {
STATIC = 414, STATIC = 414,
NEVER = 415, NEVER = 415,
INFINITE = 416, INFINITE = 416,
DELETED = 417, TOKEN_DELETED = 417,
UPDATED_DNS_RR = 418, UPDATED_DNS_RR = 418,
DNS_DELETE = 419, DNS_DELETE = 419,
DUPLICATES = 420, DUPLICATES = 420,
@ -268,7 +267,17 @@ enum dhcp_token {
STATE = 466, STATE = 466,
UNKNOWN_STATE = 567, UNKNOWN_STATE = 567,
CLTT = 568, CLTT = 568,
INCLUDE = 569 INCLUDE = 569,
BINDING = 570,
TOKEN_FREE = 571,
TOKEN_ACTIVE = 572,
TOKEN_EXPIRED = 573,
TOKEN_RELEASED = 574,
TOKEN_RESET = 575,
TOKEN_BACKUP = 576,
TOKEN_RESERVED = 577,
TOKEN_BOOTP = 578,
TOKEN_NEXT = 579,
}; };
#define is_identifier(x) ((x) >= FIRST_TOKEN && \ #define is_identifier(x) ((x) >= FIRST_TOKEN && \

View File

@ -157,13 +157,17 @@ typedef struct {
#define FTR_UNKNOWN 254 #define FTR_UNKNOWN 254
/* Lease states: */ /* Lease states: */
#define FTS_FREE 1 typedef enum {
#define FTS_ACTIVE 2 FTS_FREE = 1,
#define FTS_EXPIRED 3 FTS_ACTIVE = 2,
#define FTS_RELEASED 4 FTS_EXPIRED = 3,
#define FTS_ABANDONED 5 FTS_RELEASED = 4,
#define FTS_RESET 6 FTS_ABANDONED = 5,
#define FTS_BACKUP 7 FTS_RESET = 6,
FTS_BACKUP = 7,
FTS_RESERVED = 8,
FTS_BOOTP = 9
} binding_state_t;
#define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048 #define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: confpars.c,v 1.112 2000/05/18 20:21:43 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: confpars.c,v 1.113 2000/06/02 21:27:11 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -711,6 +711,10 @@ void parse_failover_peer (cfile, group, type)
case SECONDARY: case SECONDARY:
peer -> i_am = secondary; peer -> i_am = secondary;
if (peer -> hba)
parse_warn (cfile,
"secondary may not define %s",
"load balance settings.");
break; break;
case PEER: case PEER:
@ -783,6 +787,10 @@ void parse_failover_peer (cfile, group, type)
case HBA: case HBA:
hba_len = 32; hba_len = 32;
if (peer -> i_am == secondary)
parse_warn (cfile,
"secondary may not define %s",
"load balance settings.");
if (!parse_numeric_aggregate (cfile, hba, &hba_len, if (!parse_numeric_aggregate (cfile, hba, &hba_len,
COLON, 16, 8)) { COLON, 16, 8)) {
skip_to_rbrace (cfile, 1); skip_to_rbrace (cfile, 1);
@ -806,6 +814,10 @@ void parse_failover_peer (cfile, group, type)
case SPLIT: case SPLIT:
token = next_token (&val, cfile); token = next_token (&val, cfile);
if (peer -> i_am == secondary)
parse_warn (cfile,
"secondary may not define %s",
"load balance settings.");
if (token != NUMBER) { if (token != NUMBER) {
parse_warn (cfile, "expecting number"); parse_warn (cfile, "expecting number");
badsplit: badsplit:
@ -868,6 +880,11 @@ void parse_failover_peer (cfile, group, type)
} }
} while (token != RBRACE); } while (token != RBRACE);
if (peer -> i_am == primary && !peer -> hba) {
parse_warn (cfile,
"primary failover server must have hba or split.");
}
if (type == SHARED_NET_DECL) { if (type == SHARED_NET_DECL) {
group -> shared_network -> failover_peer = peer; group -> shared_network -> failover_peer = peer;
} }
@ -1175,7 +1192,7 @@ void parse_pool_statement (cfile, group, type)
case DYNAMIC: case DYNAMIC:
permit -> type = permit_dynamic_bootp_clients; permit -> type = permit_dynamic_bootp_clients;
if (next_token (&val, cfile) != BOOTP) { if (next_token (&val, cfile) != TOKEN_BOOTP) {
parse_warn (cfile, parse_warn (cfile,
"expecting \"bootp\""); "expecting \"bootp\"");
skip_to_semi (cfile); skip_to_semi (cfile);
@ -1385,7 +1402,7 @@ void parse_host_declaration (cfile, group)
} }
/* If the host declaration was created by the server, /* If the host declaration was created by the server,
remember to save it. */ remember to save it. */
if (token == DELETED) { if (token == TOKEN_DELETED) {
deleted = 1; deleted = 1;
token = next_token (&val, cfile); token = next_token (&val, cfile);
if (!parse_semi (cfile)) if (!parse_semi (cfile))
@ -2071,7 +2088,7 @@ void parse_group_declaration (cfile, group)
token = next_token (&val, cfile); token = next_token (&val, cfile);
parse_warn (cfile, "unexpected end of file"); parse_warn (cfile, "unexpected end of file");
break; break;
} else if (token == DELETED) { } else if (token == TOKEN_DELETED) {
token = next_token (&val, cfile); token = next_token (&val, cfile);
parse_semi (cfile); parse_semi (cfile);
deletedp = 1; deletedp = 1;
@ -2215,6 +2232,7 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile)
int noequal, newbinding; int noequal, newbinding;
struct binding *binding; struct binding *binding;
isc_result_t status; isc_result_t status;
binding_state_t *statep;
lease = (struct lease *)0; lease = (struct lease *)0;
status = lease_allocate (&lease, MDL); status = lease_allocate (&lease, MDL);
@ -2351,34 +2369,76 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile)
break; break;
case DYNAMIC_BOOTP: case DYNAMIC_BOOTP:
seenbit = 128;
lease -> flags |= BOOTP_LEASE;
parse_semi (cfile);
break;
case PEER:
token = next_token (&val, cfile);
if (token != IS) {
parse_warn (cfile, "expecting \"is\".");
skip_to_rbrace (cfile, 1);
lease_dereference (&lease, MDL);
return 0;
}
token = next_token (&val, cfile);
if (token != OWNER) {
parse_warn (cfile, "expecting \"owner\".");
skip_to_rbrace (cfile, 1);
lease_dereference (&lease, MDL);
return 0;
}
seenbit = 262144;
lease -> flags |= PEER_IS_OWNER;
parse_semi (cfile);
break;
case ABANDONED:
seenbit = 256; seenbit = 256;
lease -> flags |= ABANDONED_LEASE; lease -> binding_state = FTS_BOOTP;
lease -> next_binding_state = FTS_BOOTP;
parse_semi (cfile);
break;
case TOKEN_ABANDONED:
seenbit = 256;
lease -> binding_state = FTS_ABANDONED;
lease -> next_binding_state = FTS_ABANDONED;
parse_semi (cfile);
break;
case TOKEN_NEXT:
seenbit = 128;
statep = &lease -> next_binding_state;
goto do_binding_state;
case BINDING:
seenbit = 256;
statep = &lease -> binding_state;
do_binding_state:
token = next_token (&val, cfile);
if (token != STATE) {
parse_warn (cfile, "expecting 'state'");
skip_to_semi (cfile);
break;
}
token = next_token (&val, cfile);
switch (token) {
case TOKEN_ABANDONED:
*statep = FTS_ABANDONED;
break;
case TOKEN_FREE:
*statep = FTS_FREE;
break;
case TOKEN_ACTIVE:
*statep = FTS_ACTIVE;
break;
case TOKEN_EXPIRED:
*statep = FTS_EXPIRED;
break;
case TOKEN_RELEASED:
*statep = FTS_RELEASED;
break;
case TOKEN_RESET:
*statep = FTS_RESET;
break;
case TOKEN_BACKUP:
*statep = FTS_BACKUP;
break;
case TOKEN_RESERVED:
*statep = FTS_RESERVED;
break;
case TOKEN_BOOTP:
*statep = FTS_BOOTP;
break;
default:
parse_warn (cfile,
"%s: expecting a binding state.",
val);
skip_to_semi (cfile);
break;
}
/* If no next binding state is specified, it's
the same as the current state. */
if (!(seenmask & 128) && seenbit == 256)
lease -> next_binding_state =
lease -> binding_state;
parse_semi (cfile); parse_semi (cfile);
break; break;
@ -2817,7 +2877,7 @@ int parse_allow_deny (oc, cfile, flag)
token = next_token (&val, cfile); token = next_token (&val, cfile);
switch (token) { switch (token) {
case BOOTP: case TOKEN_BOOTP:
status = option_cache (oc, (struct data_string *)0, data, status = option_cache (oc, (struct data_string *)0, data,
&server_options [SV_ALLOW_BOOTP]); &server_options [SV_ALLOW_BOOTP]);
break; break;

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: db.c,v 1.50 2000/05/16 23:03:39 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: db.c,v 1.51 2000/06/02 21:27:12 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -143,13 +143,19 @@ int write_lease (lease)
} }
} }
if (lease -> flags & PEER_IS_OWNER) { fprintf (db_file, "\n binding state %s;",
errno = 0; ((lease -> binding_state > 0 &&
fprintf (db_file, "\n peer is owner;"); lease -> binding_state <= FTS_BOOTP)
if (errno) { ? binding_state_names [lease -> binding_state - 1]
++errors; : "abandoned"));
}
} if (lease -> binding_state != lease -> next_binding_state)
fprintf (db_file, "\n next binding state %s;",
((lease -> next_binding_state > 0 &&
lease -> next_binding_state <= FTS_BOOTP)
? (binding_state_names
[lease -> next_binding_state - 1])
: "abandoned"));
/* If this lease is billed to a class and is still valid, /* If this lease is billed to a class and is still valid,
write it out. */ write it out. */
@ -190,20 +196,6 @@ int write_lease (lease)
putc (';', db_file); putc (';', db_file);
} }
} }
if (lease -> flags & BOOTP_LEASE) {
errno = 0;
fprintf (db_file, "\n dynamic-bootp;");
if (errno) {
++errors;
}
}
if (lease -> flags & ABANDONED_LEASE) {
errno = 0;
fprintf (db_file, "\n abandoned;");
if (errno) {
++errors;
}
}
for (b = lease -> scope.bindings; b; b = b -> next) { for (b = lease -> scope.bindings; b; b = b -> next) {
if (!b -> value) if (!b -> value)
continue; continue;

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: dhcp.c,v 1.150 2000/05/17 16:04:25 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: dhcp.c,v 1.151 2000/06/02 21:27:13 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -138,16 +138,11 @@ void dhcpdiscover (packet, ms_nulltp)
: packet -> interface -> name); : packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
if (lease && lease -> pool && if (lease && !lease_mine_to_extend (lease)) {
lease -> pool -> failover_peer) { log_info ("%s: letting peer %s answer", msgbuf,
peer = lease -> pool -> failover_peer; lease -> pool -> failover_peer -> name);
if ((lease -> flags & PEER_IS_OWNER) &&
peer -> my_state == normal) {
log_info ("%s: letting peer %s respond.",
msgbuf, peer -> name);
goto out; goto out;
} }
}
#endif #endif
/* Sourceless packets don't make sense here. */ /* Sourceless packets don't make sense here. */
@ -191,7 +186,7 @@ void dhcpdiscover (packet, ms_nulltp)
if (allocatedp && lease && lease -> pool && if (allocatedp && lease && lease -> pool &&
lease -> pool -> failover_peer) { lease -> pool -> failover_peer) {
peer = lease -> pool -> failover_peer; peer = lease -> pool -> failover_peer;
if (peer -> hba && peer -> my_state == normal) { if (peer -> my_state == normal) {
if (!load_balance_mine (packet, peer)) { if (!load_balance_mine (packet, peer)) {
log_debug ("%s: load balance to peer %s", log_debug ("%s: load balance to peer %s",
msgbuf, peer -> name); msgbuf, peer -> name);
@ -256,6 +251,7 @@ void dhcprequest (packet, ms_nulltp)
find_lease (&lease, packet, find_lease (&lease, packet,
subnet -> shared_network, &ours, MDL); subnet -> shared_network, &ours, MDL);
if (lease && lease -> client_hostname && if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname)) db_printable (lease -> client_hostname))
s = lease -> client_hostname; s = lease -> client_hostname;
@ -278,6 +274,14 @@ void dhcprequest (packet, ms_nulltp)
? inet_ntoa (packet -> raw -> giaddr) ? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name); : packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL)
if (lease && !lease_mine_to_extend (lease)) {
log_info ("%s: letting peer %s answer", msgbuf,
lease -> pool -> failover_peer -> name);
goto out;
}
#endif
/* If a client on a given network REQUESTs a lease on an /* If a client on a given network REQUESTs a lease on an
address on a different network, NAK it. If the Requested address on a different network, NAK it. If the Requested
Address option was used, the protocol says that it must Address option was used, the protocol says that it must
@ -360,7 +364,7 @@ void dhcprequest (packet, ms_nulltp)
} }
} }
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL) && 0 /* XXX this isn't the same as above! */
/* If we found a lease, but it belongs to a failover peer, and /* If we found a lease, but it belongs to a failover peer, and
the client is in the SELECTING state, ignore the request - the client is in the SELECTING state, ignore the request -
it's not ours. */ it's not ours. */
@ -420,6 +424,7 @@ void dhcprelease (packet, ms_nulltp)
struct option_cache *oc; struct option_cache *oc;
struct data_string data; struct data_string data;
char *s; char *s;
char msgbuf [1024]; /* XXX */
/* DHCPRELEASE must not specify address in requested-address /* DHCPRELEASE must not specify address in requested-address
option, but old protocol specs weren't explicit about this, option, but old protocol specs weren't explicit about this,
@ -469,7 +474,8 @@ void dhcprelease (packet, ms_nulltp)
s = (char *)0; s = (char *)0;
/* Say what we're doing... */ /* Say what we're doing... */
log_info ("DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)", sprintf (msgbuf,
"DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
inet_ntoa (packet -> raw -> ciaddr), inet_ntoa (packet -> raw -> ciaddr),
(packet -> raw -> htype (packet -> raw -> htype
? print_hw_addr (packet -> raw -> htype, ? print_hw_addr (packet -> raw -> htype,
@ -485,11 +491,27 @@ void dhcprelease (packet, ms_nulltp)
: packet -> interface -> name, : packet -> interface -> name,
lease ? "" : "not "); lease ? "" : "not ");
#if defined (FAILOVER_PROTOCOL)
if (lease && !lease_mine_to_extend (lease)) {
/* DHCPRELEASE messages are unicast, so if the client
sent the DHCPRELEASE to us, it's not going to send it
to the peer. Not sure why this would happen, and
if it does happen I think we still have to change the
lease state.
XXX See what it says in the draft about this. */
log_info ("%s: peer %s holds lease",
msgbuf, lease -> pool -> failover_peer -> name);
}
#endif
/* If we found a lease, release it. */ /* If we found a lease, release it. */
if (lease && lease -> ends > cur_time) { if (lease && lease -> ends > cur_time) {
release_lease (lease, packet); release_lease (lease, packet);
lease_dereference (&lease, MDL); log_info ("%s", msgbuf);
} }
out:
if (lease)
lease_dereference (&lease, MDL);
} }
void dhcpdecline (packet, ms_nulltp) void dhcpdecline (packet, ms_nulltp)
@ -505,6 +527,7 @@ void dhcpdecline (packet, ms_nulltp)
int i; int i;
const char *status; const char *status;
char *s; char *s;
char msgbuf [1024]; /* XXX */
/* DHCPDECLINE must specify address. */ /* DHCPDECLINE must specify address. */
if (!(oc = lookup_option (&dhcp_universe, packet -> options, if (!(oc = lookup_option (&dhcp_universe, packet -> options,
@ -522,6 +545,36 @@ void dhcpdecline (packet, ms_nulltp)
data_string_forget (&data, MDL); data_string_forget (&data, MDL);
find_lease_by_ip_addr (&lease, cip, MDL); find_lease_by_ip_addr (&lease, cip, MDL);
if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname))
s = lease -> client_hostname;
else
s = (char *)0;
sprintf (msgbuf, "DHCPDECLINE of %s from %s %s%s%svia %s",
piaddr (cip),
(packet -> raw -> htype
? print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr)
: (lease
? print_hex_1 (lease -> uid_len, lease -> uid,
lease -> uid_len)
: "<no identifier>")),
s ? "(" : "", s ? s : "", s ? ") " : "",
packet -> raw -> giaddr.s_addr
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL)
if (lease && !lease_mine_to_extend (lease)) {
if (!ignorep)
log_info ("%s: peer %s holds lease", msgbuf,
lease -> pool -> failover_peer -> name);
goto out;
}
#endif
option_state_allocate (&options, MDL); option_state_allocate (&options, MDL);
/* Execute statements in scope starting with the subnet scope. */ /* Execute statements in scope starting with the subnet scope. */
@ -549,37 +602,17 @@ void dhcpdecline (packet, ms_nulltp)
/* If we found a lease, mark it as unusable and complain. */ /* If we found a lease, mark it as unusable and complain. */
if (lease) { if (lease) {
abandon_lease (lease, "declined."); abandon_lease (lease, "declined.");
status = ""; status = "abandoned";
} }
status = " (not found)"; status = "not found";
} else } else
status = " (ignored)"; status = "ignored";
if (!ignorep) { if (!ignorep)
char *s; log_info ("%s: %s", msgbuf, status);
if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname))
s = lease -> client_hostname;
else
s = (char *)0;
log_info ("DHCPDECLINE of %s from %s %s%s%svia %s %s",
piaddr (cip),
(packet -> raw -> htype
? print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr)
: (lease
? print_hex_1 (lease -> uid_len, lease -> uid,
lease -> uid_len)
: "<no identifier>")),
s ? "(" : "", s ? s : "", s ? ") " : "",
packet -> raw -> giaddr.s_addr
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name,
status);
}
out:
if (options)
option_state_dereference (&options, MDL); option_state_dereference (&options, MDL);
if (lease) if (lease)
lease_dereference (&lease, MDL); lease_dereference (&lease, MDL);
@ -1358,7 +1391,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
/* Try to find a matching host declaration for this lease. */ /* Try to find a matching host declaration for this lease. */
if (!lease -> host) { if (!lease -> host) {
struct host_decl *hp; struct host_decl *hp = (struct host_decl *)0;
struct host_decl *h;
/* Try to find a host_decl that matches the client /* Try to find a host_decl that matches the client
identifier or hardware address on the packet, and identifier or hardware address on the packet, and
@ -1371,11 +1405,12 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
evaluate_option_cache (&d1, packet, lease, evaluate_option_cache (&d1, packet, lease,
packet -> options, state -> options, packet -> options, state -> options,
&lease -> scope, oc, MDL)) { &lease -> scope, oc, MDL)) {
struct host_decl *h;
hp = (struct host_decl *)0;
find_hosts_by_uid (&hp, d1.data, d1.len, MDL); find_hosts_by_uid (&hp, d1.data, d1.len, MDL);
data_string_forget (&d1, MDL); data_string_forget (&d1, MDL);
if (!hp) if (hp)
host_reference (&lease -> host, hp, MDL);
}
if (!hp) {
find_hosts_by_haddr (&hp, find_hosts_by_haddr (&hp,
packet -> raw -> htype, packet -> raw -> htype,
packet -> raw -> chaddr, packet -> raw -> chaddr,
@ -1387,10 +1422,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
} }
if (h) if (h)
host_reference (&lease -> host, hp, MDL); host_reference (&lease -> host, hp, MDL);
}
if (hp) if (hp)
host_dereference (&hp, MDL); host_dereference (&hp, MDL);
} else
lease -> host = (struct host_decl *)0;
} }
/* Drop the request if it's not allowed for this client. By /* Drop the request if it's not allowed for this client. By
@ -1640,6 +1674,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
lt -> ends = when; lt -> ends = when;
else else
lt -> ends = state -> offered_expiry; lt -> ends = state -> offered_expiry;
lt -> next_binding_state = FTS_ACTIVE;
} else { } else {
lease_time = MAX_TIME - cur_time; lease_time = MAX_TIME - cur_time;
@ -1669,7 +1704,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
} }
lt -> ends = state -> offered_expiry = cur_time + lease_time; lt -> ends = state -> offered_expiry = cur_time + lease_time;
lt -> flags = BOOTP_LEASE; lt -> next_binding_state = FTS_BOOTP;
} }
lt -> timestamp = cur_time; lt -> timestamp = cur_time;
@ -1752,29 +1787,13 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
it) either. */ it) either. */
if (!(supersede_lease (lease, lt, !offer || offer == DHCPACK, if (!(supersede_lease (lease, lt, !offer || offer == DHCPACK,
offer == DHCPACK) offer == DHCPACK, offer == DHCPACK)
|| (offer && offer != DHCPACK))) { || (offer && offer != DHCPACK))) {
log_info ("%s: database update failed", msg); log_info ("%s: database update failed", msg);
free_lease_state (state, MDL); free_lease_state (state, MDL);
static_lease_dereference (lease, MDL); static_lease_dereference (lease, MDL);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
return; return;
} else {
/* If this is a DHCPOFFER transaction, supersede_lease
will not add the timer for the expire event to the
queue. This is because DHCPOFFERS are not commited,
and supersede_lease only adds commited leases to the
timer queue. So if supersede_lease set this lease
as the next one to expire for the pool we need to
put it on the timer queue ourself. */
/* XXX need to think about this. */
if (offer == DHCPOFFER && lease -> pool &&
lease -> pool -> next_expiry == lease)
add_timeout (lease -> ends, pool_timer,
lease -> pool,
(tvref_t)omapi_object_reference,
(tvunref_t)
omapi_object_dereference);
} }
} }
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
@ -2637,7 +2656,6 @@ int find_lease (struct lease **lp,
/* Toss ip_lease if it hasn't yet expired and doesn't belong to the /* Toss ip_lease if it hasn't yet expired and doesn't belong to the
client. */ client. */
if (ip_lease && if (ip_lease &&
ip_lease -> ends >= cur_time &&
((ip_lease -> uid && ((ip_lease -> uid &&
(!have_client_identifier || (!have_client_identifier ||
ip_lease -> uid_len != client_identifier.len || ip_lease -> uid_len != client_identifier.len ||
@ -2649,25 +2667,43 @@ int find_lease (struct lease **lp,
memcmp (&ip_lease -> hardware_addr.hbuf [1], memcmp (&ip_lease -> hardware_addr.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> chaddr,
(unsigned)(ip_lease -> hardware_addr.hlen - 1)))))) { (unsigned)(ip_lease -> hardware_addr.hlen - 1)))))) {
/* If we're not doing failover, the only state in which
we can allocate this lease to the client is FTS_FREE.
If we are doing failover, and this lease is part of a
failover pool, then if we're the primary, state has to be
FTS_FREE; if we're the secondary, state has to be
FTS_BACKUP. */
if ((ip_lease -> binding_state != FTS_FREE &&
ip_lease -> binding_state != FTS_BACKUP)
#if defined (FAILOVER_PROTOCOL)
||
(ip_lease -> pool -> failover_peer &&
((ip_lease -> binding_state == FTS_FREE &&
ip_lease -> pool -> failover_peer -> i_am == secondary)
||
(ip_lease -> binding_state == FTS_BACKUP &&
ip_lease -> pool -> failover_peer -> i_am == primary)))
#endif
) {
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
if (ip_lease)
log_info ("rejecting lease for requested address."); log_info ("rejecting lease for requested address.");
#endif #endif
lease_dereference (&ip_lease, MDL); lease_dereference (&ip_lease, MDL);
} }
}
/* If for some reason the client has more than one lease /* If for some reason the client has more than one lease
on the subnet that matches its uid, pick the one that on the subnet that matches its uid, pick the one that
it asked for and (if we can) free the other. */ it asked for and (if we can) free the other. */
if (ip_lease && if (ip_lease &&
ip_lease -> ends >= cur_time && ip_lease -> binding_state == FTS_ACTIVE &&
ip_lease -> uid && ip_lease != uid_lease) { ip_lease -> uid && ip_lease != uid_lease) {
if (have_client_identifier && if (have_client_identifier &&
(ip_lease -> uid_len == client_identifier.len) && (ip_lease -> uid_len == client_identifier.len) &&
!memcmp (client_identifier.data, !memcmp (client_identifier.data,
ip_lease -> uid, ip_lease -> uid_len)) { ip_lease -> uid, ip_lease -> uid_len)) {
if (uid_lease) { if (uid_lease) {
if (uid_lease -> ends > cur_time) { if (uid_lease -> binding_state == FTS_ACTIVE) {
log_error ("client %s has duplicate%s on %s", log_error ("client %s has duplicate%s on %s",
(print_hw_addr (print_hw_addr
(packet -> raw -> htype, (packet -> raw -> htype,
@ -2722,17 +2758,6 @@ int find_lease (struct lease **lp,
if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease) if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease)
goto db_conflict; goto db_conflict;
/* Make sure the client is permitted to use the requested lease. */
if (ip_lease &&
((ip_lease -> pool -> prohibit_list &&
permitted (packet, ip_lease -> pool -> prohibit_list)) ||
(ip_lease -> pool -> permit_list &&
!permitted (packet, ip_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (ip_lease, packet);
lease_dereference (&ip_lease, MDL);
}
/* Toss extra pointers to the same lease... */ /* Toss extra pointers to the same lease... */
if (hw_lease && hw_lease == uid_lease) { if (hw_lease && hw_lease == uid_lease) {
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
@ -2753,6 +2778,37 @@ int find_lease (struct lease **lp,
#endif #endif
} }
/* Make sure the client is permitted to use the requested lease. */
if (ip_lease &&
((ip_lease -> pool -> prohibit_list &&
permitted (packet, ip_lease -> pool -> prohibit_list)) ||
(ip_lease -> pool -> permit_list &&
!permitted (packet, ip_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (ip_lease, packet);
lease_dereference (&ip_lease, MDL);
}
if (uid_lease &&
((uid_lease -> pool -> prohibit_list &&
permitted (packet, uid_lease -> pool -> prohibit_list)) ||
(uid_lease -> pool -> permit_list &&
!permitted (packet, uid_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (uid_lease, packet);
lease_dereference (&uid_lease, MDL);
}
if (hw_lease &&
((hw_lease -> pool -> prohibit_list &&
permitted (packet, hw_lease -> pool -> prohibit_list)) ||
(hw_lease -> pool -> permit_list &&
!permitted (packet, hw_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (hw_lease, packet);
lease_dereference (&hw_lease, MDL);
}
/* If we've already eliminated the lease, it wasn't there to /* If we've already eliminated the lease, it wasn't there to
begin with. If we have come up with a matching lease, begin with. If we have come up with a matching lease,
set the message to bad network in case we have to throw it out. */ set the message to bad network in case we have to throw it out. */
@ -2862,12 +2918,13 @@ int find_lease (struct lease **lp,
requested, we assume that previous bugginess on the part requested, we assume that previous bugginess on the part
of the client, or a server database loss, caused the lease to of the client, or a server database loss, caused the lease to
be abandoned, so we reclaim it and let the client have it. */ be abandoned, so we reclaim it and let the client have it. */
if (lease && (lease -> flags & ABANDONED_LEASE) && lease == ip_lease && if (lease &&
(lease -> binding_state == FTS_ABANDONED) &&
lease == ip_lease &&
packet -> packet_type == DHCPREQUEST) { packet -> packet_type == DHCPREQUEST) {
log_error ("Reclaiming REQUESTed abandoned IP address %s.", log_error ("Reclaiming REQUESTed abandoned IP address %s.",
piaddr (lease -> ip_addr)); piaddr (lease -> ip_addr));
lease -> flags &= ~ABANDONED_LEASE; } else if (lease && (lease -> binding_state == FTS_ABANDONED)) {
} else if (lease && (lease -> flags & ABANDONED_LEASE)) {
/* Otherwise, if it's not the one the client requested, we do not /* Otherwise, if it's not the one the client requested, we do not
return it - instead, we claim it's ours, causing a DHCPNAK to be return it - instead, we claim it's ours, causing a DHCPNAK to be
sent if this lookup is for a DHCPREQUEST, and force the client sent if this lookup is for a DHCPREQUEST, and force the client
@ -2941,6 +2998,7 @@ int mockup_lease (struct lease **lp, struct packet *packet,
lease -> hardware_addr = hp -> interface; lease -> hardware_addr = hp -> interface;
lease -> starts = lease -> timestamp = lease -> ends = MIN_TIME; lease -> starts = lease -> timestamp = lease -> ends = MIN_TIME;
lease -> flags = STATIC_LEASE; lease -> flags = STATIC_LEASE;
lease -> binding_state = FTS_FREE;
lease_reference (lp, lease, MDL); lease_reference (lp, lease, MDL);
lease_dereference (&lease, MDL); lease_dereference (&lease, MDL);
return 1; return 1;
@ -2986,6 +3044,7 @@ int allocate_lease (struct lease **lp, struct packet *packet,
struct pool *pool, int *peer_has_leases) struct pool *pool, int *peer_has_leases)
{ {
struct lease *lease = (struct lease *)0; struct lease *lease = (struct lease *)0;
struct lease **lq;
struct permit *permit; struct permit *permit;
if (!pool) if (!pool)
@ -2998,31 +3057,39 @@ int allocate_lease (struct lease **lp, struct packet *packet,
return allocate_lease (lp, packet, pool -> next, return allocate_lease (lp, packet, pool -> next,
peer_has_leases); peer_has_leases);
lease = pool -> last_lease;
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
/* Peer_has_leases just says that we found at least one free lease. /* Peer_has_leases just says that we found at least one free lease.
If no free lease is returned, the caller can deduce that this If no free lease is returned, the caller can deduce that this
means the peer is hogging all the free leases, so we can print means the peer is hogging all the free leases, so we can print
a better error message. */ a better error message. */
if (lease)
*peer_has_leases = 1;
/* XXX Do we need code here to ignore PEER_IS_OWNER and just check /* XXX Do we need code here to ignore PEER_IS_OWNER and just check
XXX tstp if we're in, e.g., PARTNER_DOWN? Where do we deal with XXX tstp if we're in, e.g., PARTNER_DOWN? Where do we deal with
XXX CONFLICT_DETECTED, et al? */ XXX CONFLICT_DETECTED, et al? */
/* XXX This should be handled by the lease binding "state machine" -
XXX that is, when we get here, if a lease could be allocated, it
XXX will have the correct binding state so that the following code
XXX will result in its being allocated. */
/* Skip to the most expired lease in the pool that is not owned by a /* Skip to the most expired lease in the pool that is not owned by a
failover peer. */ failover peer. */
if (lease -> pool && lease -> pool -> failover_peer) { if (pool -> failover_peer) {
while (lease && if (pool -> failover_peer -> i_am == primary) {
(lease -> flags & PEER_IS_OWNER) && if (pool -> backup)
(lease -> ends <= *peer_has_leases = 1;
cur_time + lease -> pool -> failover_peer -> mclt)) lease = pool -> free;
lease = lease -> prev; if (!lease)
/* We didn't find an unexpired lease that we own? */ lease = pool -> abandoned;
if (lease && lease -> flags & PEER_IS_OWNER) } else {
lease = (struct lease *)0; if (pool -> free)
*peer_has_leases = 1;
lease = pool -> backup;
} }
}
#else
if (pool -> free)
lease = pool -> free;
else
lease = pool -> abandoned;
#endif #endif
/* If there are no leases in the pool that have /* If there are no leases in the pool that have
@ -3035,7 +3102,7 @@ int allocate_lease (struct lease **lp, struct packet *packet,
better, take it. */ better, take it. */
/* XXX what if there are non-abandoned leases that are younger /* XXX what if there are non-abandoned leases that are younger
XXX than this? Shouldn't we hunt for those here? */ XXX than this? Shouldn't we hunt for those here? */
if ((lease -> flags & ABANDONED_LEASE)) { if (lease -> binding_state == FTS_ABANDONED) {
/* If we already have a non-abandoned lease that we didn't /* If we already have a non-abandoned lease that we didn't
love, but that's okay, don't reclaim the abandoned lease. */ love, but that's okay, don't reclaim the abandoned lease. */
if (*lp) if (*lp)
@ -3045,7 +3112,6 @@ int allocate_lease (struct lease **lp, struct packet *packet,
pool -> next, peer_has_leases)) { pool -> next, peer_has_leases)) {
log_error ("Reclaiming abandoned IP address %s.", log_error ("Reclaiming abandoned IP address %s.",
piaddr (lease -> ip_addr)); piaddr (lease -> ip_addr));
lease -> flags &= ~ABANDONED_LEASE;
lease_reference (lp, lease, MDL); lease_reference (lp, lease, MDL);
} }
return 1; return 1;

View File

@ -1272,18 +1272,21 @@ override the use of the name in the host declaration.
\fBnot authoritative;\fR \fBnot authoritative;\fR
.PP .PP
The DHCP server will normally assume that the configuration The DHCP server will normally assume that the configuration
information about a given network segment is known to be correct and information about a given network segment is not known to be correct
is authoritative. So if a client requests an IP address on a given and is not authoritative. This is so that if a naive user installs a
network segment that the server knows is not valid for that segment, DHCP server not fully understanding how to configure it, it does not
the server will respond with a DHCPNAK message, causing the client to send spurious DHCPNAK messages to clients that have obtained addresses
forget its IP address and try to get a new one. from a legitimate DHCP server on the network.
.PP .PP
If a DHCP server is being configured by somebody who is not the Network administrators setting up authoritative DHCP servers for their
network administrator and who therefore does not wish to assert this networks should always write \fBauthoritative;\fR at the top of their
level of authority, then the statement "not authoritative" should be configuration file to indicate that the DHCP server \fIshould\fR send
written in the appropriate scope in the configuration file. DHCPNAK messages to misconfigured clients. If this is not done,
clients will be unable to get a correct IP address after changing
subnets until their old lease has expired, which could take quite a
long time.
.PP .PP
Usually, writing \fBnot authoritative;\fR at the top level of the file Usually, writing \fBauthoritative;\fR at the top level of the file
should be sufficient. However, if a DHCP server is to be set up so should be sufficient. However, if a DHCP server is to be set up so
that it is aware of some networks for which it is authoritative and that it is aware of some networks for which it is authoritative and
some networks for which it is not, it may be more appropriate to some networks for which it is not, it may be more appropriate to

View File

@ -1478,22 +1478,25 @@ dhcpd.conf(5) dhcpd.conf(5)
nnoott aauutthhoorriittaattiivvee;; nnoott aauutthhoorriittaattiivvee;;
The DHCP server will normally assume that the configura­ The DHCP server will normally assume that the configura­
tion information about a given network segment is known to tion information about a given network segment is not
be correct and is authoritative. So if a client requests known to be correct and is not authoritative. This is so
an IP address on a given network segment that the server that if a naive user installs a DHCP server not fully
knows is not valid for that segment, the server will understanding how to configure it, it does not send spuri­
respond with a DHCPNAK message, causing the client to for­ ous DHCPNAK messages to clients that have obtained
get its IP address and try to get a new one. addresses from a legitimate DHCP server on the network.
If a DHCP server is being configured by somebody who is Network administrators setting up authoritative DHCP
not the network administrator and who therefore does not servers for their networks should always write aauutthhoorriittaa­­
wish to assert this level of authority, then the statement ttiivvee;; at the top of their configuration file to indicate
"not authoritative" should be written in the appropriate that the DHCP server _s_h_o_u_l_d send DHCPNAK messages to mis­
scope in the configuration file. configured clients. If this is not done, clients will be
unable to get a correct IP address after changing subnets
until their old lease has expired, which could take quite
a long time.
Usually, writing nnoott aauutthhoorriittaattiivvee;; at the top level of Usually, writing aauutthhoorriittaattiivvee;; at the top level of the
the file should be sufficient. However, if a DHCP server file should be sufficient. However, if a DHCP server is
is to be set up so that it is aware of some networks for to be set up so that it is aware of some networks for
which it is authoritative and some networks for which it which it is authoritative and some networks for which it
is not, it may be more appropriate to declare authority on is not, it may be more appropriate to declare authority on
a per-network-segment basis. a per-network-segment basis.
@ -1508,9 +1511,6 @@ dhcpd.conf(5) dhcpd.conf(5)
that the server is authoritative for some host declara­ that the server is authoritative for some host declara­
tions and not others. tions and not others.
TThhee _a_l_w_a_y_s_-_r_e_p_l_y_-_r_f_c_1_0_4_8 ssttaatteemmeenntt
23 23
@ -1522,6 +1522,8 @@ dhcpd.conf(5) dhcpd.conf(5)
dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5)
TThhee _a_l_w_a_y_s_-_r_e_p_l_y_-_r_f_c_1_0_4_8 ssttaatteemmeenntt
aallwwaayyss--rreeppllyy--rrffcc11004488 _f_l_a_g;; aallwwaayyss--rreeppllyy--rrffcc11004488 _f_l_a_g;;
Some BOOTP clients expect RFC1048-style responses, but do Some BOOTP clients expect RFC1048-style responses, but do
@ -1574,8 +1576,6 @@ dhcpd.conf(5) dhcpd.conf(5)
uussee--lleeaassee--aaddddrr--ffoorr--ddeeffaauulltt--rroouuttee _f_l_a_g;; uussee--lleeaassee--aaddddrr--ffoorr--ddeeffaauulltt--rroouuttee _f_l_a_g;;
If the _u_s_e_-_l_e_a_s_e_-_a_d_d_r_-_f_o_r_-_d_e_f_a_u_l_t_-_r_o_u_t_e parameter is true
in a given scope, then instead of sending the value
@ -1588,11 +1588,13 @@ dhcpd.conf(5) dhcpd.conf(5)
dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5)
specified in the routers option (or sending no value at If the _u_s_e_-_l_e_a_s_e_-_a_d_d_r_-_f_o_r_-_d_e_f_a_u_l_t_-_r_o_u_t_e parameter is true
all), the IP address of the lease being assigned is sent in a given scope, then instead of sending the value speci­
to the client. This supposedly causes Win95 machines to fied in the routers option (or sending no value at all),
ARP for all IP addresses, which can be helpful if your the IP address of the lease being assigned is sent to the
router is configured for proxy ARP. client. This supposedly causes Win95 machines to ARP for
all IP addresses, which can be helpful if your router is
configured for proxy ARP.
TThhee _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r ssttaatteemmeenntt TThhee _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r ssttaatteemmeenntt
@ -1640,8 +1642,6 @@ RREEFFEERREENNCCEE:: OOPPTTIIOONN SSTTAATTEEMMEENNTTSS
SSEEEE AALLSSOO SSEEEE AALLSSOO
dhcpd.conf(5), dhcpd.leases(5), RFC2132, RFC2131. dhcpd.conf(5), dhcpd.leases(5), RFC2132, RFC2131.
AAUUTTHHOORR
ddhhccppdd((88)) was written by Ted Lemon <mellon@vix.com> under a
@ -1654,6 +1654,8 @@ AAUUTTHHOORR
dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5)
AAUUTTHHOORR
ddhhccppdd((88)) was written by Ted Lemon <mellon@vix.com> under a
contract with Vixie Labs. Funding for this project was contract with Vixie Labs. Funding for this project was
provided by the Internet Software Consortium. Information provided by the Internet Software Consortium. Information
about the Internet Software Consortium can be found at about the Internet Software Consortium can be found at
@ -1706,8 +1708,6 @@ dhcpd.conf(5) dhcpd.conf(5)

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: failover.c,v 1.15 2000/05/17 16:04:26 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: failover.c,v 1.16 2000/06/02 21:27:17 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -383,6 +383,8 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
a state object. */ a state object. */
/* XXX this should be authenticated! */ /* XXX this should be authenticated! */
if (link -> imsg -> type == FTM_CONNECT) { if (link -> imsg -> type == FTM_CONNECT) {
const char *errmsg;
int reason;
/* See if we can find a failover_state object that /* See if we can find a failover_state object that
matches this connection. This message should only matches this connection. This message should only
be received by a secondary from a primary. */ be received by a secondary from a primary. */
@ -396,10 +398,13 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
/* If we can't find a failover protocol state /* If we can't find a failover protocol state
for this remote host, drop the connection */ for this remote host, drop the connection */
if (!state) { if (!state) {
errmsg = "unknown server";
reason = FTR_INVALID_PARTNER;
badconnect:
/* XXX Send a refusal message first? /* XXX Send a refusal message first?
XXX Look in protocol spec for guidance. */ XXX Look in protocol spec for guidance. */
log_error ("Failover CONNECT from %s %d.%d.%d.%d", log_error ("Failover CONNECT from %d.%d.%d.%d: %s",
"unknown server",
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [0], (&link -> imsg -> server_addr)) [0],
((u_int8_t *) ((u_int8_t *)
@ -407,15 +412,32 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [2], (&link -> imsg -> server_addr)) [2],
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [3]); (&link -> imsg -> server_addr)) [3],
errmsg);
dhcp_failover_send_connectack dhcp_failover_send_connectack
((omapi_object_t *)link, ((omapi_object_t *)link, state,
FTR_INVALID_PARTNER); reason, errmsg);
omapi_disconnect (c, 0); omapi_disconnect (c, 0);
link -> state = dhcp_flink_disconnected; link -> state = dhcp_flink_disconnected;
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }
if (!(link -> imsg -> options_present & FTB_HBA) ||
link -> imsg -> hba.count != 32) {
errmsg = "invalid HBA";
reason = FTR_HBA_CONFLICT; /* XXX */
goto badconnect;
}
if (state -> hba)
dfree (state -> hba, MDL);
state -> hba = dmalloc (32, MDL);
if (!state -> hba) {
errmsg = "no memory";
reason = FTR_MISC_REJECT;
goto badconnect;
}
memcpy (state -> hba, link -> imsg -> hba.data, 32);
if (!link -> state_object) if (!link -> state_object)
dhcp_failover_state_reference dhcp_failover_state_reference
(&link -> state_object, state, MDL); (&link -> state_object, state, MDL);
@ -567,7 +589,7 @@ static isc_result_t do_a_failover_option (c, link)
ft_options [option_code].type == FT_DDNS1) { ft_options [option_code].type == FT_DDNS1) {
ddns_fqdn_t *ddns = ddns_fqdn_t *ddns =
((ddns_fqdn_t *) ((ddns_fqdn_t *)
(((char *)&link -> imsg) + (((char *)link -> imsg) +
ft_options [option_code].offset)); ft_options [option_code].offset));
op_count = (ft_options [option_code].type == FT_DDNS1 op_count = (ft_options [option_code].type == FT_DDNS1
@ -613,7 +635,7 @@ static isc_result_t do_a_failover_option (c, link)
op_count = option_len / op_size; op_count = option_len / op_size;
fo = ((failover_option_t *) fo = ((failover_option_t *)
(((char *)&link -> imsg) + (((char *)link -> imsg) +
ft_options [option_code].offset)); ft_options [option_code].offset));
fo -> count = op_count; fo -> count = op_count;
@ -1052,7 +1074,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
dhcp_failover_link_reference (&state -> link_to_peer, dhcp_failover_link_reference (&state -> link_to_peer,
link, MDL); link, MDL);
status = (dhcp_failover_send_connectack status = (dhcp_failover_send_connectack
((omapi_object_t *)link, 0)); ((omapi_object_t *)link, state, 0, 0));
if (status != ISC_R_SUCCESS) { if (status != ISC_R_SUCCESS) {
dhcp_failover_link_dereference dhcp_failover_link_dereference
(&state -> link_to_peer, MDL); (&state -> link_to_peer, MDL);
@ -1061,8 +1083,10 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
} }
dhcp_failover_state_transition (state, "connect"); dhcp_failover_state_transition (state, "connect");
} else if (link -> imsg -> type == FTM_CONNECTACK) { } else if (link -> imsg -> type == FTM_CONNECTACK) {
const char *errmsg;
int reason;
if (link -> imsg -> reject_reason) { if (link -> imsg -> reject_reason) {
log_error ("Failover CONNECTACK from %d.%d.%d.%d%s%s", log_error ("Failover CONNECT to %d.%d.%d.%d%s%s",
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [0], (&link -> imsg -> server_addr)) [0],
((u_int8_t *) ((u_int8_t *)
@ -1074,6 +1098,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
" rejected: ", " rejected: ",
(dhcp_failover_reject_reason_print (dhcp_failover_reject_reason_print
(link -> imsg -> reject_reason))); (link -> imsg -> reject_reason)));
/* XXX print message from peer if peer sent message. */
omapi_disconnect (link -> outer, 1); omapi_disconnect (link -> outer, 1);
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }
@ -1082,8 +1107,10 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
(state, (state,
(u_int8_t *)&link -> imsg -> server_addr, (u_int8_t *)&link -> imsg -> server_addr,
sizeof link -> imsg -> server_addr)) { sizeof link -> imsg -> server_addr)) {
log_error ("Failover CONNECTACK from %s %d.%d.%d.%d", errmsg = "unknown server";
"unknown server", reason = FTR_INVALID_PARTNER;
badconnectack:
log_error ("Failover CONNECTACK from %d.%d.%d.%d: %s",
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [0], (&link -> imsg -> server_addr)) [0],
((u_int8_t *) ((u_int8_t *)
@ -1091,27 +1118,19 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [2], (&link -> imsg -> server_addr)) [2],
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [3]); (&link -> imsg -> server_addr)) [3],
errmsg);
dhcp_failover_send_disconnect ((omapi_object_t *)link, dhcp_failover_send_disconnect ((omapi_object_t *)link,
FTR_INVALID_PARTNER, 0); reason, errmsg);
omapi_disconnect (link -> outer, 0); omapi_disconnect (link -> outer, 0);
} }
if (state -> link_to_peer) { if (state -> link_to_peer) {
log_error ("Failover CONNECTACK %s %d.%d.%d.%d", errmsg = "already connected";
"while already connected", reason = FTR_DUP_CONNECTION;
((u_int8_t *) goto badconnectack;
(&link -> imsg -> server_addr)) [0],
((u_int8_t *)
(&link -> imsg -> server_addr)) [1],
((u_int8_t *)
(&link -> imsg -> server_addr)) [2],
((u_int8_t *)
(&link -> imsg -> server_addr)) [3]);
dhcp_failover_send_disconnect ((omapi_object_t *)link,
FTR_DUP_CONNECTION, 0);
omapi_disconnect (link -> outer, 0);
} }
dhcp_failover_link_reference (&state -> link_to_peer, dhcp_failover_link_reference (&state -> link_to_peer,
link, MDL); link, MDL);
dhcp_failover_state_transition (state, "connect"); dhcp_failover_state_transition (state, "connect");
@ -1331,9 +1350,14 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state)
{ {
int lts; int lts;
int leases_queued = 0; int leases_queued = 0;
struct lease *lp; struct lease *lp = (struct lease *)0;
struct lease *next = (struct lease *)0;
struct shared_network *s; struct shared_network *s;
struct pool *p; struct pool *p;
int polarity;
binding_state_t peer_lease_state;
binding_state_t my_lease_state;
struct lease **lq;
if (state -> my_state != normal || state -> i_am == secondary) if (state -> my_state != normal || state -> i_am == secondary)
return 0; return 0;
@ -1342,32 +1366,59 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state)
for (p = s -> pools; p; p = p -> next) { for (p = s -> pools; p; p = p -> next) {
if (p -> failover_peer != state) if (p -> failover_peer != state)
continue; continue;
log_info ("pool %lx total %d local free %d peer free %d", log_info ("pool %lx total %d free %d backup %d",
(unsigned long)p, p -> lease_count, (unsigned long)p, p -> lease_count,
p -> local_leases, p -> peer_leases); p -> free_leases, p -> backup_leases);
/* Right now we're giving the peer half of the free leases.
If we have more leases than the peer (i.e., more than
half), then the number of leases we have, less the number
of leases the peer has, will be how many more leases we
have than the peer has. So if we send half that number
to the peer, we should be even. */
if (p -> failover_peer -> i_am == primary) {
lts = (p -> free_leases - p -> backup_leases) / 2;
peer_lease_state = FTS_BACKUP;
my_lease_state = FTS_FREE;
lq = &p -> free;
} else {
lts = (p -> backup_leases - p -> free_leases) / 2;
peer_lease_state = FTS_FREE;
my_lease_state = FTS_BACKUP;
lq = &p -> backup;
}
lts = ((p -> local_leases +
p -> peer_leases) / 2) - p -> peer_leases;
if (lts > 1) { if (lts > 1) {
struct lease lt; lease_reference (&lp, *lq, MDL);
leases_queued += lts; while (lp && lts) {
for (lp = p -> last_lease; lp && lts; /* Remember the next lease in the list. */
lp = lp -> prev) { if (next)
if (!(lp -> flags & PEER_IS_OWNER)) { lease_dereference (&next, MDL);
lp -> flags |= PEER_IS_OWNER; if (lp -> next)
lease_reference (&next, lp -> next, MDL);
--lts;
++leases_queued;
lp -> next_binding_state = peer_lease_state;
lp -> tstp = cur_time; lp -> tstp = cur_time;
if (!write_lease (lp) || lp -> starts = cur_time;
!commit_leases () || if (!supersede_lease (lp, (struct lease *)0, 1, 1, 0))
!dhcp_failover_queue_update (lp)) { {
log_info ("%s lease %s on giveaway", log_info ("can't commit lease %s on giveaway",
"unable to commit",
piaddr (lp -> ip_addr)); piaddr (lp -> ip_addr));
} }
}
}
}
lease_dereference (&lp, MDL);
if (next)
lease_reference (&lp, next, MDL);
}
if (next)
lease_dereference (&next, MDL);
if (lp)
lease_dereference (&lp, MDL);
}
if (lts > 1) { if (lts > 1) {
log_info ("lease imbalance - lts = %d", lts); log_info ("lease imbalance - lts = %d", lts);
leases_queued -= lts; leases_queued -= lts;
@ -1375,6 +1426,7 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state)
} }
} }
dhcp_failover_send_poolresp (state, leases_queued); dhcp_failover_send_poolresp (state, leases_queued);
dhcp_failover_send_updates (state);
return leases_queued; return leases_queued;
} }
@ -1388,12 +1440,15 @@ int dhcp_failover_pool_check (struct pool *pool)
pool -> failover_peer -> my_state != normal) pool -> failover_peer -> my_state != normal)
return 0; return 0;
log_info ("pool %lx total %d local free %d peer free %d", if (pool -> failover_peer -> i_am == primary)
(unsigned long)pool, pool -> lease_count, lts = (pool -> backup_leases - pool -> free_leases) / 2;
pool -> local_leases, pool -> peer_leases); else
lts = (pool -> free_leases - pool -> backup_leases) / 2;
log_info ("pool %lx total %d free %d backup %d lts %d",
(unsigned long)pool, pool -> lease_count,
pool -> free_leases, pool -> backup_leases, lts);
lts = ((pool -> local_leases +
pool -> peer_leases) / 2) - pool -> local_leases;
if (lts > 1) { if (lts > 1) {
/* XXX What about multiple pools? */ /* XXX What about multiple pools? */
dhcp_failover_send_poolreq (pool -> failover_peer); dhcp_failover_send_poolreq (pool -> failover_peer);
@ -1477,7 +1532,7 @@ isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *state)
not an error for this to be called on a lease for which there's no not an error for this to be called on a lease for which there's no
failover peer. */ failover peer. */
int dhcp_failover_queue_update (struct lease *lease) int dhcp_failover_queue_update (struct lease *lease, int immediate)
{ {
dhcp_failover_state_t *state; dhcp_failover_state_t *state;
@ -1509,6 +1564,7 @@ int dhcp_failover_queue_update (struct lease *lease)
} }
lease_reference (&state -> update_queue_tail, lease, MDL); lease_reference (&state -> update_queue_tail, lease, MDL);
lease -> flags |= ON_UPDATE_QUEUE; lease -> flags |= ON_UPDATE_QUEUE;
if (immediate)
dhcp_failover_send_updates (state); dhcp_failover_send_updates (state);
return 1; return 1;
} }
@ -1530,7 +1586,7 @@ void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *state,
return; return;
} }
for (lp = state -> ack_queue_head; for (lp = state -> ack_queue_head;
lp -> next_pending != lease; lp = lp -> next_pending) lp && lp -> next_pending != lease; lp = lp -> next_pending)
; ;
if (lp) { if (lp) {
lease_dereference (&lp -> next_pending, MDL); lease_dereference (&lp -> next_pending, MDL);
@ -2140,7 +2196,8 @@ failover_option_t *dhcp_failover_option_printf (unsigned code,
char *obuf, char *obuf,
unsigned *obufix, unsigned *obufix,
unsigned obufmax, unsigned obufmax,
const char *fmt, ...) { const char *fmt, ...)
{
va_list va; va_list va;
char tbuf [256]; char tbuf [256];
@ -2472,6 +2529,7 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
dhcp_failover_link_t *link; dhcp_failover_link_t *link;
dhcp_failover_state_t *state; dhcp_failover_state_t *state;
isc_result_t status; isc_result_t status;
char hba [32];
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
unsigned obufix = 0; unsigned obufix = 0;
@ -2489,6 +2547,12 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
if (!l -> outer || l -> outer -> type != omapi_type_connection) if (!l -> outer || l -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
if (state -> hba) {
int i;
for (i = 0; i < 32; i++)
hba [i] = ~state -> hba [i];
}
status = (dhcp_failover_put_message status = (dhcp_failover_put_message
(link, l -> outer, (link, l -> outer,
FTM_CONNECT, FTM_CONNECT,
@ -2507,7 +2571,9 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
0, 0), 0, 0),
dhcp_failover_make_option (FTO_MCLT, FMA, dhcp_failover_make_option (FTO_MCLT, FMA,
state -> mclt), state -> mclt),
dhcp_failover_make_option (FTO_HBA, FMA, 32, state -> hba), (state -> hba
? dhcp_failover_make_option (FTO_HBA, FMA, 32, hba)
: &skip_failover_option),
(failover_option_t *)0)); (failover_option_t *)0));
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
@ -2521,10 +2587,11 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
return status; return status;
} }
isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason) isc_result_t dhcp_failover_send_connectack (omapi_object_t *l,
dhcp_failover_state_t *state,
int reason, const char *errmsg)
{ {
dhcp_failover_link_t *link; dhcp_failover_link_t *link;
dhcp_failover_state_t *state;
isc_result_t status; isc_result_t status;
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
@ -2539,20 +2606,26 @@ isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason)
if (!l || l -> type != dhcp_type_failover_link) if (!l || l -> type != dhcp_type_failover_link)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
link = (dhcp_failover_link_t *)l; link = (dhcp_failover_link_t *)l;
state = link -> state_object;
if (!l -> outer || l -> outer -> type != omapi_type_connection) if (!l -> outer || l -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
status = (dhcp_failover_put_message status = (dhcp_failover_put_message
(link, l -> outer, (link, l -> outer,
FTM_CONNECTACK, FTM_CONNECTACK,
dhcp_failover_make_option (FTO_SERVER_ADDR, FMA, (state
? (dhcp_failover_make_option
(FTO_SERVER_ADDR, FMA,
state -> server_identifier.len, state -> server_identifier.len,
state -> server_identifier.data), state -> server_identifier.data))
dhcp_failover_make_option (FTO_MAX_UNACKED, FMA, : &skip_failover_option),
state -> max_flying_updates), (state
dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA, ? dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
state -> max_response_delay), state -> max_flying_updates)
: &skip_failover_option),
(state
? dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA,
state -> max_response_delay)
: &skip_failover_option),
dhcp_failover_option_printf (FTO_VENDOR_CLASS, FMA, dhcp_failover_option_printf (FTO_VENDOR_CLASS, FMA,
"isc-%s", DHCP_VERSION), "isc-%s", DHCP_VERSION),
dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA, dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA,
@ -2563,6 +2636,10 @@ isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason)
? dhcp_failover_make_option (FTO_REJECT_REASON, ? dhcp_failover_make_option (FTO_REJECT_REASON,
FMA, reason) FMA, reason)
: &skip_failover_option), : &skip_failover_option),
(errmsg
? dhcp_failover_make_option (FTO_MESSAGE, FMA,
strlen (errmsg), errmsg)
: &skip_failover_option),
(failover_option_t *)0)); (failover_option_t *)0));
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
@ -2635,7 +2712,6 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
unsigned obufix = 0; unsigned obufix = 0;
int binding_status;
# define FMA obuf, &obufix, sizeof obuf # define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(bndupd"); failover_print (FMA, "(bndupd");
@ -2651,26 +2727,6 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
if (!link -> outer || link -> outer -> type != omapi_type_connection) if (!link -> outer || link -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
/* Kludge up the binding status. */
if (lease -> flags & ABANDONED)
binding_status = FTS_ABANDONED;
else if (lease -> tsfp <= cur_time) {
if (lease -> flags & PEER_IS_OWNER) {
if (state -> i_am == primary)
binding_status = FTS_BACKUP;
else
binding_status = FTS_FREE;
} else {
if (state -> i_am == primary)
binding_status = FTS_FREE;
else
binding_status = FTS_BACKUP;
}
} else if (lease -> ends <= cur_time) {
binding_status = FTS_EXPIRED;
} else
binding_status = FTS_ACTIVE;
/* Send the update. */ /* Send the update. */
status = (dhcp_failover_put_message status = (dhcp_failover_put_message
(link, link -> outer, (link, link -> outer,
@ -2679,7 +2735,7 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
lease -> ip_addr.len, lease -> ip_addr.len,
lease -> ip_addr.iabuf), lease -> ip_addr.iabuf),
dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
binding_status), lease -> binding_state),
lease -> uid_len lease -> uid_len
? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA, ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
lease -> uid_len, lease -> uid_len,
@ -2726,7 +2782,6 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
unsigned obufix = 0; unsigned obufix = 0;
int binding_status;
# define FMA obuf, &obufix, sizeof obuf # define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(bndack"); failover_print (FMA, "(bndack");
@ -2742,26 +2797,6 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
if (!link -> outer || link -> outer -> type != omapi_type_connection) if (!link -> outer || link -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
/* Kludge up the binding status. */
if (lease -> flags & ABANDONED)
binding_status = FTS_ABANDONED;
else if (lease -> tsfp <= cur_time) {
if (lease -> flags & PEER_IS_OWNER) {
if (state -> i_am == primary)
binding_status = FTS_BACKUP;
else
binding_status = FTS_FREE;
} else {
if (state -> i_am == primary)
binding_status = FTS_FREE;
else
binding_status = FTS_BACKUP;
}
} else if (lease -> ends <= cur_time) {
binding_status = FTS_EXPIRED;
} else
binding_status = FTS_ACTIVE;
if (!message && reason) if (!message && reason)
message = dhcp_failover_reject_reason_print (reason); message = dhcp_failover_reject_reason_print (reason);
@ -2773,7 +2808,7 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
lease -> ip_addr.len, lease -> ip_addr.len,
lease -> ip_addr.iabuf), lease -> ip_addr.iabuf),
dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
binding_status), lease -> binding_state),
lease -> uid_len lease -> uid_len
? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA, ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
lease -> uid_len, lease -> uid_len,
@ -2864,7 +2899,7 @@ isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *state,
unsigned obufix = 0; unsigned obufix = 0;
# define FMA obuf, &obufix, sizeof obuf # define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(poolreq"); failover_print (FMA, "(poolresp");
#else #else
# define FMA (unsigned char *)0, (unsigned *)0, 0 # define FMA (unsigned char *)0, (unsigned *)0, 0
#endif #endif
@ -2902,6 +2937,7 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state,
struct iaddr ia; struct iaddr ia;
int reason = FTR_MISC_REJECT; int reason = FTR_MISC_REJECT;
const char *message; const char *message;
int new_binding_state;
ia.len = sizeof msg -> assigned_addr; ia.len = sizeof msg -> assigned_addr;
memcpy (ia.iabuf, &msg -> assigned_addr, ia.len); memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
@ -2964,21 +3000,20 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state,
} }
if (msg -> options_present & FTB_BINDING_STATUS) { if (msg -> options_present & FTB_BINDING_STATUS) {
if (state -> i_am == primary) { /* Check the requested transition to make sure it's
if (msg -> binding_status == FTS_BACKUP) valid. */
lease -> flags |= PEER_IS_OWNER; new_binding_state = (binding_state_transition_check
else if (msg -> binding_status == FTS_FREE) (lease, state, msg -> binding_status));
lease -> flags &= ~PEER_IS_OWNER; if (new_binding_state != msg -> binding_status) {
} else { dhcp_failover_send_bind_ack
if (msg -> binding_status == FTS_BACKUP) (state, lease, msg, FTR_FATAL_CONFLICT,
lease -> flags &= PEER_IS_OWNER; "invalid binding state transition");
else if (msg -> binding_status == FTS_FREE)
lease -> flags |= ~PEER_IS_OWNER;
} }
lt -> next_binding_state = new_binding_state;
} }
/* Try to install the new information. */ /* Try to install the new information. */
if (!supersede_lease (lease, lt, 1, 0)) { if (!supersede_lease (lease, lt, 1, 0, 0)) {
message = "database update failed"; message = "database update failed";
bad: bad:
dhcp_failover_send_bind_ack (state, lease, msg, dhcp_failover_send_bind_ack (state, lease, msg,
@ -3022,7 +3057,7 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *state,
} }
/* Try to install the new information. */ /* Try to install the new information. */
supersede_lease (lease, lt, 1, 0); supersede_lease (lease, lt, 1, 0, 0);
state -> cur_unacked_updates--; state -> cur_unacked_updates--;
dhcp_failover_ack_queue_remove (state, lease); dhcp_failover_ack_queue_remove (state, lease);
@ -3120,6 +3155,11 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
return 1; return 1;
} }
/* If we don't have a hash bucket array, we can't tell if this
one's ours, so we assume it's not. */
if (!state -> hba)
return 0;
oc = lookup_option (&dhcp_universe, packet -> options, oc = lookup_option (&dhcp_universe, packet -> options,
DHO_DHCP_CLIENT_IDENTIFIER); DHO_DHCP_CLIENT_IDENTIFIER);
memset (&ds, 0, sizeof ds); memset (&ds, 0, sizeof ds);
@ -3139,6 +3179,195 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
return !hm; return !hm;
} }
binding_state_t binding_state_transition_check (struct lease *lease,
dhcp_failover_state_t *state,
binding_state_t binding_state)
{
/* If there is no transition, it's no problem. */
if (binding_state == lease -> binding_state)
return binding_state;
/* This is really only dealing with what to do with bind updates when
we're in the normal state - if we were down and came back, and the
peer is in partner_down state, then we should take whatever it
sends, as long as it hasn't done anything illegal. What about
when we're in potential_conflict? */
/* Also, we should sanity check things here - the partner shouldn't
be allowed to set a lease to the EXPIRED state when it hasn't
expired, for example. */
/* Note that tsfp had better be set from the latest bind update
_before_ this function is called! */
switch (lease -> binding_state) {
case FTS_FREE:
case FTS_ABANDONED:
switch (binding_state) {
case FTS_ACTIVE:
case FTS_ABANDONED:
case FTS_BACKUP:
case FTS_RESERVED:
case FTS_BOOTP:
/* If the lease was free, and our peer is primary,
then it can make it active, or abandoned, or
backup. Abandoned is treated like free in
this case. */
if (state -> i_am == secondary)
return binding_state;
/* Otherwise, it can't do any sort of state
transition. */
case FTS_FREE: /* for compiler */
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
return FTS_FREE;
}
case FTS_ACTIVE:
case FTS_RESERVED:
case FTS_BOOTP:
/* The secondary can't change the state of an active
lease. */
if (state -> i_am == primary)
return FTS_ACTIVE;
/* So this is only for transitions made by the primary: */
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_EXPIRED:
if (lease -> ends > cur_time)
return lease -> binding_state;
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_RELEASED:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_ACTIVE:
return binding_state;
}
case FTS_EXPIRED:
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_ACTIVE:
case FTS_RELEASED:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_EXPIRED:
return binding_state;
}
case FTS_RELEASED:
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_EXPIRED:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_ACTIVE:
case FTS_RELEASED:
return binding_state;
}
case FTS_RESET:
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_ACTIVE:
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_ABANDONED:
case FTS_RESET:
return binding_state;
}
case FTS_BACKUP:
switch (binding_state) {
case FTS_ACTIVE:
case FTS_ABANDONED:
case FTS_FREE:
case FTS_RESERVED:
case FTS_BOOTP:
/* If the lease was in backup, and our peer is
secondary, then it can make it active, or
abandoned, or free. */
if (state -> i_am == primary)
return binding_state;
/* Otherwise, it can't do any sort of state
transition. */
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
return lease -> binding_state;
case FTS_BACKUP:
return FTS_BACKUP;
}
}
/*NOTREACHED*/
return lease -> binding_state;
}
int lease_mine_to_extend (struct lease *lease)
{
dhcp_failover_state_t *peer;
if (lease && lease -> pool &&
lease -> pool -> failover_peer) {
peer = lease -> pool -> failover_peer;
/* XXX This does't seem right - either peer can extend a lease to MCLT. */
if (peer -> my_state == normal) { /* XXX */
switch (lease -> binding_state) {
case FTS_ACTIVE:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_RELEASED:
case FTS_EXPIRED:
case FTS_FREE:
case FTS_BOOTP:
case FTS_RESERVED:
if (peer -> i_am == secondary)
return 0;
break;
case FTS_BACKUP:
if (peer -> i_am == primary)
return 0;
break;
}
}
}
return 1;
}
OMAPI_OBJECT_ALLOC (dhcp_failover_state, dhcp_failover_state_t, OMAPI_OBJECT_ALLOC (dhcp_failover_state, dhcp_failover_state_t,
dhcp_type_failover_state) dhcp_type_failover_state)
OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t, OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t,

View File

@ -3,7 +3,7 @@
Server-specific in-memory database support. */ Server-specific in-memory database support. */
/* /*
* Copyright (c) 1996-1999 Internet Software Consortium. * Copyright (c) 1996-2000 Internet Software Consortium.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: mdb.c,v 1.32 2000/05/16 23:03:46 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: mdb.c,v 1.33 2000/06/02 21:27:19 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -498,10 +498,6 @@ void new_address_range (low, high, subnet, pool)
subnet -> netmask, subnet -> netmask,
i + min)), i + min)),
isc_result_totext (status)); isc_result_totext (status));
/* Fill in the last lease if it hasn't been already... */
if (!pool -> last_lease) {
lease_reference (&pool -> last_lease, lp, MDL);
}
#endif #endif
lp -> ip_addr = ip_addr (subnet -> net, lp -> ip_addr = ip_addr (subnet -> net,
subnet -> netmask, i + min); subnet -> netmask, i + min);
@ -509,34 +505,20 @@ void new_address_range (low, high, subnet, pool)
lp -> ends = MIN_TIME; lp -> ends = MIN_TIME;
subnet_reference (&lp -> subnet, subnet, MDL); subnet_reference (&lp -> subnet, subnet, MDL);
pool_reference (&lp -> pool, pool, MDL); pool_reference (&lp -> pool, pool, MDL);
#if defined (FAILOVER_PROTOCOL) lp -> binding_state = FTS_FREE;
if (pool -> failover_peer && lp -> next_binding_state = FTS_FREE;
pool -> failover_peer -> i_am == secondary)
lp -> flags = PEER_IS_OWNER;
else
lp -> flags = 0; lp -> flags = 0;
#endif
/* Link this entry into the list. */ /* Link this entry into the list. */
if (pool -> leases) { if (pool -> free) {
lease_reference (&lp -> next, pool -> leases, MDL); lease_reference (&lp -> next, pool -> free, MDL);
lease_dereference (&pool -> leases, MDL); lease_dereference (&pool -> free, MDL);
} }
lease_reference (&pool -> leases, lp, MDL); lease_reference (&pool -> free, lp, MDL);
if (lp -> next)
lease_reference (&lp -> next -> prev,
pool -> leases, MDL);
lease_hash_add (lease_ip_addr_hash, lp -> ip_addr.iabuf, lease_hash_add (lease_ip_addr_hash, lp -> ip_addr.iabuf,
lp -> ip_addr.len, lp, MDL); lp -> ip_addr.len, lp, MDL);
} }
#if defined (COMPACT_LEASES)
/* Fill in the last lease if it hasn't been already... */
if (!pool -> last_lease) {
lease_reference (&pool -> last_lease, &address_range [0], MDL);
}
#endif
/* Find out if any dangling leases are in range... */ /* Find out if any dangling leases are in range... */
plp = (struct lease *)0; plp = (struct lease *)0;
for (lp = dangling_leases; lp; lp = lp -> next) { for (lp = dangling_leases; lp; lp = lp -> next) {
@ -568,7 +550,7 @@ void new_address_range (low, high, subnet, pool)
lp -> hostname = (char *)0; lp -> hostname = (char *)0;
lt -> client_hostname = lp -> client_hostname; lt -> client_hostname = lp -> client_hostname;
lp -> client_hostname = (char *)0; lp -> client_hostname = (char *)0;
supersede_lease (lt, lp, 0, 0); supersede_lease (lt, lp, 0, 0, 0);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
} }
lease_dereference (&lp, MDL); lease_dereference (&lp, MDL);
@ -744,15 +726,13 @@ void enter_lease (lease)
/* If we don't have a place for this lease yet, save it for /* If we don't have a place for this lease yet, save it for
later. */ later. */
if (!find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) { if (!find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) {
if (comp -> next) if (lease -> next)
lease_dereference (&comp -> next, MDL); lease_dereference (&lease -> next, MDL);
if (dangling_leases) if (dangling_leases)
lease_reference (&comp -> next, dangling_leases, MDL); lease_reference (&lease -> next, dangling_leases, MDL);
lease_reference (&dangling_leases, comp, MDL); lease_reference (&dangling_leases, lease, MDL);
if (comp -> prev)
lease_dereference (&comp -> prev, MDL);
} else { } else {
supersede_lease (comp, lease, 0, 0); supersede_lease (comp, lease, 0, 0, 0);
} }
} }
@ -761,14 +741,20 @@ void enter_lease (lease)
list of leases by expiry time so that we can always find the oldest list of leases by expiry time so that we can always find the oldest
lease. */ lease. */
int supersede_lease (comp, lease, commit, propogate) int supersede_lease (comp, lease, commit, propogate, pimmediate)
struct lease *comp, *lease; struct lease *comp, *lease;
int commit; int commit;
int propogate; int propogate;
int pimmediate;
{ {
int enter_uid = 0; int enter_uid = 0;
int enter_hwaddr = 0; int enter_hwaddr = 0;
struct lease *lp; struct lease *lp, **lq, *prev;
TIME lp_next_state;
/* If there is no sample lease, just do the move. */
if (!lease)
goto just_move_it;
/* Static leases are not currently kept in the database... */ /* Static leases are not currently kept in the database... */
if (lease -> flags & STATIC_LEASE) if (lease -> flags & STATIC_LEASE)
@ -783,8 +769,10 @@ int supersede_lease (comp, lease, commit, propogate)
lease, then we allow that, in case a dynamic BOOTP lease is lease, then we allow that, in case a dynamic BOOTP lease is
requested *after* a DHCP lease has been assigned. */ requested *after* a DHCP lease has been assigned. */
if (!(lease -> flags & ABANDONED_LEASE) && if (lease -> binding_state != FTS_ABANDONED &&
comp -> ends > cur_time && (comp -> binding_state == FTS_ACTIVE ||
comp -> binding_state == FTS_RESERVED ||
comp -> binding_state == FTS_BOOTP) &&
(((comp -> uid && lease -> uid) && (((comp -> uid && lease -> uid) &&
(comp -> uid_len != lease -> uid_len || (comp -> uid_len != lease -> uid_len ||
memcmp (comp -> uid, lease -> uid, comp -> uid_len))) || memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
@ -905,274 +893,234 @@ int supersede_lease (comp, lease, commit, propogate)
hw_hash_add (comp); hw_hash_add (comp);
} }
/* Remove the lease from its current place in the
timeout sequence. */
if (comp -> prev) {
lease_dereference (&comp -> prev -> next, MDL);
if (comp -> next) {
lease_reference (&comp -> prev -> next,
comp -> next, MDL);
lease_dereference (&comp -> next, MDL);
}
} else {
lease_dereference (&comp -> pool -> leases, MDL);
if (comp -> next) {
lease_reference (&comp -> pool -> leases,
comp -> next, MDL);
}
}
if (comp -> next) {
lease_dereference (&comp -> next -> prev, MDL);
if (comp -> prev) {
lease_reference (&comp -> next -> prev,
comp -> prev, MDL);
}
}
if (comp -> pool -> last_lease == comp) {
lease_dereference (&comp -> pool -> last_lease, MDL);
if (comp -> prev)
lease_reference (&comp -> pool -> last_lease,
comp -> prev, MDL);
}
if (comp -> prev)
lease_dereference (&comp -> prev, MDL);
if (comp -> next)
lease_dereference (&comp -> next, MDL);
/* If there's an expiry event on this lease, get rid of it
(we may wind up putting it back, but we can't count on
that here without too much additional complexity). */
if (comp -> pool -> next_expiry == comp) {
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
lp = comp -> prev;
#else
for (lp = comp -> prev; lp; lp = lp -> prev)
if (lp -> on_expiry)
break;
#endif
if (lp
#if !defined (FAILOVER_PROTOCOL)
&& lp -> on_expiry
#endif
) {
lease_dereference (&comp -> pool -> next_expiry, MDL);
lease_reference (&comp -> pool -> next_expiry,
lp, MDL);
if (commit)
add_timeout (lp -> ends,
pool_timer, lp -> pool,
(tvref_t)pool_reference,
(tvunref_t)pool_dereference);
} else {
lease_dereference (&comp -> pool -> next_expiry, MDL);
if (commit)
cancel_timeout (pool_timer, comp -> pool);
}
}
/* Find the last insertion point... */
if (comp == comp -> pool -> insertion_point ||
!comp -> pool -> insertion_point) {
lp = comp -> pool -> leases;
} else {
lp = comp -> pool -> insertion_point;
}
if (!lp) {
/* Nothing on the list yet? Just make comp the
head of the list. */
lease_reference (&comp -> pool -> leases, comp, MDL);
if (comp -> pool -> last_lease) {
lease_dereference (&comp -> pool -> last_lease, MDL);
lease_reference (&comp -> pool -> last_lease,
comp, MDL);
}
} else if (lp -> ends > lease -> ends) {
/* Skip down the list until we run out of list
or find a place for comp. */
while (lp -> next && lp -> ends > lease -> ends) {
lp = lp -> next;
}
if (lp -> ends > lease -> ends) {
/* If we ran out of list, put comp at the end. */
lease_reference (&lp -> next, comp, MDL);
lease_reference (&comp -> prev, lp, MDL);
if (comp -> pool -> last_lease)
lease_dereference (&comp -> pool -> last_lease,
MDL);
lease_reference (&comp -> pool -> last_lease,
comp, MDL);
} else {
/* If we didn't, put it between lp and
the previous item on the list. */
if (lp -> prev) {
lease_reference (&comp -> prev,
lp -> prev, MDL);
lease_dereference (&lp -> prev -> next, MDL);
lease_reference (&comp -> prev -> next,
comp, MDL);
lease_dereference (&lp -> prev, MDL);
} else {
if (comp -> pool -> leases)
lease_dereference
(&comp -> pool -> leases, MDL);
lease_reference (&comp -> pool -> leases,
comp, MDL);
}
lease_reference (&comp -> next, lp, MDL);
lease_reference (&lp -> prev, comp, MDL);
}
} else {
/* Skip up the list until we run out of list
or find a place for comp. */
while (lp -> prev && lp -> ends < lease -> ends) {
lp = lp -> prev;
}
if (lp -> ends < lease -> ends) {
/* If we ran out of list, put comp at the beginning. */
lease_reference (&lp -> prev, comp, MDL);
lease_reference (&comp -> next, lp, MDL);
if (comp -> pool -> leases)
lease_dereference (&comp -> pool -> leases,
MDL);
lease_reference (&comp -> pool -> leases, comp, MDL);
} else {
/* If we didn't, put it between lp and
the next item on the list. */
if (lp -> next) {
lease_reference (&comp -> next,
lp -> next, MDL);
lease_dereference (&lp -> next -> prev, MDL);
lease_reference (&lp -> next -> prev,
comp, MDL);
lease_dereference (&lp -> next, MDL);
} else {
/* XXX are we really supposed to
XXX be doing this? */
if (comp -> pool -> last_lease)
lease_dereference
(&comp -> pool -> last_lease,
MDL);
lease_reference (&comp -> pool -> last_lease,
comp, MDL);
}
lease_reference (&comp -> prev, lp, MDL);
lease_reference (&lp -> next, comp, MDL);
}
}
if (comp -> pool -> insertion_point)
lease_dereference (&comp -> pool -> insertion_point, MDL);
lease_reference (&comp -> pool -> insertion_point, comp, MDL);
#if defined (FAILOVER_PROTOCOL)
if (comp -> ends <= cur_time && lease -> ends > cur_time) {
if (lease -> flags & PEER_IS_OWNER)
comp -> pool -> peer_leases--;
else
comp -> pool -> local_leases--;
} else if (comp -> ends > cur_time && lease -> ends <= cur_time) {
if (lease -> flags & PEER_IS_OWNER)
comp -> pool -> peer_leases++;
else
comp -> pool -> local_leases++;
}
comp -> cltt = lease -> cltt; comp -> cltt = lease -> cltt;
comp -> tstp = lease -> tstp; comp -> tstp = lease -> tstp;
comp -> tsfp = lease -> tsfp; comp -> tsfp = lease -> tsfp;
#endif /* FAILOVER_PROTOCOL */ #endif /* FAILOVER_PROTOCOL */
comp -> ends = lease -> ends; comp -> ends = lease -> ends;
comp -> next_binding_state = lease -> next_binding_state;
/* If there's an expiry event on this lease, process it or just_move_it:
queue it. */ /* Figure out which queue it's on. */
#if !defined (FAILOVER_PROTOCOL) switch (comp -> binding_state) {
if (comp -> on_expiry) { case FTS_FREE:
#endif lq = &comp -> pool -> free;
if (comp -> ends <= cur_time && commit) { comp -> pool -> free_leases--;
if (comp -> on_expiry) { break;
execute_statements ((struct packet *)0, lease,
(struct option_state *)0, case FTS_ACTIVE:
(struct option_state *)0, /* XXX */ case FTS_RESERVED:
&lease -> scope, case FTS_BOOTP:
comp -> on_expiry); lq = &comp -> pool -> active;
executable_statement_dereference (&comp -> on_expiry, break;
MDL);
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
lq = &comp -> pool -> expired;
break;
case FTS_ABANDONED:
lq = &comp -> pool -> abandoned;
break;
case FTS_BACKUP:
lq = &comp -> pool -> backup;
comp -> pool -> backup_leases--;
break;
default:
log_error ("Lease with bogus binding state: %d",
comp -> binding_state);
return 0;
} }
/* No sense releasing a lease after it's expired. */ /* Remove the lease from its current place in its current
if (comp -> on_release) timer sequence. */
executable_statement_dereference prev = (struct lease *)0;
(&comp -> on_release, MDL); for (lp = *lq; lp; lp = lp -> next) {
if (lp == comp)
break;
prev = lp;
}
if (!lp) {
log_error ("Lease with binding state %s not on its queue.",
(comp -> binding_state < 1 &&
comp -> binding_state < FTS_BOOTP)
? "unknown"
: binding_state_names [comp -> binding_state - 1]);
return 0;
}
if (prev) {
lease_dereference (&prev -> next, MDL);
if (comp -> next) {
lease_reference (&prev -> next, comp -> next, MDL);
lease_dereference (&comp -> next, MDL);
}
} else { } else {
/* If this is the next lease that will timeout on the lease_dereference (lq, MDL);
pool, zap the old timeout and set the timeout on if (comp -> next) {
this pool to the time that the lease ends. lease_reference (lq, comp -> next, MDL);
lease_dereference (&comp -> next, MDL);
}
}
We do not actually set the timeout unless commit is /* Make the state transition. */
true - we don't want to thrash the timer queue when
reading the lease database. Instead, the database
code calls the expiry event on each pool after
reading in the lease file, and the expiry code sets
the timer if there's anything left to expire after
it's run any outstanding expiry events on the
pool. */
if (comp -> pool) {
if (!comp -> pool -> next_expiry ||
(comp -> ends <
comp -> pool -> next_expiry -> ends)) {
if (comp -> pool -> next_expiry)
lease_dereference
(&comp -> pool -> next_expiry,
MDL);
lease_reference
(&comp -> pool -> next_expiry,
comp, MDL);
if (commit) if (commit)
add_timeout (comp -> ends, process_state_transition (comp);
pool_timer,
comp -> pool, /* Figure out which queue it's going to. */
switch (comp -> binding_state) {
case FTS_FREE:
lq = &comp -> pool -> free;
comp -> pool -> free_leases++;
comp -> sort_time = comp -> ends;
break;
case FTS_ACTIVE:
case FTS_RESERVED:
case FTS_BOOTP:
lq = &comp -> pool -> active;
comp -> sort_time = comp -> ends;
break;
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
lq = &comp -> pool -> expired;
comp -> sort_time = comp -> ends;
break;
case FTS_ABANDONED:
lq = &comp -> pool -> abandoned;
comp -> sort_time = comp -> ends;
break;
case FTS_BACKUP:
lq = &comp -> pool -> backup;
comp -> pool -> backup_leases++;
comp -> sort_time = comp -> ends;
break;
default:
log_error ("Lease with bogus binding state: %d",
comp -> binding_state);
return 0;
}
/* Insertion sort the lease onto the appropriate queue. */
prev = (struct lease *)0;
for (lp = *lq; lp; lp = lp -> next) {
if (lp -> sort_time > comp -> sort_time)
break;
prev = lp;
}
if (prev) {
if (prev -> next) {
lease_reference (&comp -> next, prev -> next, MDL);
lease_dereference (&prev -> next, MDL);
}
lease_reference (&prev -> next, comp, MDL);
} else {
if (*lq) {
lease_reference (&comp -> next, *lq, MDL);
lease_dereference (lq, MDL);
}
lease_reference (lq, comp, MDL);
}
/* If this is the next lease that will timeout on the pool,
zap the old timeout and set the timeout on this pool to the
time that the lease's next event will happen.
We do not actually set the timeout unless commit is true -
we don't want to thrash the timer queue when reading the
lease database. Instead, the database code calls the
expiry event on each pool after reading in the lease file,
and the expiry code sets the timer if there's anything left
to expire after it's run any outstanding expiry events on
the pool. */
if (commit &&
comp -> sort_time != MIN_TIME &&
comp -> sort_time < cur_time &&
comp -> sort_time < comp -> pool -> next_event_time) {
comp -> pool -> next_event_time = comp -> sort_time;
add_timeout (comp -> pool -> next_event_time,
pool_timer, comp -> pool,
(tvref_t)pool_reference, (tvref_t)pool_reference,
(tvunref_t) (tvunref_t)pool_dereference);
pool_dereference);
} else if (comp -> ends ==
comp -> pool -> next_expiry -> ends) {
/* If there are other leases that expire at
the same time as comp, we need to make
sure that we have the one that appears
last on the list that needs an expiry
event - otherwise we'll miss expiry
events until the server restarts. */
struct lease *foo;
struct lease *install = comp;
for (foo = comp;
foo && foo -> ends == comp -> ends;
foo = foo -> next) {
#if !defined (FAILOVER_PROTOCOL)
if (foo -> on_expiry)
#endif
install = foo;
} }
lease_dereference
(&comp -> pool -> next_expiry,
MDL);
lease_reference
(&comp -> pool -> next_expiry,
install, MDL);
}
}
}
#if !defined (FAILOVER_PROTOCOL)
}
#endif
/* Return zero if we didn't commit the lease to permanent storage; /* Return zero if we didn't commit the lease to permanent storage;
nonzero if we did. */ nonzero if we did. */
return commit && write_lease (comp) && commit_leases () return commit && write_lease (comp) && commit_leases ()
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
&& (!propogate || dhcp_failover_queue_update (comp)) && (!propogate ||
dhcp_failover_queue_update (comp, pimmediate))
#endif #endif
; ;
} }
void process_state_transition (struct lease *lease)
{
/* If the lease was active and is now no longer active, but isn't
released, then it just expired, so do the expiry event. */
if (lease -> next_binding_state != lease -> binding_state &&
(lease -> binding_state == FTS_ACTIVE ||
lease -> binding_state == FTS_BOOTP ||
lease -> binding_state == FTS_RESERVED) &&
lease -> next_binding_state != FTS_RELEASED) {
if (lease -> on_expiry) {
execute_statements ((struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
lease -> on_expiry);
executable_statement_dereference (&lease -> on_expiry,
MDL);
}
/* No sense releasing a lease after it's expired. */
if (lease -> on_release)
executable_statement_dereference (&lease -> on_release,
MDL);
/* Send the expiry time to the peer. */
lease -> tstp = lease -> ends;
}
/* If the lease was active and is now released, do the release
event. */
if ((lease -> binding_state == FTS_ACTIVE ||
lease -> binding_state == FTS_BOOTP ||
lease -> binding_state == FTS_RESERVED) &&
lease -> next_binding_state == FTS_RELEASED) {
if (lease -> on_release) {
execute_statements ((struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
lease -> on_release);
executable_statement_dereference (&lease -> on_release,
MDL);
}
/* A released lease can't expire. */
if (lease -> on_expiry)
executable_statement_dereference (&lease -> on_expiry,
MDL);
/* Send the release time (should be == cur_time) to the
peer. */
lease -> tstp = lease -> ends;
}
lease -> binding_state = lease -> next_binding_state;
}
/* Copy the contents of one lease into another, correctly maintaining /* Copy the contents of one lease into another, correctly maintaining
reference counts. */ reference counts. */
int lease_copy (struct lease **lp, int lease_copy (struct lease **lp,
@ -1242,6 +1190,8 @@ int lease_copy (struct lease **lp,
lt -> tstp = lease -> tstp; lt -> tstp = lease -> tstp;
lt -> tsfp = lease -> tsfp; lt -> tsfp = lease -> tsfp;
lt -> cltt = lease -> cltt; lt -> cltt = lease -> cltt;
lt -> binding_state = lease -> binding_state;
lt -> next_binding_state = lease -> next_binding_state;
status = lease_reference (lp, lt, file, line); status = lease_reference (lp, lt, file, line);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
return status == ISC_R_SUCCESS; return status == ISC_R_SUCCESS;
@ -1252,8 +1202,6 @@ void release_lease (lease, packet)
struct lease *lease; struct lease *lease;
struct packet *packet; struct packet *packet;
{ {
struct lease *lt;
/* If there are statements to execute when the lease is /* If there are statements to execute when the lease is
released, execute them. */ released, execute them. */
if (lease -> on_release) { if (lease -> on_release) {
@ -1272,21 +1220,26 @@ void release_lease (lease, packet)
executable_statement_dereference (&lease -> on_expiry, MDL); executable_statement_dereference (&lease -> on_expiry, MDL);
if (lease -> ends > cur_time) { if (lease -> ends > cur_time) {
if (!lease_copy (&lt, lease, MDL)) if (lease -> on_commit)
return; executable_statement_dereference (&lease -> on_commit,
if (lt -> on_commit)
executable_statement_dereference (&lt -> on_commit,
MDL); MDL);
/* Blow away any bindings. */ /* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0; /* XXX free them?!? */
lease -> scope.bindings = (struct binding *)0;
lt -> ends = cur_time; lease -> ends = cur_time;
if (lt -> billing_class) #if defined (FAILOVER_PROTOCOL)
class_dereference (&lt -> billing_class, MDL); if (lease -> pool && lease -> pool -> failover_peer) {
supersede_lease (lease, lt, 1, 1); lease -> next_binding_state = FTS_RELEASED;
lease_dereference (&lt, MDL); } else {
lease -> next_binding_state = FTS_FREE;
}
#else
lease -> next_binding_state = FTS_FREE;
#endif
if (lease -> billing_class)
class_dereference (&lease -> billing_class, MDL);
supersede_lease (lease, (struct lease *)0, 1, 1, 1);
} }
} }
@ -1299,7 +1252,6 @@ void abandon_lease (lease, message)
{ {
struct lease *lt = (struct lease *)0; struct lease *lt = (struct lease *)0;
lease -> flags |= ABANDONED_LEASE;
if (!lease_copy (&lt, lease, MDL)) if (!lease_copy (&lt, lease, MDL))
return; return;
@ -1312,8 +1264,9 @@ void abandon_lease (lease, message)
/* Blow away any bindings. */ /* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0; lt -> scope.bindings = (struct binding *)0;
lt -> ends = cur_time; /* XXX */ lt -> ends = cur_time; /* XXX */
lt -> next_binding_state = FTS_ABANDONED;
log_error ("Abandoning IP address %s: %s", log_error ("Abandoning IP address %s: %s",
piaddr (lease -> ip_addr), message); piaddr (lease -> ip_addr), message);
lt -> hardware_addr.hlen = 0; lt -> hardware_addr.hlen = 0;
@ -1324,7 +1277,7 @@ void abandon_lease (lease, message)
lt -> uid_max = 0; lt -> uid_max = 0;
if (lt -> billing_class) if (lt -> billing_class)
class_dereference (&lt -> billing_class, MDL); class_dereference (&lt -> billing_class, MDL);
supersede_lease (lease, lt, 1, 1); supersede_lease (lease, lt, 1, 1, 1);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
} }
@ -1349,6 +1302,15 @@ void dissociate_lease (lease)
/* Blow away any bindings. */ /* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0; lt -> scope.bindings = (struct binding *)0;
#if defined (FAILOVER_PROTOCOL)
if (lease -> pool && lease -> pool -> failover_peer) {
lt -> next_binding_state = FTS_RESET;
} else {
lt -> next_binding_state = FTS_FREE;
}
#else
lt -> next_binding_state = FTS_FREE;
#endif
lt -> ends = cur_time; /* XXX */ lt -> ends = cur_time; /* XXX */
lt -> hardware_addr.hlen = 0; lt -> hardware_addr.hlen = 0;
if (lt -> uid != lt -> uid_buf) if (lt -> uid != lt -> uid_buf)
@ -1358,7 +1320,7 @@ void dissociate_lease (lease)
lt -> uid_max = 0; lt -> uid_max = 0;
if (lt -> billing_class) if (lt -> billing_class)
class_dereference (&lt -> billing_class, MDL); class_dereference (&lt -> billing_class, MDL);
supersede_lease (lease, lt, 1, 1); supersede_lease (lease, lt, 1, 1, 1);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
} }
@ -1367,72 +1329,75 @@ void pool_timer (vpool)
void *vpool; void *vpool;
{ {
struct pool *pool; struct pool *pool;
struct lease *lease; struct lease *lt = (struct lease *)0;
struct lease *next = (struct lease *)0;
struct lease *lease = (struct lease *)0;
struct lease **lptr [5];
TIME next_expiry = MAX_TIME;
int i;
pool = (struct pool *)vpool; pool = (struct pool *)vpool;
for (lease = pool -> next_expiry; lease; lease = lease -> prev) {
/* Stop processing when we get to the first lease that has not #define FREE_LEASES 0
yet expired. */ lptr [FREE_LEASES] = &pool -> free;
if (lease -> ends > cur_time) #define ACTIVE_LEASES 1
lptr [ACTIVE_LEASES] = &pool -> active;
#define EXPIRED_LEASES 2
lptr [EXPIRED_LEASES] = &pool -> expired;
#define ABANDONED_LEASES 3
lptr [ABANDONED_LEASES] = &pool -> abandoned;
#define BACKUP_LEASES 4
lptr [BACKUP_LEASES] = &pool -> backup;
for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
/* If there's nothing on the queue, skip it. */
if (!*(lptr [i]))
continue;
lease_reference (&lease, *(lptr [i]), MDL);
while (lease) {
/* Remember the next lease in the list. */
if (next)
lease_dereference (&next, MDL);
if (lease -> next)
lease_reference (&next, lease -> next, MDL);
/* If we've run out of things to expire on this list,
stop. */
if (lease -> sort_time > cur_time) {
if (lease -> sort_time < next_expiry)
next_expiry = lease -> sort_time;
break; break;
/* Skip entries that aren't set to expire. */
if (lease -> on_expiry) {
/* Okay, the current lease needs to expire, so
do it. */
execute_statements ((struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
lease -> on_expiry);
if (lease -> on_expiry)
executable_statement_dereference
(&lease -> on_expiry, MDL);
} }
/* If there's an on_release event, blow it away. */ /* If there is a pending state change, and
if (lease -> on_release) this lease has gotten to the time when the
executable_statement_dereference (&lease -> on_release, state change should happen, just call
MDL); supersede_lease on it to make the change
happen. */
if (lease -> next_binding_state !=
lease -> binding_state)
supersede_lease (lease,
(struct lease *)0, 1, 1, 1);
/* There are two problems with writing the lease out here. lease_dereference (&lease, MDL);
if (next)
The first is that we've just done a commit, and the write lease_reference (&lease, next, MDL);
may fail, in which case we will redo the operation. If the
operation is not idempotent, we're in trouble here. I have
no proposed solution for this problem - make the event
idempotent, or make sure that it at least isn't harmful to
do it twice.
The second is that if we just read in the lease file and ran
all the expiry events, we're going to rewrite all expiring
leases twice. There's no real answer for this - if we
postpone writing until we've expired all leases, we're
increasing the window to lose as described above. I guess a
dirty bit on the lease would work. Hm. */
if (!write_lease (lease)) {
log_error ("Error updating lease %s after expiry",
piaddr (lease -> ip_addr));
} }
if (!commit_leases ()) { if (next)
log_error ("Error committing after writing lease %s", lease_dereference (&next, MDL);
piaddr (lease -> ip_addr)); if (lease)
lease_dereference (&lease, MDL);
} }
#if defined (FAILOVER_PROTOCOL) if (next_expiry != MAX_TIME) {
if (lease -> flags & PEER_IS_OWNER) pool -> next_event_time = next_expiry;
pool -> peer_leases++; add_timeout (pool -> next_event_time, pool_timer, pool,
else
pool -> local_leases++;
#endif
}
if (pool -> next_expiry)
lease_dereference (&pool -> next_expiry, MDL);
if (lease) {
lease_reference (&pool -> next_expiry, lease, MDL);
add_timeout (lease -> ends, pool_timer, pool,
(tvref_t)pool_reference, (tvref_t)pool_reference,
(tvunref_t)pool_dereference); (tvunref_t)pool_dereference);
} } else
pool -> next_event_time = MIN_TIME;
} }
/* Locate the lease associated with a given IP address... */ /* Locate the lease associated with a given IP address... */
@ -1618,6 +1583,7 @@ void write_leases ()
struct hash_bucket *hb; struct hash_bucket *hb;
int i; int i;
int num_written; int num_written;
struct lease **lptr [5];
/* Write all the dynamically-created group declarations. */ /* Write all the dynamically-created group declarations. */
if (group_name_hash) { if (group_name_hash) {
@ -1683,18 +1649,25 @@ void write_leases ()
num_written = 0; num_written = 0;
for (s = shared_networks; s; s = s -> next) { for (s = shared_networks; s; s = s -> next) {
for (p = s -> pools; p; p = p -> next) { for (p = s -> pools; p; p = p -> next) {
for (l = p -> leases; l; l = l -> next) { lptr [FREE_LEASES] = &p -> free;
lptr [ACTIVE_LEASES] = &p -> active;
lptr [EXPIRED_LEASES] = &p -> expired;
lptr [ABANDONED_LEASES] = &p -> abandoned;
lptr [BACKUP_LEASES] = &p -> backup;
for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
for (l = *(lptr [i]); l; l = l -> next) {
if (l -> hardware_addr.hlen || if (l -> hardware_addr.hlen ||
l -> uid_len || l -> uid_len ||
(l -> flags & ABANDONED_LEASE)) { (l -> binding_state != FTS_FREE)) {
if (!write_lease (l)) if (!write_lease (l))
log_fatal ("Can't rewrite %s", log_fatal ("Can't rewrite lease database");
"lease database");
num_written++; num_written++;
} }
} }
} }
} }
}
log_info ("Wrote %d leases to leases file.", num_written); log_info ("Wrote %d leases to leases file.", num_written);
if (!commit_leases ()) if (!commit_leases ())
log_fatal ("Can't commit leases to new database: %m"); log_fatal ("Can't commit leases to new database: %m");
@ -1712,6 +1685,7 @@ void expire_all_pools ()
struct hash_bucket *hb; struct hash_bucket *hb;
int i; int i;
struct lease *l; struct lease *l;
struct lease **lptr [5];
/* Loop through each pool in each shared network and call the /* Loop through each pool in each shared network and call the
expiry routine on the pool. */ expiry routine on the pool. */
@ -1721,21 +1695,29 @@ void expire_all_pools ()
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
p -> lease_count = 0; p -> lease_count = 0;
p -> local_leases = 0; p -> free_leases = 0;
p -> peer_leases = 0; p -> backup_leases = 0;
for (l = p -> leases; l; l = l -> next) { lptr [FREE_LEASES] = &p -> free;
lptr [ACTIVE_LEASES] = &p -> active;
lptr [EXPIRED_LEASES] = &p -> expired;
lptr [ABANDONED_LEASES] = &p -> abandoned;
lptr [BACKUP_LEASES] = &p -> backup;
for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
for (l = *(lptr [i]); l; l = l -> next) {
p -> lease_count++; p -> lease_count++;
if (l -> ends <= cur_time) { if (l -> ends <= cur_time) {
if (l -> flags & PEER_IS_OWNER) if (l -> binding_state == FTS_FREE)
p -> peer_leases++; p -> free_leases++;
else else if (l -> binding_state == FTS_BACKUP)
p -> local_leases++; p -> backup_leases++;
} }
if (p -> failover_peer && if (p -> failover_peer &&
l -> tstp > l -> tsfp && l -> tstp > l -> tsfp &&
!(l -> flags & ON_UPDATE_QUEUE)) !(l -> flags & ON_UPDATE_QUEUE))
dhcp_failover_queue_update (l); dhcp_failover_queue_update (l, 1);
}
} }
#endif #endif
} }
@ -1748,6 +1730,8 @@ void dump_subnets ()
struct shared_network *s; struct shared_network *s;
struct subnet *n; struct subnet *n;
struct pool *p; struct pool *p;
struct lease **lptr [5];
int i;
log_info ("Subnets:"); log_info ("Subnets:");
for (n = subnets; n; n = n -> next_subnet) { for (n = subnets; n; n = n -> next_subnet) {
@ -1759,11 +1743,17 @@ void dump_subnets ()
for (s = shared_networks; s; s = s -> next) { for (s = shared_networks; s; s = s -> next) {
log_info (" %s", s -> name); log_info (" %s", s -> name);
for (p = s -> pools; p; p = p -> next) { for (p = s -> pools; p; p = p -> next) {
for (l = p -> leases; l; l = l -> next) { lptr [FREE_LEASES] = &p -> free;
lptr [ACTIVE_LEASES] = &p -> active;
lptr [EXPIRED_LEASES] = &p -> expired;
lptr [ABANDONED_LEASES] = &p -> abandoned;
lptr [BACKUP_LEASES] = &p -> backup;
for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
for (l = *(lptr [i]); l; l = l -> next) {
print_lease (l); print_lease (l);
} }
log_debug ("Last Lease:"); }
print_lease (p -> last_lease);
} }
} }
} }

View File

@ -50,7 +50,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: omapi.c,v 1.28 2000/05/16 23:03:48 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: omapi.c,v 1.29 2000/06/02 21:27:20 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -179,27 +179,21 @@ isc_result_t dhcp_lease_set_value (omapi_object_t *h,
lease = (struct lease *)h; lease = (struct lease *)h;
/* We're skipping a lot of things it might be interesting to /* We're skipping a lot of things it might be interesting to
set - for now, we just make it possible to whack the abandoned set - for now, we just make it possible to whack the state. */
flag. */ if (!omapi_ds_strcmp (name, "state")) {
if (!omapi_ds_strcmp (name, "abandoned")) { unsigned long bar;
int bar; status = omapi_get_int_value (&bar, value);
if (status != ISC_R_SUCCESS)
return status;
if (value -> type == omapi_datatype_int) if (bar < 1 || bar > FTS_BOOTP)
bar = value -> u.integer;
else if (value -> type == omapi_datatype_data &&
value -> u.buffer.len == sizeof (int)) {
memcpy (&bar, value -> u.buffer.value, sizeof bar);
/* No need to byte-swap here. */
} else
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
if (lease -> binding_state != bar) {
foo = lease -> flags; lease -> next_binding_state = bar;
if (bar) if (supersede_lease (lease, 0, 1, 1, 1))
lease -> flags |= ABANDONED_LEASE;
else
lease -> flags &= ~ABANDONED_LEASE;
if (foo != lease -> flags)
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
return ISC_R_IOERROR;
}
return ISC_R_UNCHANGED; return ISC_R_UNCHANGED;
} }
@ -226,14 +220,9 @@ isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id,
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
lease = (struct lease *)h; lease = (struct lease *)h;
if (!omapi_ds_strcmp (name, "abandoned")) if (!omapi_ds_strcmp (name, "state"))
return omapi_make_int_value (value, name, return omapi_make_int_value (value, name,
(lease -> flags & (int)lease -> binding_state, MDL);
ABANDONED_LEASE) ? 1 : 0, MDL);
else if (!omapi_ds_strcmp (name, "bootpp"))
return omapi_make_int_value (value, name,
(lease -> flags &
BOOTP_LEASE) ? 1 : 0, MDL);
else if (!omapi_ds_strcmp (name, "ip-address")) else if (!omapi_ds_strcmp (name, "ip-address"))
return omapi_make_const_value (value, name, return omapi_make_const_value (value, name,
lease -> ip_addr.iabuf, lease -> ip_addr.iabuf,
@ -362,7 +351,7 @@ isc_result_t dhcp_lease_signal_handler (omapi_object_t *h,
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
if (!write_lease (lease) || !commit_leases () if (!write_lease (lease) || !commit_leases ()
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
|| !dhcp_failover_queue_update (lease) || !dhcp_failover_queue_update (lease, 1)
#endif #endif
) { ) {
return ISC_R_IOERROR; return ISC_R_IOERROR;
@ -395,26 +384,13 @@ isc_result_t dhcp_lease_stuff_values (omapi_object_t *c,
/* Write out all the values. */ /* Write out all the values. */
status = omapi_connection_put_name (c, "abandoned"); status = omapi_connection_put_name (c, "state");
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
return status; return status;
status = omapi_connection_put_uint32 (c, sizeof (int)); status = omapi_connection_put_uint32 (c, sizeof (int));
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
return status; return status;
status = omapi_connection_put_uint32 (c, (lease -> flags & status = omapi_connection_put_uint32 (c, lease -> binding_state);
ABANDONED_LEASE) ? 1U : 0U);
if (status != ISC_R_SUCCESS)
return status;
status = omapi_connection_put_name (c, "bootpp");
if (status != ISC_R_SUCCESS)
return status;
status = omapi_connection_put_uint32 (c, sizeof (int));
if (status != ISC_R_SUCCESS)
return status;
status = omapi_connection_put_uint32 (c, ((unsigned)
((lease -> flags &
BOOTP_LEASE) ? 1 : 0)));
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
return status; return status;

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: stables.c,v 1.12 2000/05/16 23:03:49 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: stables.c,v 1.13 2000/06/02 21:27:21 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -176,6 +176,12 @@ const char *dhcp_flink_state_names [] = {
}; };
#endif /* FAILOVER_PROTOCOL */ #endif /* FAILOVER_PROTOCOL */
/* Failover binding state names. These are used even if there is no
failover protocol support. */
const char *binding_state_names [] = {
"free", "active", "expired", "released", "abandoned",
"reset", "backup", "reserved", "bootp" };
struct universe agent_universe; struct universe agent_universe;
struct option agent_options [256] = { struct option agent_options [256] = {
{ "pad", "", &agent_universe, 0 }, { "pad", "", &agent_universe, 0 },