#ifndef lint
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 */
#include "dhcpd.h"
return;
}
config -> auth_policy = policy;
- } else if (token != BOOTP) {
+ } else if (token != TOKEN_BOOTP) {
if (policy != P_PREFER &&
policy != P_IGNORE &&
policy != P_ACCEPT) {
parse_warn (cfile, "unknown key %s", val);
parse_semi (cfile);
break;
- case BOOTP:
+ case TOKEN_BOOTP:
lease -> is_bootp = 1;
break;
#ifndef lint
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 */
#include "dhcpd.h"
}
/* 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. */
if (client -> active)
struct client_state *client = cpp;
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",
client -> name ? client -> name : client -> interface -> name,
- inet_ntoa (sockaddr_broadcast.sin_addr),
- ntohs (sockaddr_broadcast.sin_port));
+ inet_ntoa (destination.sin_addr),
+ ntohs (destination.sin_port));
- /* Send out a packet. */
- result = send_packet (client -> interface, (struct packet *)0,
- &client -> packet,
- client -> packet_length,
- inaddr_any, &sockaddr_broadcast,
- (struct hardware *)0);
+ 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. */
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
+ from, &destination,
+ (struct hardware *)0);
}
void make_client_options (client, lease, type, sid, rip, prl, op)
for (ip = interfaces; ip; ip = ip -> next) {
for (client = ip -> client; client; client = client -> 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)
write_client_lease (client,
- client -> active, 1);
+ client -> active, 1, 0);
}
}
for (ip = dummy_interfaces; ip; ip = ip -> next) {
for (client = ip -> client; client; client = client -> 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)
write_client_lease (client,
- client -> active, 1);
+ client -> active, 1, 0);
}
}
fflush (leaseFile);
}
-void write_client_lease (client, lease, rewrite)
+int write_client_lease (client, lease, rewrite, makesure)
struct client_state *client;
struct client_lease *lease;
int rewrite;
+ int makesure;
{
int i;
struct tm *t;
struct option_cache *oc;
struct data_string ds;
pair *hash;
+ int errors = 0;
if (!rewrite) {
if (leases_written++ > 20) {
/* If the lease came from the config file, we don't need to stash
a copy in the lease database. */
if (lease -> is_static)
- return;
+ return 1;
if (!leaseFile) { /* XXX */
leaseFile = fopen (path_dhclient_db, "w");
log_fatal ("can't create %s: %m", path_dhclient_db);
}
+ errno = 0;
fprintf (leaseFile, "lease {\n");
if (lease -> is_bootp)
fprintf (leaseFile, " bootp;\n");
if (lease -> medium)
fprintf (leaseFile, " medium \"%s\";\n",
lease -> medium -> string);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
memset (&ds, 0, sizeof ds);
(oc -> option -> code,
ds.data, ds.len, 1, 1));
data_string_forget (&ds, MDL);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
}
}
}
t -> tm_hour, t -> tm_min, t -> tm_sec);
fprintf (leaseFile, "}\n");
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
void do_release(client)
struct client_state *client;
{
+ struct data_string ds;
+ struct option_cache *oc;
+
/* make_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */
/* Make a DHCPRELEASE packet, and set appropriate per-interface
flags. */
make_release (client, client -> active);
- client -> destination = iaddr_broadcast;
+
+ 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 -> first_sending = cur_time;
client -> interval = client -> config -> initial_interval;
/* Send out the first and only DHCPRELEASE packet. */
send_release (client);
- }
-
- /* remove the timeouts for this client */
- cancel_timeout (NULL, client);
- /* if there was no lease, nothing to "do" */
- if (client -> active) {
+ /* Do the client script RELEASE operation. */
script_init (client,
"RELEASE", (struct string_list *)0);
if (client -> alias)
client -> alias);
script_go (client);
}
+
+ /* remove the timeouts for this client */
+ cancel_timeout (0, client);
}
int dhclient_interface_shutdown_hook (struct interface_info *interface)
#ifndef lint
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 */
#include "dhcpd.h"
if (!strcasecmp (atom + 1, "lgorithm"))
return ALGORITHM;
if (!strcasecmp (atom + 1, "bandoned"))
- return ABANDONED;
+ return TOKEN_ABANDONED;
if (!strcasecmp (atom + 1, "dd"))
return TOKEN_ADD;
if (!strcasecmp (atom + 1, "ll"))
return ARRAY;
if (!strcasecmp (atom + 1, "ddress"))
return ADDRESS;
+ if (!strcasecmp (atom + 1, "ctive"))
+ return TOKEN_ACTIVE;
break;
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"))
return BINARY_TO_ASCII;
if (!strcasecmp (atom + 1, "ackoff-cutoff"))
return BACKOFF_CUTOFF;
- if (!strcasecmp (atom + 1, "ootp"))
- return BOOTP;
if (!strcasecmp (atom + 1, "ooting"))
return BOOTING;
if (!strcasecmp (atom + 1, "oot-unknown-clients"))
if (!strcasecmp (atom + 1, "eny"))
return DENY;
if (!strcasecmp (atom + 1, "eleted"))
- return DELETED;
+ return TOKEN_DELETED;
if (!strcasecmp (atom + 1, "elete"))
return TOKEN_DELETE;
if (!strncasecmp (atom + 1, "efault", 6)) {
return EXPIRY;
if (!strcasecmp (atom + 2, "pire"))
return EXPIRE;
+ if (!strcasecmp (atom + 2, "pired"))
+ return TOKEN_EXPIRED;
}
if (!strcasecmp (atom + 1, "ncode-int"))
return ENCODE_INT;
return FUNCTION;
if (!strcasecmp (atom + 1, "ailover"))
return FAILOVER;
+ if (!strcasecmp (atom + 1, "ree"))
+ return TOKEN_FREE;
break;
case 'g':
if (!strcasecmp (atom + 1, "iaddr"))
return NS_NXRRSET;
if (!strcasecmp (atom + 1, "ull"))
return TOKEN_NULL;
+ if (!strcasecmp (atom + 1, "ext"))
+ return TOKEN_NEXT;
break;
case 'o':
if (!strcasecmp (atom + 1, "r"))
return RELEASE;
if (!strcasecmp (atom + 1, "efused"))
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;
case 's':
if (!strcasecmp (atom + 1, "tate"))
struct lease {
OMAPI_OBJECT_PREAMBLE;
struct lease *next;
- struct lease *prev;
struct lease *n_uid, *n_hw;
- struct lease *waitq_next;
struct iaddr ip_addr;
- TIME starts, ends, timestamp;
+ TIME starts, ends, timestamp, sort_time;
unsigned char *uid;
unsigned uid_len;
unsigned uid_max;
struct executable_statement *on_commit;
struct executable_statement *on_release;
- int flags;
+ u_int16_t flags;
# define STATIC_LEASE 1
-# define BOOTP_LEASE 2
# define PERSISTENT_FLAGS (0)
# define MS_NULL_TERMINATION 8
-# define ABANDONED_LEASE 16
-# define PEER_IS_OWNER 32
-# define ON_UPDATE_QUEUE 64
-# define ON_ACK_QUEUE 128
-# define EPHEMERAL_FLAGS (BOOTP_LEASE | MS_NULL_TERMINATION | \
- ABANDONED_LEASE | PEER_IS_OWNER | \
+# define ON_UPDATE_QUEUE 16
+# define ON_ACK_QUEUE 32
+# define EPHEMERAL_FLAGS (MS_NULL_TERMINATION | \
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;
TIME tstp; /* Time sent to partner. */
struct shared_network *shared_network;
struct permit *permit_list;
struct permit *prohibit_list;
- struct lease *leases;
- struct lease *insertion_point;
- struct lease *last_lease;
- struct lease *next_expiry;
+ struct lease *active;
+ struct lease *expired;
+ struct lease *free;
+ struct lease *backup;
+ struct lease *abandoned;
+ TIME next_event_time;
#if defined (FAILOVER_PROTOCOL)
int lease_count;
- int local_leases;
- int peer_leases;
+ int free_leases;
+ int backup_leases;
dhcp_failover_state_t *failover_peer;
#endif
};
extern int ft_sizes [];
extern const char *dhcp_flink_state_names [];
#endif
+extern const char *binding_state_names [];
+
extern struct universe agent_universe;
extern struct option agent_options [256];
extern struct universe server_universe;
void destroy_client_lease PROTO ((struct client_lease *));
void rewrite_client_leases PROTO ((void));
-void write_client_lease PROTO ((struct client_state *,
- struct client_lease *, int));
+int write_client_lease PROTO ((struct client_state *,
+ struct client_lease *, int, int));
char *dhcp_option_ev_name PROTO ((struct option *));
void script_init PROTO ((struct client_state *, const char *,
int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int));
void enter_subnet PROTO ((struct subnet *));
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));
void release_lease PROTO ((struct lease *, struct packet *));
void abandon_lease PROTO ((struct lease *, const char *));
int dhcp_failover_pool_check (struct pool *);
int dhcp_failover_state_pool_check (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 *);
isc_result_t dhcp_failover_state_set_value PROTO ((omapi_object_t *,
omapi_object_t *,
isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *,
omapi_object_t *, int, ...);
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 *,
int, const char *));
isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *,
void failover_print PROTO ((char *, unsigned *, unsigned, const char *));
void update_partner PROTO ((struct lease *));
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,
dhcp_type_failover_state)
OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t,
EXPIRE = 308,
UNKNOWN_CLIENTS = 309,
ALLOW = 310,
- BOOTP = 311,
DENY = 312,
BOOTING = 313,
DEFAULT = 314,
MEDIUM = 316,
ALIAS = 317,
REBOOT = 318,
- ABANDONED = 319,
+ TOKEN_ABANDONED = 319,
BACKOFF_CUTOFF = 320,
INITIAL_INTERVAL = 321,
NAMESERVER = 322,
STATIC = 414,
NEVER = 415,
INFINITE = 416,
- DELETED = 417,
+ TOKEN_DELETED = 417,
UPDATED_DNS_RR = 418,
DNS_DELETE = 419,
DUPLICATES = 420,
STATE = 466,
UNKNOWN_STATE = 567,
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 FTR_UNKNOWN 254
/* Lease states: */
-#define FTS_FREE 1
-#define FTS_ACTIVE 2
-#define FTS_EXPIRED 3
-#define FTS_RELEASED 4
-#define FTS_ABANDONED 5
-#define FTS_RESET 6
-#define FTS_BACKUP 7
+typedef enum {
+ FTS_FREE = 1,
+ FTS_ACTIVE = 2,
+ FTS_EXPIRED = 3,
+ FTS_RELEASED = 4,
+ FTS_ABANDONED = 5,
+ FTS_RESET = 6,
+ FTS_BACKUP = 7,
+ FTS_RESERVED = 8,
+ FTS_BOOTP = 9
+} binding_state_t;
#define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048
#ifndef lint
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 */
#include "dhcpd.h"
case SECONDARY:
peer -> i_am = secondary;
+ if (peer -> hba)
+ parse_warn (cfile,
+ "secondary may not define %s",
+ "load balance settings.");
break;
case PEER:
case HBA:
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,
COLON, 16, 8)) {
skip_to_rbrace (cfile, 1);
case SPLIT:
token = next_token (&val, cfile);
+ if (peer -> i_am == secondary)
+ parse_warn (cfile,
+ "secondary may not define %s",
+ "load balance settings.");
if (token != NUMBER) {
parse_warn (cfile, "expecting number");
badsplit:
}
} 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) {
group -> shared_network -> failover_peer = peer;
}
case DYNAMIC:
permit -> type = permit_dynamic_bootp_clients;
- if (next_token (&val, cfile) != BOOTP) {
+ if (next_token (&val, cfile) != TOKEN_BOOTP) {
parse_warn (cfile,
"expecting \"bootp\"");
skip_to_semi (cfile);
}
/* If the host declaration was created by the server,
remember to save it. */
- if (token == DELETED) {
+ if (token == TOKEN_DELETED) {
deleted = 1;
token = next_token (&val, cfile);
if (!parse_semi (cfile))
token = next_token (&val, cfile);
parse_warn (cfile, "unexpected end of file");
break;
- } else if (token == DELETED) {
+ } else if (token == TOKEN_DELETED) {
token = next_token (&val, cfile);
parse_semi (cfile);
deletedp = 1;
int noequal, newbinding;
struct binding *binding;
isc_result_t status;
+ binding_state_t *statep;
lease = (struct lease *)0;
status = lease_allocate (&lease, MDL);
break;
case DYNAMIC_BOOTP:
- seenbit = 128;
- lease -> flags |= BOOTP_LEASE;
+ seenbit = 256;
+ lease -> binding_state = FTS_BOOTP;
+ lease -> next_binding_state = FTS_BOOTP;
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;
+ case TOKEN_ABANDONED:
+ seenbit = 256;
+ lease -> binding_state = FTS_ABANDONED;
+ lease -> next_binding_state = FTS_ABANDONED;
parse_semi (cfile);
break;
- case ABANDONED:
+ case TOKEN_NEXT:
+ seenbit = 128;
+ statep = &lease -> next_binding_state;
+ goto do_binding_state;
+
+ case BINDING:
seenbit = 256;
- lease -> flags |= ABANDONED_LEASE;
+ 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);
break;
token = next_token (&val, cfile);
switch (token) {
- case BOOTP:
+ case TOKEN_BOOTP:
status = option_cache (oc, (struct data_string *)0, data,
&server_options [SV_ALLOW_BOOTP]);
break;
#ifndef lint
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 */
#include "dhcpd.h"
}
}
- if (lease -> flags & PEER_IS_OWNER) {
- errno = 0;
- fprintf (db_file, "\n peer is owner;");
- if (errno) {
- ++errors;
- }
- }
+ fprintf (db_file, "\n binding state %s;",
+ ((lease -> binding_state > 0 &&
+ lease -> binding_state <= FTS_BOOTP)
+ ? binding_state_names [lease -> binding_state - 1]
+ : "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,
write it out. */
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) {
if (!b -> value)
continue;
#ifndef lint
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 */
#include "dhcpd.h"
: packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL)
- if (lease && lease -> pool &&
- lease -> pool -> failover_peer) {
- peer = lease -> pool -> failover_peer;
- if ((lease -> flags & PEER_IS_OWNER) &&
- peer -> my_state == normal) {
- log_info ("%s: letting peer %s respond.",
- msgbuf, peer -> name);
- goto out;
- }
+ if (lease && !lease_mine_to_extend (lease)) {
+ log_info ("%s: letting peer %s answer", msgbuf,
+ lease -> pool -> failover_peer -> name);
+ goto out;
}
#endif
if (allocatedp && lease && lease -> pool &&
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)) {
log_debug ("%s: load balance to peer %s",
msgbuf, peer -> name);
find_lease (&lease, packet,
subnet -> shared_network, &ours, MDL);
+
if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname))
s = lease -> client_hostname;
? inet_ntoa (packet -> raw -> giaddr)
: 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
address on a different network, NAK it. If the Requested
Address option was used, the protocol says that it must
}
}
-#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
the client is in the SELECTING state, ignore the request -
it's not ours. */
struct option_cache *oc;
struct data_string data;
char *s;
+ char msgbuf [1024]; /* XXX */
/* DHCPRELEASE must not specify address in requested-address
option, but old protocol specs weren't explicit about this,
s = (char *)0;
/* Say what we're doing... */
- log_info ("DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
- inet_ntoa (packet -> raw -> ciaddr),
- (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,
- lease ? "" : "not ");
+ sprintf (msgbuf,
+ "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
+ inet_ntoa (packet -> raw -> ciaddr),
+ (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,
+ 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 (lease && lease -> ends > cur_time) {
release_lease (lease, packet);
- lease_dereference (&lease, MDL);
+ log_info ("%s", msgbuf);
}
+ out:
+ if (lease)
+ lease_dereference (&lease, MDL);
}
void dhcpdecline (packet, ms_nulltp)
int i;
const char *status;
char *s;
+ char msgbuf [1024]; /* XXX */
/* DHCPDECLINE must specify address. */
if (!(oc = lookup_option (&dhcp_universe, packet -> options,
data_string_forget (&data, 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);
/* Execute statements in scope starting with the subnet scope. */
/* If we found a lease, mark it as unusable and complain. */
if (lease) {
abandon_lease (lease, "declined.");
- status = "";
+ status = "abandoned";
}
- status = " (not found)";
+ status = "not found";
} else
- status = " (ignored)";
+ status = "ignored";
- if (!ignorep) {
- char *s;
- 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);
- }
+ if (!ignorep)
+ log_info ("%s: %s", msgbuf, status);
- option_state_dereference (&options, MDL);
+ out:
+ if (options)
+ option_state_dereference (&options, MDL);
if (lease)
lease_dereference (&lease, MDL);
}
/* Try to find a matching host declaration for this lease. */
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
identifier or hardware address on the packet, and
evaluate_option_cache (&d1, packet, lease,
packet -> options, state -> options,
&lease -> scope, oc, MDL)) {
- struct host_decl *h;
- hp = (struct host_decl *)0;
find_hosts_by_uid (&hp, d1.data, d1.len, MDL);
data_string_forget (&d1, MDL);
- if (!hp)
- find_hosts_by_haddr (&hp,
- packet -> raw -> htype,
- packet -> raw -> chaddr,
- packet -> raw -> hlen,
- MDL);
+ if (hp)
+ host_reference (&lease -> host, hp, MDL);
+ }
+ if (!hp) {
+ find_hosts_by_haddr (&hp,
+ packet -> raw -> htype,
+ packet -> raw -> chaddr,
+ packet -> raw -> hlen,
+ MDL);
for (h = hp; h; h = h -> n_ipaddr) {
if (!h -> fixed_addr)
break;
}
if (h)
host_reference (&lease -> host, hp, MDL);
- if (hp)
- host_dereference (&hp, MDL);
- } else
- lease -> host = (struct host_decl *)0;
+ }
+ if (hp)
+ host_dereference (&hp, MDL);
}
/* Drop the request if it's not allowed for this client. By
lt -> ends = when;
else
lt -> ends = state -> offered_expiry;
+ lt -> next_binding_state = FTS_ACTIVE;
} else {
lease_time = MAX_TIME - cur_time;
}
lt -> ends = state -> offered_expiry = cur_time + lease_time;
- lt -> flags = BOOTP_LEASE;
+ lt -> next_binding_state = FTS_BOOTP;
}
lt -> timestamp = cur_time;
it) either. */
if (!(supersede_lease (lease, lt, !offer || offer == DHCPACK,
- offer == DHCPACK)
+ offer == DHCPACK, offer == DHCPACK)
|| (offer && offer != DHCPACK))) {
log_info ("%s: database update failed", msg);
free_lease_state (state, MDL);
static_lease_dereference (lease, MDL);
lease_dereference (<, MDL);
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 (<, MDL);
/* Toss ip_lease if it hasn't yet expired and doesn't belong to the
client. */
if (ip_lease &&
- ip_lease -> ends >= cur_time &&
((ip_lease -> uid &&
(!have_client_identifier ||
ip_lease -> uid_len != client_identifier.len ||
memcmp (&ip_lease -> hardware_addr.hbuf [1],
packet -> raw -> chaddr,
(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 (ip_lease)
log_info ("rejecting lease for requested address.");
#endif
- lease_dereference (&ip_lease, MDL);
+ lease_dereference (&ip_lease, MDL);
+ }
}
/* If for some reason the client has more than one lease
on the subnet that matches its uid, pick the one that
it asked for and (if we can) free the other. */
if (ip_lease &&
- ip_lease -> ends >= cur_time &&
+ ip_lease -> binding_state == FTS_ACTIVE &&
ip_lease -> uid && ip_lease != uid_lease) {
if (have_client_identifier &&
(ip_lease -> uid_len == client_identifier.len) &&
!memcmp (client_identifier.data,
ip_lease -> uid, ip_lease -> uid_len)) {
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",
(print_hw_addr
(packet -> raw -> htype,
if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease)
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... */
if (hw_lease && hw_lease == uid_lease) {
#if defined (DEBUG_FIND_LEASE)
#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
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. */
requested, we assume that previous bugginess on the part
of the client, or a server database loss, caused the lease to
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) {
log_error ("Reclaiming REQUESTed abandoned IP address %s.",
piaddr (lease -> ip_addr));
- lease -> flags &= ~ABANDONED_LEASE;
- } else if (lease && (lease -> flags & ABANDONED_LEASE)) {
+ } else if (lease && (lease -> binding_state == FTS_ABANDONED)) {
/* 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
sent if this lookup is for a DHCPREQUEST, and force the client
lease -> hardware_addr = hp -> interface;
lease -> starts = lease -> timestamp = lease -> ends = MIN_TIME;
lease -> flags = STATIC_LEASE;
+ lease -> binding_state = FTS_FREE;
lease_reference (lp, lease, MDL);
lease_dereference (&lease, MDL);
return 1;
struct pool *pool, int *peer_has_leases)
{
struct lease *lease = (struct lease *)0;
+ struct lease **lq;
struct permit *permit;
if (!pool)
return allocate_lease (lp, packet, pool -> next,
peer_has_leases);
- lease = pool -> last_lease;
-
#if defined (FAILOVER_PROTOCOL)
/* 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
means the peer is hogging all the free leases, so we can print
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 tstp if we're in, e.g., PARTNER_DOWN? Where do we deal with
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
failover peer. */
- if (lease -> pool && lease -> pool -> failover_peer) {
- while (lease &&
- (lease -> flags & PEER_IS_OWNER) &&
- (lease -> ends <=
- cur_time + lease -> pool -> failover_peer -> mclt))
- lease = lease -> prev;
- /* We didn't find an unexpired lease that we own? */
- if (lease && lease -> flags & PEER_IS_OWNER)
- lease = (struct lease *)0;
+ if (pool -> failover_peer) {
+ if (pool -> failover_peer -> i_am == primary) {
+ if (pool -> backup)
+ *peer_has_leases = 1;
+ lease = pool -> free;
+ if (!lease)
+ lease = pool -> abandoned;
+ } else {
+ if (pool -> free)
+ *peer_has_leases = 1;
+ lease = pool -> backup;
+ }
}
+#else
+ if (pool -> free)
+ lease = pool -> free;
+ else
+ lease = pool -> abandoned;
#endif
/* If there are no leases in the pool that have
better, take it. */
/* XXX what if there are non-abandoned leases that are younger
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
love, but that's okay, don't reclaim the abandoned lease. */
if (*lp)
pool -> next, peer_has_leases)) {
log_error ("Reclaiming abandoned IP address %s.",
piaddr (lease -> ip_addr));
- lease -> flags &= ~ABANDONED_LEASE;
lease_reference (lp, lease, MDL);
}
return 1;
\fBnot authoritative;\fR
.PP
The DHCP server will normally assume that the configuration
-information about a given network segment is known to be correct and
-is authoritative. So if a client requests an IP address on a given
-network segment that the server knows is not valid for that segment,
-the server will respond with a DHCPNAK message, causing the client to
-forget its IP address and try to get a new one.
-.PP
-If a DHCP server is being configured by somebody who is not the
-network administrator and who therefore does not wish to assert this
-level of authority, then the statement "not authoritative" should be
-written in the appropriate scope in the configuration file.
-.PP
-Usually, writing \fBnot authoritative;\fR at the top level of the file
+information about a given network segment is not known to be correct
+and is not authoritative. This is so that if a naive user installs a
+DHCP server not fully understanding how to configure it, it does not
+send spurious DHCPNAK messages to clients that have obtained addresses
+from a legitimate DHCP server on the network.
+.PP
+Network administrators setting up authoritative DHCP servers for their
+networks should always write \fBauthoritative;\fR at the top of their
+configuration file to indicate that the DHCP server \fIshould\fR send
+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
+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
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
n\bno\bot\bt a\bau\but\bth\bho\bor\bri\bit\bta\bat\bti\biv\bve\be;\b;
The DHCP server will normally assume that the configuraÂ
- tion information about a given network segment is known to
- be correct and is authoritative. So if a client requests
- an IP address on a given network segment that the server
- knows is not valid for that segment, the server will
- respond with a DHCPNAK message, causing the client to forÂ
- get its IP address and try to get a new one.
-
- If a DHCP server is being configured by somebody who is
- not the network administrator and who therefore does not
- wish to assert this level of authority, then the statement
- "not authoritative" should be written in the appropriate
- scope in the configuration file.
-
- Usually, writing n\bno\bot\bt a\bau\but\bth\bho\bor\bri\bit\bta\bat\bti\biv\bve\be;\b; at the top level of
- the file 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 some networks for which it
+ tion information about a given network segment is not
+ known to be correct and is not authoritative. This is so
+ that if a naive user installs a DHCP server not fully
+ understanding how to configure it, it does not send spuriÂ
+ ous DHCPNAK messages to clients that have obtained
+ addresses from a legitimate DHCP server on the network.
+
+ Network administrators setting up authoritative DHCP
+ servers for their networks should always write a\bau\but\bth\bho\bor\bri\bit\bta\baÂ\bÂ
+ t\bti\biv\bve\be;\b; at the top of their configuration file to indicate
+ that the DHCP server _\bs_\bh_\bo_\bu_\bl_\bd send DHCPNAK messages to misÂ
+ 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 a\bau\but\bth\bho\bor\bri\bit\bta\bat\bti\biv\bve\be;\b; at the top level of the
+ file 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 some networks for which it
is not, it may be more appropriate to declare authority on
a per-network-segment basis.
Note that the most specific scope for which the concept of
- authority makes any sense is the physical network segment
- - either a shared-network statement or a subnet statement
- that is not contained within a shared-network statement.
+ authority makes any sense is the physical network segment
+ - either a shared-network statement or a subnet statement
+ that is not contained within a shared-network statement.
It is not meaningful to specify that the server is authorÂ
- itative for some subnets within a shared network, but not
- authoritative for others, nor is it meaningful to specify
- that the server is authoritative for some host declaraÂ
+ itative for some subnets within a shared network, but not
+ authoritative for others, nor is it meaningful to specify
+ that the server is authoritative for some host declaraÂ
tions and not others.
- T\bTh\bhe\be _\ba_\bl_\bw_\ba_\by_\bs_\b-_\br_\be_\bp_\bl_\by_\b-_\br_\bf_\bc_\b1_\b0_\b4_\b8 s\bst\bta\bat\bte\bem\bme\ben\bnt\bt
-
-
23
dhcpd.conf(5) dhcpd.conf(5)
+ T\bTh\bhe\be _\ba_\bl_\bw_\ba_\by_\bs_\b-_\br_\be_\bp_\bl_\by_\b-_\br_\bf_\bc_\b1_\b0_\b4_\b8 s\bst\bta\bat\bte\bem\bme\ben\bnt\bt
+
a\bal\blw\bwa\bay\bys\bs-\b-r\bre\bep\bpl\bly\by-\b-r\brf\bfc\bc1\b10\b04\b48\b8 _\bf_\bl_\ba_\bg;\b;
- Some BOOTP clients expect RFC1048-style responses, but do
- not follow RFC1048 when sending their requests. You can
- tell that a client is having this problem if it is not
- getting the options you have configured for it and if you
- see in the server log the message "(non-rfc1048)" printed
+ Some BOOTP clients expect RFC1048-style responses, but do
+ not follow RFC1048 when sending their requests. You can
+ tell that a client is having this problem if it is not
+ getting the options you have configured for it and if you
+ see in the server log the message "(non-rfc1048)" printed
with each BOOTREQUEST that is logged.
- If you want to send rfc1048 options to such a client, you
- can set the a\bal\blw\bwa\bay\bys\bs-\b-r\bre\bep\bpl\bly\by-\b-r\brf\bfc\bc1\b10\b04\b48\b8 option in that client's
+ If you want to send rfc1048 options to such a client, you
+ can set the a\bal\blw\bwa\bay\bys\bs-\b-r\bre\bep\bpl\bly\by-\b-r\brf\bfc\bc1\b10\b04\b48\b8 option in that client's
host declaration, and the DHCP server will respond with an
- RFC-1048-style vendor options field. This flag can be
- set in any scope, and will affect all clients covered by
+ RFC-1048-style vendor options field. This flag can be
+ set in any scope, and will affect all clients covered by
that scope.
T\bTh\bhe\be _\ba_\bl_\bw_\ba_\by_\bs_\b-_\bb_\br_\bo_\ba_\bd_\bc_\ba_\bs_\bt s\bst\bta\bat\bte\bem\bme\ben\bnt\bt
a\bal\blw\bwa\bay\bys\bs-\b-b\bbr\bro\boa\bad\bdc\bca\bas\bst\bt _\bf_\bl_\ba_\bg;\b;
- The DHCP and BOOTP protocols both require DHCP and BOOTP
+ The DHCP and BOOTP protocols both require DHCP and BOOTP
clients to set the broadcast bit in the flags field of the
- BOOTP message header. Unfortunately, some DHCP and BOOTP
- clients do not do this, and therefore may not receive
- responses from the DHCP server. The DHCP server can be
- made to always broadcast its responses to clients by setÂ
- ting this flag to 'on' for the relevant scope. To avoid
+ BOOTP message header. Unfortunately, some DHCP and BOOTP
+ clients do not do this, and therefore may not receive
+ responses from the DHCP server. The DHCP server can be
+ made to always broadcast its responses to clients by setÂ
+ ting this flag to 'on' for the relevant scope. To avoid
creating excess broadcast traffic on your network, we recÂ
- ommend that you restrict the use of this option to as few
- clients as possible. For example, the Microsoft DHCP
+ ommend that you restrict the use of this option to as few
+ clients as possible. For example, the Microsoft DHCP
client is known not to have this problem, as are the OpenÂ
Transport and ISC DHCP clients.
o\bon\bne\be-\b-l\ble\bea\bas\bse\be-\b-p\bpe\ber\br-\b-c\bcl\bli\bie\ben\bnt\bt _\bf_\bl_\ba_\bg;\b;
If this flag is enabled, whenever a client sends a DHCPREÂ
- QUEST for a particular lease, the server will automatiÂ
- cally free any other leases the client holds. This preÂ
- sumes that when the client sends a DHCPREQUEST, it has
- forgotten any lease not mentioned in the DHCPREQUEST -
- i.e., the client has only a single network interface _\ba_\bn_\bd
- it does not remember leases it's holding on networks to
- which it is not currently attached. Neither of these
+ QUEST for a particular lease, the server will automatiÂ
+ cally free any other leases the client holds. This preÂ
+ sumes that when the client sends a DHCPREQUEST, it has
+ forgotten any lease not mentioned in the DHCPREQUEST -
+ i.e., the client has only a single network interface _\ba_\bn_\bd
+ it does not remember leases it's holding on networks to
+ which it is not currently attached. Neither of these
assumptions are guaranteed or provable, so we urge caution
in the use of this statement.
u\bus\bse\be-\b-l\ble\bea\bas\bse\be-\b-a\bad\bdd\bdr\br-\b-f\bfo\bor\br-\b-d\bde\bef\bfa\bau\bul\blt\bt-\b-r\bro\bou\but\bte\be _\bf_\bl_\ba_\bg;\b;
- If the _\bu_\bs_\be_\b-_\bl_\be_\ba_\bs_\be_\b-_\ba_\bd_\bd_\br_\b-_\bf_\bo_\br_\b-_\bd_\be_\bf_\ba_\bu_\bl_\bt_\b-_\br_\bo_\bu_\bt_\be parameter is true
- in a given scope, then instead of sending the value
dhcpd.conf(5) dhcpd.conf(5)
- specified in the routers option (or sending no value at
- all), the IP address of the lease being assigned is sent
- to the client. This supposedly causes Win95 machines to
- ARP for all IP addresses, which can be helpful if your
- router is configured for proxy ARP.
+ If the _\bu_\bs_\be_\b-_\bl_\be_\ba_\bs_\be_\b-_\ba_\bd_\bd_\br_\b-_\bf_\bo_\br_\b-_\bd_\be_\bf_\ba_\bu_\bl_\bt_\b-_\br_\bo_\bu_\bt_\be parameter is true
+ in a given scope, then instead of sending the value speciÂ
+ fied in the routers option (or sending no value at all),
+ the IP address of the lease being assigned is sent to the
+ client. This supposedly causes Win95 machines to ARP for
+ all IP addresses, which can be helpful if your router is
+ configured for proxy ARP.
T\bTh\bhe\be _\bs_\be_\br_\bv_\be_\br_\b-_\bi_\bd_\be_\bn_\bt_\bi_\bf_\bi_\be_\br s\bst\bta\bat\bte\bem\bme\ben\bnt\bt
s\bse\ber\brv\bve\ber\br-\b-i\bid\bde\ben\bnt\bti\bif\bfi\bie\ber\br _\bh_\bo_\bs_\bt_\bn_\ba_\bm_\be;\b;
- The server-identifier statement can be used to define the
- value that is sent in the DHCP Server Identifier option
- for a given scope. The value specified m\bmu\bus\bst\bt be an IP
- address for the DHCP server, and must be reachable by all
+ The server-identifier statement can be used to define the
+ value that is sent in the DHCP Server Identifier option
+ for a given scope. The value specified m\bmu\bus\bst\bt be an IP
+ address for the DHCP server, and must be reachable by all
clients served by a particular scope.
- The use of the server-identifier statement is not recomÂ
- mended - the only reason to use it is to force a value
+ The use of the server-identifier statement is not recomÂ
+ mended - the only reason to use it is to force a value
other than the default value to be sent on occasions where
- the default value would be incorrect. The default value
- is the first IP address associated with the physical netÂ
+ the default value would be incorrect. The default value
+ is the first IP address associated with the physical netÂ
work interface on which the request arrived.
The usual case where the _\bs_\be_\br_\bv_\be_\br_\b-_\bi_\bd_\be_\bn_\bt_\bi_\bf_\bi_\be_\br statement needs
- to be sent is when a physical interface has more than one
+ to be sent is when a physical interface has more than one
IP address, and the one being sent by default isn't approÂ
- priate for some or all clients served by that interface.
- Another common case is when an alias is defined for the
- purpose of having a consistent IP address for the DHCP
- server, and it is desired that the clients use this IP
+ priate for some or all clients served by that interface.
+ Another common case is when an alias is defined for the
+ purpose of having a consistent IP address for the DHCP
+ server, and it is desired that the clients use this IP
address when contacting the server.
Supplying a value for the dhcp-server-identifier option is
d\bdd\bdn\bns\bs-\b-u\bup\bpd\bda\bat\bte\bes\bs _\bf_\bl_\ba_\bg;\b;
- The _\bd_\bd_\bn_\bs_\b-_\bu_\bp_\bd_\ba_\bt_\be_\bs parameter controls whether or not the
- server will attempt to do a ddns update when a lease is
- confirmed. Set this to _\bo_\bf_\bf if the server should not
- attempt to do updates within a certain scope. The _\bd_\bd_\bn_\bs_\b-
+ The _\bd_\bd_\bn_\bs_\b-_\bu_\bp_\bd_\ba_\bt_\be_\bs parameter controls whether or not the
+ server will attempt to do a ddns update when a lease is
+ confirmed. Set this to _\bo_\bf_\bf if the server should not
+ attempt to do updates within a certain scope. The _\bd_\bd_\bn_\bs_\b-
_\bu_\bp_\bd_\ba_\bt_\be_\bs parameter is on by default.
R\bRE\bEF\bFE\bER\bRE\bEN\bNC\bCE\bE:\b: O\bOP\bPT\bTI\bIO\bON\bN S\bST\bTA\bAT\bTE\bEM\bME\bEN\bNT\bTS\bS
- DHCP option statements are documented in the d\bdh\bhc\bcp\bp-\b-
+ DHCP option statements are documented in the d\bdh\bhc\bcp\bp-\b-
o\bop\bpt\bti\bio\bon\bns\bs(\b(5\b5)\b) manual page.
S\bSE\bEE\bE A\bAL\bLS\bSO\bO
dhcpd.conf(5), dhcpd.leases(5), RFC2132, RFC2131.
-A\bAU\bUT\bTH\bHO\bOR\bR
- d\bdh\bhc\bcp\bpd\bd(\b(8\b8)\b) was written by Ted Lemon <mellon@vix.com> under a
dhcpd.conf(5) dhcpd.conf(5)
- contract with Vixie Labs. Funding for this project was
+A\bAU\bUT\bTH\bHO\bOR\bR
+ d\bdh\bhc\bcp\bpd\bd(\b(8\b8)\b) was written by Ted Lemon <mellon@vix.com> under a
+ contract with Vixie Labs. Funding for this project was
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
h\bht\btt\btp\bp:\b:/\b//\b/w\bww\bww\bw.\b.i\bis\bsc\bc.\b.o\bor\brg\bg/\b/i\bis\bsc\bc.\b.
-
-
#ifndef lint
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 */
#include "dhcpd.h"
a state object. */
/* XXX this should be authenticated! */
if (link -> imsg -> type == FTM_CONNECT) {
+ const char *errmsg;
+ int reason;
/* See if we can find a failover_state object that
matches this connection. This message should only
be received by a secondary from a primary. */
/* If we can't find a failover protocol state
for this remote host, drop the connection */
if (!state) {
+ errmsg = "unknown server";
+ reason = FTR_INVALID_PARTNER;
+
+ badconnect:
/* XXX Send a refusal message first?
XXX Look in protocol spec for guidance. */
- log_error ("Failover CONNECT from %s %d.%d.%d.%d",
- "unknown server",
+ log_error ("Failover CONNECT from %d.%d.%d.%d: %s",
((u_int8_t *)
(&link -> imsg -> server_addr)) [0],
((u_int8_t *)
((u_int8_t *)
(&link -> imsg -> server_addr)) [2],
((u_int8_t *)
- (&link -> imsg -> server_addr)) [3]);
+ (&link -> imsg -> server_addr)) [3],
+ errmsg);
dhcp_failover_send_connectack
- ((omapi_object_t *)link,
- FTR_INVALID_PARTNER);
+ ((omapi_object_t *)link, state,
+ reason, errmsg);
omapi_disconnect (c, 0);
link -> state = dhcp_flink_disconnected;
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)
dhcp_failover_state_reference
(&link -> state_object, state, MDL);
ft_options [option_code].type == FT_DDNS1) {
ddns_fqdn_t *ddns =
((ddns_fqdn_t *)
- (((char *)&link -> imsg) +
+ (((char *)link -> imsg) +
ft_options [option_code].offset));
op_count = (ft_options [option_code].type == FT_DDNS1
op_count = option_len / op_size;
fo = ((failover_option_t *)
- (((char *)&link -> imsg) +
+ (((char *)link -> imsg) +
ft_options [option_code].offset));
fo -> count = op_count;
dhcp_failover_link_reference (&state -> link_to_peer,
link, MDL);
status = (dhcp_failover_send_connectack
- ((omapi_object_t *)link, 0));
+ ((omapi_object_t *)link, state, 0, 0));
if (status != ISC_R_SUCCESS) {
dhcp_failover_link_dereference
(&state -> link_to_peer, MDL);
}
dhcp_failover_state_transition (state, "connect");
} else if (link -> imsg -> type == FTM_CONNECTACK) {
+ const char *errmsg;
+ int 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 *)
(&link -> imsg -> server_addr)) [0],
((u_int8_t *)
" rejected: ",
(dhcp_failover_reject_reason_print
(link -> imsg -> reject_reason)));
+ /* XXX print message from peer if peer sent message. */
omapi_disconnect (link -> outer, 1);
return ISC_R_SUCCESS;
}
(state,
(u_int8_t *)&link -> imsg -> server_addr,
sizeof link -> imsg -> server_addr)) {
- log_error ("Failover CONNECTACK from %s %d.%d.%d.%d",
- "unknown server",
+ errmsg = "unknown server";
+ reason = FTR_INVALID_PARTNER;
+ badconnectack:
+ log_error ("Failover CONNECTACK from %d.%d.%d.%d: %s",
((u_int8_t *)
(&link -> imsg -> server_addr)) [0],
((u_int8_t *)
((u_int8_t *)
(&link -> imsg -> server_addr)) [2],
((u_int8_t *)
- (&link -> imsg -> server_addr)) [3]);
+ (&link -> imsg -> server_addr)) [3],
+ errmsg);
dhcp_failover_send_disconnect ((omapi_object_t *)link,
- FTR_INVALID_PARTNER, 0);
+ reason, errmsg);
omapi_disconnect (link -> outer, 0);
}
if (state -> link_to_peer) {
- log_error ("Failover CONNECTACK %s %d.%d.%d.%d",
- "while already connected",
- ((u_int8_t *)
- (&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);
+ errmsg = "already connected";
+ reason = FTR_DUP_CONNECTION;
+ goto badconnectack;
}
+
dhcp_failover_link_reference (&state -> link_to_peer,
link, MDL);
dhcp_failover_state_transition (state, "connect");
{
int lts;
int leases_queued = 0;
- struct lease *lp;
+ struct lease *lp = (struct lease *)0;
+ struct lease *next = (struct lease *)0;
struct shared_network *s;
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)
return 0;
for (p = s -> pools; p; p = p -> next) {
if (p -> failover_peer != state)
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,
- 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) {
- struct lease lt;
-
- leases_queued += lts;
- for (lp = p -> last_lease; lp && lts;
- lp = lp -> prev) {
- if (!(lp -> flags & PEER_IS_OWNER)) {
- lp -> flags |= PEER_IS_OWNER;
- lp -> tstp = cur_time;
- if (!write_lease (lp) ||
- !commit_leases () ||
- !dhcp_failover_queue_update (lp)) {
- log_info ("%s lease %s on giveaway",
- "unable to commit",
- piaddr (lp -> ip_addr));
- }
+ lease_reference (&lp, *lq, MDL);
+
+ while (lp && lts) {
+ /* Remember the next lease in the list. */
+ if (next)
+ lease_dereference (&next, MDL);
+ if (lp -> next)
+ lease_reference (&next, lp -> next, MDL);
+
+ --lts;
+ ++leases_queued;
+ lp -> next_binding_state = peer_lease_state;
+ lp -> tstp = cur_time;
+ lp -> starts = cur_time;
+ if (!supersede_lease (lp, (struct lease *)0, 1, 1, 0))
+ {
+ log_info ("can't commit lease %s on giveaway",
+ 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) {
log_info ("lease imbalance - lts = %d", lts);
leases_queued -= lts;
}
}
dhcp_failover_send_poolresp (state, leases_queued);
+ dhcp_failover_send_updates (state);
return leases_queued;
}
pool -> failover_peer -> my_state != normal)
return 0;
- log_info ("pool %lx total %d local free %d peer free %d",
+ if (pool -> failover_peer -> i_am == primary)
+ lts = (pool -> backup_leases - pool -> free_leases) / 2;
+ 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 -> local_leases, pool -> peer_leases);
+ pool -> free_leases, pool -> backup_leases, lts);
- lts = ((pool -> local_leases +
- pool -> peer_leases) / 2) - pool -> local_leases;
if (lts > 1) {
/* XXX What about multiple pools? */
dhcp_failover_send_poolreq (pool -> failover_peer);
not an error for this to be called on a lease for which there's no
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;
}
lease_reference (&state -> update_queue_tail, lease, MDL);
lease -> flags |= ON_UPDATE_QUEUE;
- dhcp_failover_send_updates (state);
+ if (immediate)
+ dhcp_failover_send_updates (state);
return 1;
}
return;
}
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) {
lease_dereference (&lp -> next_pending, MDL);
char *obuf,
unsigned *obufix,
unsigned obufmax,
- const char *fmt, ...) {
+ const char *fmt, ...)
+{
va_list va;
char tbuf [256];
dhcp_failover_link_t *link;
dhcp_failover_state_t *state;
isc_result_t status;
+ char hba [32];
#if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64];
unsigned obufix = 0;
if (!l -> outer || l -> outer -> type != omapi_type_connection)
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
(link, l -> outer,
FTM_CONNECT,
0, 0),
dhcp_failover_make_option (FTO_MCLT, FMA,
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));
#if defined (DEBUG_FAILOVER_MESSAGES)
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_state_t *state;
isc_result_t status;
#if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64];
if (!l || l -> type != dhcp_type_failover_link)
return ISC_R_INVALIDARG;
link = (dhcp_failover_link_t *)l;
- state = link -> state_object;
if (!l -> outer || l -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG;
status = (dhcp_failover_put_message
(link, l -> outer,
FTM_CONNECTACK,
- dhcp_failover_make_option (FTO_SERVER_ADDR, FMA,
- state -> server_identifier.len,
- state -> server_identifier.data),
- dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
- state -> max_flying_updates),
- dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA,
- state -> max_response_delay),
+ (state
+ ? (dhcp_failover_make_option
+ (FTO_SERVER_ADDR, FMA,
+ state -> server_identifier.len,
+ state -> server_identifier.data))
+ : &skip_failover_option),
+ (state
+ ? dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
+ 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,
"isc-%s", DHCP_VERSION),
dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA,
? dhcp_failover_make_option (FTO_REJECT_REASON,
FMA, reason)
: &skip_failover_option),
- (failover_option_t *)0));
+ (errmsg
+ ? dhcp_failover_make_option (FTO_MESSAGE, FMA,
+ strlen (errmsg), errmsg)
+ : &skip_failover_option),
+ (failover_option_t *)0));
#if defined (DEBUG_FAILOVER_MESSAGES)
if (status != ISC_R_SUCCESS)
#if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64];
unsigned obufix = 0;
- int binding_status;
# define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(bndupd");
if (!link -> outer || link -> outer -> type != omapi_type_connection)
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. */
status = (dhcp_failover_put_message
(link, link -> outer,
lease -> ip_addr.len,
lease -> ip_addr.iabuf),
dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
- binding_status),
+ lease -> binding_state),
lease -> uid_len
? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
lease -> uid_len,
#if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64];
unsigned obufix = 0;
- int binding_status;
# define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(bndack");
if (!link -> outer || link -> outer -> type != omapi_type_connection)
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)
message = dhcp_failover_reject_reason_print (reason);
lease -> ip_addr.len,
lease -> ip_addr.iabuf),
dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
- binding_status),
+ lease -> binding_state),
lease -> uid_len
? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
lease -> uid_len,
unsigned obufix = 0;
# define FMA obuf, &obufix, sizeof obuf
- failover_print (FMA, "(poolreq");
+ failover_print (FMA, "(poolresp");
#else
# define FMA (unsigned char *)0, (unsigned *)0, 0
#endif
struct iaddr ia;
int reason = FTR_MISC_REJECT;
const char *message;
+ int new_binding_state;
ia.len = sizeof msg -> assigned_addr;
memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
}
if (msg -> options_present & FTB_BINDING_STATUS) {
- if (state -> i_am == primary) {
- if (msg -> binding_status == FTS_BACKUP)
- lease -> flags |= PEER_IS_OWNER;
- else if (msg -> binding_status == FTS_FREE)
- lease -> flags &= ~PEER_IS_OWNER;
- } else {
- if (msg -> binding_status == FTS_BACKUP)
- lease -> flags &= PEER_IS_OWNER;
- else if (msg -> binding_status == FTS_FREE)
- lease -> flags |= ~PEER_IS_OWNER;
+ /* Check the requested transition to make sure it's
+ valid. */
+ new_binding_state = (binding_state_transition_check
+ (lease, state, msg -> binding_status));
+ if (new_binding_state != msg -> binding_status) {
+ dhcp_failover_send_bind_ack
+ (state, lease, msg, FTR_FATAL_CONFLICT,
+ "invalid binding state transition");
}
+ lt -> next_binding_state = new_binding_state;
}
/* 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";
bad:
dhcp_failover_send_bind_ack (state, lease, msg,
}
/* Try to install the new information. */
- supersede_lease (lease, lt, 1, 0);
+ supersede_lease (lease, lt, 1, 0, 0);
state -> cur_unacked_updates--;
dhcp_failover_ack_queue_remove (state, lease);
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,
DHO_DHCP_CLIENT_IDENTIFIER);
memset (&ds, 0, sizeof ds);
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,
dhcp_type_failover_state)
OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t,
Server-specific in-memory database support. */
/*
- * Copyright (c) 1996-1999 Internet Software Consortium.
+ * Copyright (c) 1996-2000 Internet Software Consortium.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#ifndef lint
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 */
#include "dhcpd.h"
subnet -> netmask,
i + min)),
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
lp -> ip_addr = ip_addr (subnet -> net,
- subnet -> netmask, i + min);
+ subnet -> netmask, i + min);
lp -> starts = lp -> timestamp = MIN_TIME;
lp -> ends = MIN_TIME;
subnet_reference (&lp -> subnet, subnet, MDL);
pool_reference (&lp -> pool, pool, MDL);
-#if defined (FAILOVER_PROTOCOL)
- if (pool -> failover_peer &&
- pool -> failover_peer -> i_am == secondary)
- lp -> flags = PEER_IS_OWNER;
- else
- lp -> flags = 0;
-#endif
+ lp -> binding_state = FTS_FREE;
+ lp -> next_binding_state = FTS_FREE;
+ lp -> flags = 0;
/* Link this entry into the list. */
- if (pool -> leases) {
- lease_reference (&lp -> next, pool -> leases, MDL);
- lease_dereference (&pool -> leases, MDL);
+ if (pool -> free) {
+ lease_reference (&lp -> next, pool -> free, MDL);
+ lease_dereference (&pool -> free, MDL);
}
- lease_reference (&pool -> leases, lp, MDL);
- if (lp -> next)
- lease_reference (&lp -> next -> prev,
- pool -> leases, MDL);
+ lease_reference (&pool -> free, lp, MDL);
lease_hash_add (lease_ip_addr_hash, lp -> ip_addr.iabuf,
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... */
plp = (struct lease *)0;
for (lp = dangling_leases; lp; lp = lp -> next) {
lp -> hostname = (char *)0;
lt -> client_hostname = lp -> client_hostname;
lp -> client_hostname = (char *)0;
- supersede_lease (lt, lp, 0, 0);
+ supersede_lease (lt, lp, 0, 0, 0);
lease_dereference (<, MDL);
}
lease_dereference (&lp, MDL);
/* If we don't have a place for this lease yet, save it for
later. */
if (!find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) {
- if (comp -> next)
- lease_dereference (&comp -> next, MDL);
+ if (lease -> next)
+ lease_dereference (&lease -> next, MDL);
if (dangling_leases)
- lease_reference (&comp -> next, dangling_leases, MDL);
- lease_reference (&dangling_leases, comp, MDL);
- if (comp -> prev)
- lease_dereference (&comp -> prev, MDL);
+ lease_reference (&lease -> next, dangling_leases, MDL);
+ lease_reference (&dangling_leases, lease, MDL);
} else {
- supersede_lease (comp, lease, 0, 0);
+ supersede_lease (comp, lease, 0, 0, 0);
}
}
list of leases by expiry time so that we can always find the oldest
lease. */
-int supersede_lease (comp, lease, commit, propogate)
+int supersede_lease (comp, lease, commit, propogate, pimmediate)
struct lease *comp, *lease;
int commit;
int propogate;
+ int pimmediate;
{
int enter_uid = 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... */
if (lease -> flags & STATIC_LEASE)
lease, then we allow that, in case a dynamic BOOTP lease is
requested *after* a DHCP lease has been assigned. */
- if (!(lease -> flags & ABANDONED_LEASE) &&
- comp -> ends > cur_time &&
+ if (lease -> binding_state != FTS_ABANDONED &&
+ (comp -> binding_state == FTS_ACTIVE ||
+ comp -> binding_state == FTS_RESERVED ||
+ comp -> binding_state == FTS_BOOTP) &&
(((comp -> uid && lease -> uid) &&
(comp -> uid_len != lease -> uid_len ||
memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
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 defined (FAILOVER_PROTOCOL)
+ comp -> cltt = lease -> cltt;
+ comp -> tstp = lease -> tstp;
+ comp -> tsfp = lease -> tsfp;
+#endif /* FAILOVER_PROTOCOL */
+ comp -> ends = lease -> ends;
+ comp -> next_binding_state = lease -> next_binding_state;
+
+ just_move_it:
+ /* Figure out which queue it's on. */
+ switch (comp -> binding_state) {
+ case FTS_FREE:
+ lq = &comp -> pool -> free;
+ comp -> pool -> free_leases--;
+ break;
+
+ case FTS_ACTIVE:
+ case FTS_RESERVED:
+ case FTS_BOOTP:
+ lq = &comp -> pool -> active;
+ break;
+
+ 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;
+ }
+
+ /* Remove the lease from its current place in its current
+ timer sequence. */
+ prev = (struct lease *)0;
+ 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 (&comp -> prev -> next,
- comp -> next, MDL);
+ lease_reference (&prev -> next, comp -> next, MDL);
lease_dereference (&comp -> next, MDL);
}
} else {
- lease_dereference (&comp -> pool -> leases, MDL);
+ lease_dereference (lq, 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);
+ lease_reference (lq, comp -> next, MDL);
+ lease_dereference (&comp -> next, 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)
- 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);
- }
+ /* Make the state transition. */
+ if (commit)
+ process_state_transition (comp);
+
+ /* 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;
}
-
- /* 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;
+
+ /* 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 (!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);
+ if (prev) {
+ if (prev -> next) {
+ lease_reference (&comp -> next, prev -> next, MDL);
+ lease_dereference (&prev -> next, MDL);
}
+ lease_reference (&prev -> next, 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 (*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,
+ (tvunref_t)pool_dereference);
}
- 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 -> tstp = lease -> tstp;
- comp -> tsfp = lease -> tsfp;
-#endif /* FAILOVER_PROTOCOL */
- comp -> ends = lease -> ends;
- /* If there's an expiry event on this lease, process it or
- queue it. */
-#if !defined (FAILOVER_PROTOCOL)
- if (comp -> on_expiry) {
+ /* Return zero if we didn't commit the lease to permanent storage;
+ nonzero if we did. */
+ return commit && write_lease (comp) && commit_leases ()
+#if defined (FAILOVER_PROTOCOL)
+ && (!propogate ||
+ dhcp_failover_queue_update (comp, pimmediate))
#endif
- if (comp -> ends <= cur_time && commit) {
- if (comp -> on_expiry) {
+ ;
+}
+
+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,
- comp -> on_expiry);
- executable_statement_dereference (&comp -> on_expiry,
+ 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;
+ }
- /* No sense releasing a lease after it's expired. */
- if (comp -> on_release)
- executable_statement_dereference
- (&comp -> on_release, MDL);
- } else {
- /* 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 ends.
-
- 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 (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)
- add_timeout (comp -> ends,
- pool_timer,
- comp -> pool,
- (tvref_t)pool_reference,
- (tvunref_t)
- 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 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);
}
-#if !defined (FAILOVER_PROTOCOL)
+
+ /* 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;
}
-#endif
- /* Return zero if we didn't commit the lease to permanent storage;
- nonzero if we did. */
- return commit && write_lease (comp) && commit_leases ()
-#if defined (FAILOVER_PROTOCOL)
- && (!propogate || dhcp_failover_queue_update (comp))
-#endif
- ;
+ lease -> binding_state = lease -> next_binding_state;
}
/* Copy the contents of one lease into another, correctly maintaining
lt -> tstp = lease -> tstp;
lt -> tsfp = lease -> tsfp;
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);
lease_dereference (<, MDL);
return status == ISC_R_SUCCESS;
struct lease *lease;
struct packet *packet;
{
- struct lease *lt;
-
/* If there are statements to execute when the lease is
released, execute them. */
if (lease -> on_release) {
executable_statement_dereference (&lease -> on_expiry, MDL);
if (lease -> ends > cur_time) {
- if (!lease_copy (<, lease, MDL))
- return;
-
- if (lt -> on_commit)
- executable_statement_dereference (< -> on_commit,
+ if (lease -> on_commit)
+ executable_statement_dereference (&lease -> on_commit,
MDL);
/* Blow away any bindings. */
- lt -> scope.bindings = (struct binding *)0;
-
- lt -> ends = cur_time;
- if (lt -> billing_class)
- class_dereference (< -> billing_class, MDL);
- supersede_lease (lease, lt, 1, 1);
- lease_dereference (<, MDL);
+ /* XXX free them?!? */
+ lease -> scope.bindings = (struct binding *)0;
+ lease -> ends = cur_time;
+#if defined (FAILOVER_PROTOCOL)
+ if (lease -> pool && lease -> pool -> failover_peer) {
+ lease -> next_binding_state = FTS_RELEASED;
+ } 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);
}
}
{
struct lease *lt = (struct lease *)0;
- lease -> flags |= ABANDONED_LEASE;
if (!lease_copy (<, lease, MDL))
return;
/* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0;
-
lt -> ends = cur_time; /* XXX */
+ lt -> next_binding_state = FTS_ABANDONED;
+
log_error ("Abandoning IP address %s: %s",
piaddr (lease -> ip_addr), message);
lt -> hardware_addr.hlen = 0;
lt -> uid_max = 0;
if (lt -> billing_class)
class_dereference (< -> billing_class, MDL);
- supersede_lease (lease, lt, 1, 1);
+ supersede_lease (lease, lt, 1, 1, 1);
lease_dereference (<, MDL);
}
/* Blow away any bindings. */
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 -> hardware_addr.hlen = 0;
if (lt -> uid != lt -> uid_buf)
lt -> uid_max = 0;
if (lt -> billing_class)
class_dereference (< -> billing_class, MDL);
- supersede_lease (lease, lt, 1, 1);
+ supersede_lease (lease, lt, 1, 1, 1);
lease_dereference (<, MDL);
}
void *vpool;
{
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;
- for (lease = pool -> next_expiry; lease; lease = lease -> prev) {
- /* Stop processing when we get to the first lease that has not
- yet expired. */
- if (lease -> ends > cur_time)
- 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 (lease -> on_release)
- executable_statement_dereference (&lease -> on_release,
- MDL);
+#define FREE_LEASES 0
+ lptr [FREE_LEASES] = &pool -> free;
+#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;
- /* There are two problems with writing the lease out here.
-
- The first is that we've just done a commit, and the write
- 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 ()) {
- log_error ("Error committing after writing lease %s",
- piaddr (lease -> ip_addr));
+ 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;
+ }
+
+ /* If there is a pending state change, and
+ this lease has gotten to the time when the
+ state change should happen, just call
+ 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);
+
+ lease_dereference (&lease, MDL);
+ if (next)
+ lease_reference (&lease, next, MDL);
}
-#if defined (FAILOVER_PROTOCOL)
- if (lease -> flags & PEER_IS_OWNER)
- pool -> peer_leases++;
- 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,
+ if (next)
+ lease_dereference (&next, MDL);
+ if (lease)
+ lease_dereference (&lease, MDL);
+ }
+ if (next_expiry != MAX_TIME) {
+ pool -> next_event_time = next_expiry;
+ add_timeout (pool -> next_event_time, pool_timer, pool,
(tvref_t)pool_reference,
(tvunref_t)pool_dereference);
- }
+ } else
+ pool -> next_event_time = MIN_TIME;
+
}
/* Locate the lease associated with a given IP address... */
struct hash_bucket *hb;
int i;
int num_written;
+ struct lease **lptr [5];
/* Write all the dynamically-created group declarations. */
if (group_name_hash) {
/* Write all the leases. */
num_written = 0;
for (s = shared_networks; s; s = s -> next) {
- for (p = s -> pools; p; p = p -> next) {
- for (l = p -> leases; l; l = l -> next) {
- if (l -> hardware_addr.hlen ||
- l -> uid_len ||
- (l -> flags & ABANDONED_LEASE)) {
- if (!write_lease (l))
- log_fatal ("Can't rewrite %s",
- "lease database");
- num_written++;
- }
+ for (p = s -> pools; p; p = p -> 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 ||
+ l -> uid_len ||
+ (l -> binding_state != FTS_FREE)) {
+ if (!write_lease (l))
+ log_fatal ("Can't rewrite lease database");
+ num_written++;
}
+ }
}
+ }
}
log_info ("Wrote %d leases to leases file.", num_written);
if (!commit_leases ())
struct hash_bucket *hb;
int i;
struct lease *l;
+ struct lease **lptr [5];
/* Loop through each pool in each shared network and call the
expiry routine on the pool. */
#if defined (FAILOVER_PROTOCOL)
p -> lease_count = 0;
- p -> local_leases = 0;
- p -> peer_leases = 0;
+ p -> free_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++;
if (l -> ends <= cur_time) {
- if (l -> flags & PEER_IS_OWNER)
- p -> peer_leases++;
- else
- p -> local_leases++;
+ if (l -> binding_state == FTS_FREE)
+ p -> free_leases++;
+ else if (l -> binding_state == FTS_BACKUP)
+ p -> backup_leases++;
}
if (p -> failover_peer &&
l -> tstp > l -> tsfp &&
!(l -> flags & ON_UPDATE_QUEUE))
- dhcp_failover_queue_update (l);
+ dhcp_failover_queue_update (l, 1);
+ }
}
#endif
}
struct shared_network *s;
struct subnet *n;
struct pool *p;
+ struct lease **lptr [5];
+ int i;
log_info ("Subnets:");
for (n = subnets; n; n = n -> next_subnet) {
}
log_info ("Shared networks:");
for (s = shared_networks; s; s = s -> next) {
- log_info (" %s", s -> name);
- for (p = s -> pools; p; p = p -> next) {
- for (l = p -> leases; l; l = l -> next) {
- print_lease (l);
- }
- log_debug ("Last Lease:");
- print_lease (p -> last_lease);
+ log_info (" %s", s -> name);
+ for (p = s -> pools; p; p = p -> 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);
+ }
}
+ }
}
}
#ifndef lint
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 */
#include "dhcpd.h"
lease = (struct lease *)h;
/* We're skipping a lot of things it might be interesting to
- set - for now, we just make it possible to whack the abandoned
- flag. */
- if (!omapi_ds_strcmp (name, "abandoned")) {
- int bar;
-
- if (value -> type == omapi_datatype_int)
- 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;
+ set - for now, we just make it possible to whack the state. */
+ if (!omapi_ds_strcmp (name, "state")) {
+ unsigned long bar;
+ status = omapi_get_int_value (&bar, value);
+ if (status != ISC_R_SUCCESS)
+ return status;
- foo = lease -> flags;
- if (bar)
- lease -> flags |= ABANDONED_LEASE;
- else
- lease -> flags &= ~ABANDONED_LEASE;
- if (foo != lease -> flags)
- return ISC_R_SUCCESS;
+ if (bar < 1 || bar > FTS_BOOTP)
+ return ISC_R_INVALIDARG;
+ if (lease -> binding_state != bar) {
+ lease -> next_binding_state = bar;
+ if (supersede_lease (lease, 0, 1, 1, 1))
+ return ISC_R_SUCCESS;
+ return ISC_R_IOERROR;
+ }
return ISC_R_UNCHANGED;
}
return ISC_R_INVALIDARG;
lease = (struct lease *)h;
- if (!omapi_ds_strcmp (name, "abandoned"))
- return omapi_make_int_value (value, name,
- (lease -> flags &
- ABANDONED_LEASE) ? 1 : 0, MDL);
- else if (!omapi_ds_strcmp (name, "bootpp"))
+ if (!omapi_ds_strcmp (name, "state"))
return omapi_make_int_value (value, name,
- (lease -> flags &
- BOOTP_LEASE) ? 1 : 0, MDL);
+ (int)lease -> binding_state, MDL);
else if (!omapi_ds_strcmp (name, "ip-address"))
return omapi_make_const_value (value, name,
lease -> ip_addr.iabuf,
return ISC_R_INVALIDARG;
if (!write_lease (lease) || !commit_leases ()
#if defined (FAILOVER_PROTOCOL)
- || !dhcp_failover_queue_update (lease)
+ || !dhcp_failover_queue_update (lease, 1)
#endif
) {
return ISC_R_IOERROR;
/* Write out all the values. */
- status = omapi_connection_put_name (c, "abandoned");
- 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, (lease -> flags &
- ABANDONED_LEASE) ? 1U : 0U);
- if (status != ISC_R_SUCCESS)
- return status;
-
- status = omapi_connection_put_name (c, "bootpp");
+ status = omapi_connection_put_name (c, "state");
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)));
+ status = omapi_connection_put_uint32 (c, lease -> binding_state);
if (status != ISC_R_SUCCESS)
return status;
#ifndef lint
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 */
#include "dhcpd.h"
};
#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 option agent_options [256] = {
{ "pad", "", &agent_universe, 0 },