From 007e3ee4dfc2ddb718a9b2cd9845b97056cab816 Mon Sep 17 00:00:00 2001 From: Ted Lemon Date: Fri, 2 Jun 2000 21:27:21 +0000 Subject: [PATCH] Rework DHCP lease state handling to be compatible with failover protocol. --- client/clparse.c | 6 +- client/dhclient.c | 119 +++++-- common/conflex.c | 28 +- includes/dhcpd.h | 54 +-- includes/dhctoken.h | 17 +- includes/failover.h | 18 +- server/confpars.c | 112 ++++-- server/db.c | 36 +- server/dhcp.c | 308 ++++++++++------- server/dhcpd.conf.5 | 23 +- server/dhcpd.conf.cat5 | 158 ++++----- server/failover.c | 485 +++++++++++++++++++------- server/mdb.c | 766 ++++++++++++++++++++--------------------- server/omapi.c | 62 +--- server/stables.c | 8 +- 15 files changed, 1317 insertions(+), 883 deletions(-) diff --git a/client/clparse.c b/client/clparse.c index 393df3fe..c52d1fc0 100644 --- a/client/clparse.c +++ b/client/clparse.c @@ -43,7 +43,7 @@ #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" @@ -291,7 +291,7 @@ void parse_client_statement (cfile, ip, config) return; } config -> auth_policy = policy; - } else if (token != BOOTP) { + } else if (token != TOKEN_BOOTP) { if (policy != P_PREFER && policy != P_IGNORE && policy != P_ACCEPT) { @@ -919,7 +919,7 @@ void parse_client_lease_declaration (cfile, lease, ipp, clientp) parse_warn (cfile, "unknown key %s", val); parse_semi (cfile); break; - case BOOTP: + case TOKEN_BOOTP: lease -> is_bootp = 1; break; diff --git a/client/dhclient.c b/client/dhclient.c index 91da4d2a..a6e4b09f 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -41,7 +41,7 @@ #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" @@ -779,7 +779,7 @@ void bind_lease (client) } /* 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) @@ -1561,18 +1561,50 @@ void send_release (cpp) 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) @@ -1926,11 +1958,11 @@ void rewrite_client_leases () 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); } } @@ -1939,20 +1971,21 @@ void rewrite_client_leases () 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; @@ -1960,6 +1993,7 @@ void write_client_lease (client, lease, rewrite) struct option_cache *oc; struct data_string ds; pair *hash; + int errors = 0; if (!rewrite) { if (leases_written++ > 20) { @@ -1971,7 +2005,7 @@ void write_client_lease (client, lease, rewrite) /* If the lease came from the config file, we don't need to stash a copy in the lease database. */ if (lease -> is_static) - return; + return 1; if (!leaseFile) { /* XXX */ leaseFile = fopen (path_dhclient_db, "w"); @@ -1979,6 +2013,7 @@ void write_client_lease (client, lease, rewrite) log_fatal ("can't create %s: %m", path_dhclient_db); } + errno = 0; fprintf (leaseFile, "lease {\n"); if (lease -> is_bootp) fprintf (leaseFile, " bootp;\n"); @@ -1997,6 +2032,10 @@ void write_client_lease (client, lease, rewrite) if (lease -> medium) fprintf (leaseFile, " medium \"%s\";\n", lease -> medium -> string); + if (errno != 0) { + errors++; + errno = 0; + } memset (&ds, 0, sizeof ds); @@ -2018,6 +2057,10 @@ void write_client_lease (client, lease, rewrite) (oc -> option -> code, ds.data, ds.len, 1, 1)); data_string_forget (&ds, MDL); + if (errno != 0) { + errors++; + errno = 0; + } } } } @@ -2045,6 +2088,17 @@ void write_client_lease (client, lease, rewrite) t -> tm_hour, t -> tm_min, t -> tm_sec); 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 @@ -2357,6 +2411,9 @@ void client_location_changed () 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. */ @@ -2367,7 +2424,25 @@ void do_release(client) /* 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; @@ -2376,13 +2451,8 @@ void do_release(client) /* 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) @@ -2390,6 +2460,9 @@ void do_release(client) client -> alias); script_go (client); } + + /* remove the timeouts for this client */ + cancel_timeout (0, client); } int dhclient_interface_shutdown_hook (struct interface_info *interface) diff --git a/common/conflex.c b/common/conflex.c index ca6943a5..5d23d9f2 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -43,7 +43,7 @@ #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" @@ -503,7 +503,7 @@ static enum dhcp_token intern (atom, dfv) 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")) @@ -514,14 +514,20 @@ static enum dhcp_token intern (atom, dfv) 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")) @@ -575,7 +581,7 @@ static enum dhcp_token intern (atom, dfv) 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)) { @@ -619,6 +625,8 @@ static enum dhcp_token intern (atom, dfv) 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; @@ -649,6 +657,8 @@ static enum dhcp_token intern (atom, dfv) 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")) @@ -779,6 +789,8 @@ static enum dhcp_token intern (atom, dfv) 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")) @@ -850,6 +862,12 @@ static enum dhcp_token intern (atom, dfv) 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")) diff --git a/includes/dhcpd.h b/includes/dhcpd.h index f41017b7..e0f821f0 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -238,12 +238,10 @@ struct hardware { 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; @@ -261,19 +259,17 @@ struct lease { 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. */ @@ -500,14 +496,16 @@ struct pool { 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 }; @@ -1550,6 +1548,8 @@ extern u_int32_t fto_allowed []; 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; @@ -1617,8 +1617,8 @@ void make_release PROTO ((struct client_state *, struct client_lease *)); 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 *, @@ -2115,7 +2115,8 @@ void new_shared_network_interface PROTO ((struct parse *, 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 *)); @@ -2205,7 +2206,7 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *); 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 *, @@ -2243,7 +2244,9 @@ failover_option_t *dhcp_failover_make_option PROTO ((unsigned, char *, isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *, 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 *, @@ -2260,6 +2263,11 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *, void failover_print PROTO ((char *, unsigned *, unsigned, const char *)); void 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, diff --git a/includes/dhctoken.h b/includes/dhctoken.h index 3ed47519..98042d48 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -114,7 +114,6 @@ enum dhcp_token { EXPIRE = 308, UNKNOWN_CLIENTS = 309, ALLOW = 310, - BOOTP = 311, DENY = 312, BOOTING = 313, DEFAULT = 314, @@ -122,7 +121,7 @@ enum dhcp_token { MEDIUM = 316, ALIAS = 317, REBOOT = 318, - ABANDONED = 319, + TOKEN_ABANDONED = 319, BACKOFF_CUTOFF = 320, INITIAL_INTERVAL = 321, NAMESERVER = 322, @@ -216,7 +215,7 @@ enum dhcp_token { STATIC = 414, NEVER = 415, INFINITE = 416, - DELETED = 417, + TOKEN_DELETED = 417, UPDATED_DNS_RR = 418, DNS_DELETE = 419, DUPLICATES = 420, @@ -268,7 +267,17 @@ enum dhcp_token { 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 && \ diff --git a/includes/failover.h b/includes/failover.h index 9105a210..fef57f85 100644 --- a/includes/failover.h +++ b/includes/failover.h @@ -157,13 +157,17 @@ typedef struct { #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 diff --git a/server/confpars.c b/server/confpars.c index 8f877346..ae5a30b9 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -43,7 +43,7 @@ #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" @@ -711,6 +711,10 @@ void parse_failover_peer (cfile, group, type) case SECONDARY: peer -> i_am = secondary; + if (peer -> hba) + parse_warn (cfile, + "secondary may not define %s", + "load balance settings."); break; case PEER: @@ -783,6 +787,10 @@ void parse_failover_peer (cfile, group, type) 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); @@ -806,6 +814,10 @@ void parse_failover_peer (cfile, group, type) 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: @@ -868,6 +880,11 @@ void parse_failover_peer (cfile, group, type) } } 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; } @@ -1175,7 +1192,7 @@ void parse_pool_statement (cfile, group, type) 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); @@ -1385,7 +1402,7 @@ void parse_host_declaration (cfile, group) } /* 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)) @@ -2071,7 +2088,7 @@ void parse_group_declaration (cfile, group) 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; @@ -2215,6 +2232,7 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile) int noequal, newbinding; struct binding *binding; isc_result_t status; + binding_state_t *statep; lease = (struct lease *)0; status = lease_allocate (&lease, MDL); @@ -2351,34 +2369,76 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile) 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; @@ -2817,7 +2877,7 @@ int parse_allow_deny (oc, cfile, flag) 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; diff --git a/server/db.c b/server/db.c index da252c5f..6b8a3ba2 100644 --- a/server/db.c +++ b/server/db.c @@ -43,7 +43,7 @@ #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" @@ -143,13 +143,19 @@ int write_lease (lease) } } - 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. */ @@ -190,20 +196,6 @@ int write_lease (lease) 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; diff --git a/server/dhcp.c b/server/dhcp.c index ff000ca6..bd8c0e43 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -43,7 +43,7 @@ #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" @@ -138,15 +138,10 @@ void dhcpdiscover (packet, ms_nulltp) : 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 @@ -191,7 +186,7 @@ void dhcpdiscover (packet, ms_nulltp) 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); @@ -256,6 +251,7 @@ void dhcprequest (packet, ms_nulltp) find_lease (&lease, packet, subnet -> shared_network, &ours, MDL); + if (lease && lease -> client_hostname && db_printable (lease -> client_hostname)) s = lease -> client_hostname; @@ -278,6 +274,14 @@ void dhcprequest (packet, ms_nulltp) ? 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 @@ -360,7 +364,7 @@ void dhcprequest (packet, ms_nulltp) } } -#if defined (FAILOVER_PROTOCOL) +#if defined (FAILOVER_PROTOCOL) && 0 /* XXX this isn't the same as above! */ /* If we found a lease, but it belongs to a failover peer, and the client is in the SELECTING state, ignore the request - it's not ours. */ @@ -420,6 +424,7 @@ void dhcprelease (packet, ms_nulltp) 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, @@ -469,27 +474,44 @@ void dhcprelease (packet, ms_nulltp) 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) - : "")), - 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) + : "")), + 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) @@ -505,6 +527,7 @@ 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, @@ -522,6 +545,36 @@ void dhcpdecline (packet, ms_nulltp) 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) + : "")), + 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. */ @@ -549,38 +602,18 @@ void dhcpdecline (packet, ms_nulltp) /* 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) - : "")), - 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); } @@ -1358,7 +1391,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp) /* 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 @@ -1371,26 +1405,26 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp) 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 @@ -1640,6 +1674,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp) lt -> ends = when; else lt -> ends = state -> offered_expiry; + lt -> next_binding_state = FTS_ACTIVE; } else { lease_time = MAX_TIME - cur_time; @@ -1669,7 +1704,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp) } lt -> ends = state -> offered_expiry = cur_time + lease_time; - lt -> flags = BOOTP_LEASE; + lt -> next_binding_state = FTS_BOOTP; } lt -> timestamp = cur_time; @@ -1752,29 +1787,13 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp) 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); @@ -2637,7 +2656,6 @@ int find_lease (struct lease **lp, /* Toss ip_lease if it hasn't yet expired and doesn't belong to the client. */ if (ip_lease && - ip_lease -> ends >= cur_time && ((ip_lease -> uid && (!have_client_identifier || ip_lease -> uid_len != client_identifier.len || @@ -2649,25 +2667,43 @@ int find_lease (struct lease **lp, 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, @@ -2722,17 +2758,6 @@ int find_lease (struct lease **lp, 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) @@ -2753,6 +2778,37 @@ int find_lease (struct lease **lp, #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. */ @@ -2862,12 +2918,13 @@ int find_lease (struct lease **lp, 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 @@ -2941,6 +2998,7 @@ int mockup_lease (struct lease **lp, struct packet *packet, 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; @@ -2986,6 +3044,7 @@ int allocate_lease (struct lease **lp, struct packet *packet, struct pool *pool, int *peer_has_leases) { struct lease *lease = (struct lease *)0; + struct lease **lq; struct permit *permit; if (!pool) @@ -2998,31 +3057,39 @@ int allocate_lease (struct lease **lp, struct packet *packet, 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 @@ -3035,7 +3102,7 @@ int allocate_lease (struct lease **lp, struct packet *packet, 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) @@ -3045,7 +3112,6 @@ int allocate_lease (struct lease **lp, struct packet *packet, 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; diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index d50b031a..a4b66c11 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -1272,18 +1272,21 @@ override the use of the name in the host declaration. \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. +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 -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. +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 \fBnot authoritative;\fR at the top level of the file +Usually, writing \fBauthoritative;\fR at the top level of the file should be sufficient. However, if a DHCP server is to be set up so 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 diff --git a/server/dhcpd.conf.cat5 b/server/dhcpd.conf.cat5 index cb619ae6..f104d635 100644 --- a/server/dhcpd.conf.cat5 +++ b/server/dhcpd.conf.cat5 @@ -1478,39 +1478,39 @@ dhcpd.conf(5) dhcpd.conf(5) nnoott aauutthhoorriittaattiivvee;; 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. + 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. - 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. + Network administrators setting up authoritative DHCP + servers for their networks should always write aauutthhoorriittaa­­ + ttiivvee;; at the top of their configuration file to indicate + that the DHCP server _s_h_o_u_l_d 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 nnoott aauutthhoorriittaattiivvee;; 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 + Usually, writing aauutthhoorriittaattiivvee;; 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. - TThhee _a_l_w_a_y_s_-_r_e_p_l_y_-_r_f_c_1_0_4_8 ssttaatteemmeenntt - - 23 @@ -1522,36 +1522,38 @@ dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) + TThhee _a_l_w_a_y_s_-_r_e_p_l_y_-_r_f_c_1_0_4_8 ssttaatteemmeenntt + aallwwaayyss--rreeppllyy--rrffcc11004488 _f_l_a_g;; - 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 aallwwaayyss--rreeppllyy--rrffcc11004488 option in that client's + If you want to send rfc1048 options to such a client, you + can set the aallwwaayyss--rreeppllyy--rrffcc11004488 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. TThhee _a_l_w_a_y_s_-_b_r_o_a_d_c_a_s_t ssttaatteemmeenntt aallwwaayyss--bbrrooaaddccaasstt _f_l_a_g;; - 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. @@ -1560,13 +1562,13 @@ dhcpd.conf(5) dhcpd.conf(5) oonnee--lleeaassee--ppeerr--cclliieenntt _f_l_a_g;; 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 _a_n_d - 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 _a_n_d + 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. @@ -1574,8 +1576,6 @@ dhcpd.conf(5) dhcpd.conf(5) uussee--lleeaassee--aaddddrr--ffoorr--ddeeffaauulltt--rroouuttee _f_l_a_g;; - If the _u_s_e_-_l_e_a_s_e_-_a_d_d_r_-_f_o_r_-_d_e_f_a_u_l_t_-_r_o_u_t_e parameter is true - in a given scope, then instead of sending the value @@ -1588,36 +1588,38 @@ dhcpd.conf(5) dhcpd.conf(5) 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 _u_s_e_-_l_e_a_s_e_-_a_d_d_r_-_f_o_r_-_d_e_f_a_u_l_t_-_r_o_u_t_e parameter is true + in a given scope, then instead of sending the value 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. TThhee _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r ssttaatteemmeenntt sseerrvveerr--iiddeennttiiffiieerr _h_o_s_t_n_a_m_e;; - 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 mmuusstt 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 mmuusstt 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 _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r 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 @@ -1627,21 +1629,19 @@ dhcpd.conf(5) dhcpd.conf(5) ddddnnss--uuppddaatteess _f_l_a_g;; - The _d_d_n_s_-_u_p_d_a_t_e_s parameter controls whether or not the - server will attempt to do a ddns update when a lease is - confirmed. Set this to _o_f_f if the server should not - attempt to do updates within a certain scope. The _d_d_n_s_- + The _d_d_n_s_-_u_p_d_a_t_e_s parameter controls whether or not the + server will attempt to do a ddns update when a lease is + confirmed. Set this to _o_f_f if the server should not + attempt to do updates within a certain scope. The _d_d_n_s_- _u_p_d_a_t_e_s parameter is on by default. RREEFFEERREENNCCEE:: OOPPTTIIOONN SSTTAATTEEMMEENNTTSS - DHCP option statements are documented in the ddhhccpp-- + DHCP option statements are documented in the ddhhccpp-- ooppttiioonnss((55)) manual page. SSEEEE AALLSSOO dhcpd.conf(5), dhcpd.leases(5), RFC2132, RFC2131. -AAUUTTHHOORR - ddhhccppdd((88)) was written by Ted Lemon under a @@ -1654,9 +1654,11 @@ AAUUTTHHOORR dhcpd.conf(5) dhcpd.conf(5) - contract with Vixie Labs. Funding for this project was +AAUUTTHHOORR + ddhhccppdd((88)) was written by Ted Lemon 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 hhttttpp::////wwwwww..iisscc..oorrgg//iisscc.. @@ -1706,8 +1708,6 @@ dhcpd.conf(5) dhcpd.conf(5) - - diff --git a/server/failover.c b/server/failover.c index 1f8627b6..07539b8d 100644 --- a/server/failover.c +++ b/server/failover.c @@ -43,7 +43,7 @@ #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" @@ -383,6 +383,8 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *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. */ @@ -396,10 +398,13 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h, /* 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 *) @@ -407,15 +412,32 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h, ((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); @@ -567,7 +589,7 @@ static isc_result_t do_a_failover_option (c, link) 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 @@ -613,7 +635,7 @@ static isc_result_t do_a_failover_option (c, link) 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; @@ -1052,7 +1074,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, 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); @@ -1061,8 +1083,10 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, } 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 *) @@ -1074,6 +1098,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, " 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; } @@ -1082,8 +1107,10 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, (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 *) @@ -1091,27 +1118,19 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, ((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"); @@ -1331,9 +1350,14 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state) { 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; @@ -1342,32 +1366,59 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state) 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); - 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)); - } - } - } + /* 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; } + if (lts > 1) { + 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; @@ -1375,6 +1426,7 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state) } } dhcp_failover_send_poolresp (state, leases_queued); + dhcp_failover_send_updates (state); return leases_queued; } @@ -1388,12 +1440,15 @@ int dhcp_failover_pool_check (struct pool *pool) pool -> failover_peer -> my_state != normal) return 0; - log_info ("pool %lx total %d local free %d peer free %d", - (unsigned long)pool, pool -> lease_count, - pool -> local_leases, pool -> peer_leases); + 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 -> 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); @@ -1477,7 +1532,7 @@ isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *state) not an error for this to be called on a lease for which there's no 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; @@ -1509,7 +1564,8 @@ int dhcp_failover_queue_update (struct lease *lease) } 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; } @@ -1530,7 +1586,7 @@ void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *state, 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); @@ -2140,7 +2196,8 @@ failover_option_t *dhcp_failover_option_printf (unsigned code, char *obuf, unsigned *obufix, unsigned obufmax, - const char *fmt, ...) { + const char *fmt, ...) +{ va_list va; char tbuf [256]; @@ -2472,6 +2529,7 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l) dhcp_failover_link_t *link; dhcp_failover_state_t *state; isc_result_t status; + char hba [32]; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; @@ -2489,6 +2547,12 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l) if (!l -> outer || l -> outer -> type != omapi_type_connection) 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, @@ -2507,7 +2571,9 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l) 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) @@ -2521,10 +2587,11 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l) 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]; @@ -2539,20 +2606,26 @@ isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason) if (!l || l -> type != dhcp_type_failover_link) 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, @@ -2563,7 +2636,11 @@ isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason) ? 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) @@ -2635,7 +2712,6 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state, #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; - int binding_status; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(bndupd"); @@ -2651,26 +2727,6 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state, if (!link -> outer || link -> outer -> type != omapi_type_connection) 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, @@ -2679,7 +2735,7 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state, 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, @@ -2726,7 +2782,6 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state, #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; - int binding_status; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(bndack"); @@ -2742,26 +2797,6 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state, if (!link -> outer || link -> outer -> type != omapi_type_connection) 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); @@ -2773,7 +2808,7 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state, 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, @@ -2864,7 +2899,7 @@ isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *state, 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 @@ -2902,6 +2937,7 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state, 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); @@ -2964,21 +3000,20 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state, } if (msg -> options_present & FTB_BINDING_STATUS) { - if (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, @@ -3022,7 +3057,7 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *state, } /* 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); @@ -3120,6 +3155,11 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state) 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); @@ -3139,6 +3179,195 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state) 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, diff --git a/server/mdb.c b/server/mdb.c index c6b28978..079540ff 100644 --- a/server/mdb.c +++ b/server/mdb.c @@ -3,7 +3,7 @@ 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 @@ -43,7 +43,7 @@ #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" @@ -498,45 +498,27 @@ void new_address_range (low, high, subnet, pool) 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) { @@ -568,7 +550,7 @@ void new_address_range (low, high, subnet, pool) 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); @@ -744,15 +726,13 @@ void enter_lease (lease) /* 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); } } @@ -761,14 +741,20 @@ void enter_lease (lease) 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) @@ -783,8 +769,10 @@ int supersede_lease (comp, lease, commit, propogate) 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))) || @@ -905,274 +893,234 @@ int supersede_lease (comp, lease, commit, propogate) hw_hash_add (comp); } - /* Remove the lease from its current place in the - timeout sequence. */ - if (comp -> prev) { - lease_dereference (&comp -> prev -> next, MDL); - if (comp -> next) { - lease_reference (&comp -> prev -> next, - comp -> next, MDL); - lease_dereference (&comp -> next, MDL); - } - } else { - lease_dereference (&comp -> pool -> leases, MDL); - if (comp -> next) { - lease_reference (&comp -> pool -> leases, - comp -> next, MDL); - } - } - if (comp -> next) { - lease_dereference (&comp -> next -> prev, MDL); - if (comp -> prev) { - lease_reference (&comp -> next -> prev, - comp -> prev, MDL); - } - } - if (comp -> pool -> last_lease == comp) { - lease_dereference (&comp -> pool -> last_lease, MDL); - if (comp -> prev) - lease_reference (&comp -> pool -> last_lease, - comp -> prev, MDL); - } - if (comp -> prev) - lease_dereference (&comp -> prev, MDL); - if (comp -> next) - lease_dereference (&comp -> next, MDL); - - - /* If there's an expiry event on this lease, get rid of it - (we may wind up putting it back, but we can't count on - that here without too much additional complexity). */ - if (comp -> pool -> next_expiry == comp) { #if defined (FAILOVER_PROTOCOL) - lp = comp -> prev; -#else - for (lp = comp -> prev; lp; lp = lp -> prev) - if (lp -> on_expiry) - break; -#endif - if (lp -#if !defined (FAILOVER_PROTOCOL) - && lp -> on_expiry -#endif - ) { - lease_dereference (&comp -> pool -> next_expiry, MDL); - lease_reference (&comp -> pool -> next_expiry, - lp, MDL); - if (commit) - add_timeout (lp -> ends, - pool_timer, lp -> pool, - (tvref_t)pool_reference, - (tvunref_t)pool_dereference); - } else { - lease_dereference (&comp -> pool -> next_expiry, MDL); - if (commit) - cancel_timeout (pool_timer, comp -> pool); - } - } - - /* Find the last insertion point... */ - if (comp == comp -> pool -> insertion_point || - !comp -> pool -> insertion_point) { - lp = comp -> pool -> leases; - } else { - lp = comp -> pool -> insertion_point; - } - - if (!lp) { - /* Nothing on the list yet? Just make comp the - head of the list. */ - lease_reference (&comp -> pool -> leases, comp, MDL); - if (comp -> pool -> last_lease) { - lease_dereference (&comp -> pool -> last_lease, MDL); - lease_reference (&comp -> pool -> last_lease, - comp, MDL); - } - } else if (lp -> ends > lease -> ends) { - /* Skip down the list until we run out of list - or find a place for comp. */ - while (lp -> next && lp -> ends > lease -> ends) { - lp = lp -> next; - } - if (lp -> ends > lease -> ends) { - /* If we ran out of list, put comp at the end. */ - lease_reference (&lp -> next, comp, MDL); - lease_reference (&comp -> prev, lp, MDL); - if (comp -> pool -> last_lease) - lease_dereference (&comp -> pool -> last_lease, - MDL); - lease_reference (&comp -> pool -> last_lease, - comp, MDL); - } else { - /* If we didn't, put it between lp and - the previous item on the list. */ - if (lp -> prev) { - lease_reference (&comp -> prev, - lp -> prev, MDL); - lease_dereference (&lp -> prev -> next, MDL); - lease_reference (&comp -> prev -> next, - comp, MDL); - lease_dereference (&lp -> prev, MDL); - } else { - if (comp -> pool -> leases) - lease_dereference - (&comp -> pool -> leases, MDL); - lease_reference (&comp -> pool -> leases, - comp, MDL); - } - lease_reference (&comp -> next, lp, MDL); - lease_reference (&lp -> prev, comp, MDL); - } - } else { - /* Skip up the list until we run out of list - or find a place for comp. */ - while (lp -> prev && lp -> ends < lease -> ends) { - lp = lp -> prev; - } - if (lp -> ends < lease -> ends) { - /* If we ran out of list, put comp at the beginning. */ - lease_reference (&lp -> prev, comp, MDL); - lease_reference (&comp -> next, lp, MDL); - if (comp -> pool -> leases) - lease_dereference (&comp -> pool -> leases, - MDL); - lease_reference (&comp -> pool -> leases, comp, MDL); - } else { - /* If we didn't, put it between lp and - the next item on the list. */ - if (lp -> next) { - lease_reference (&comp -> next, - lp -> next, MDL); - lease_dereference (&lp -> next -> prev, MDL); - lease_reference (&lp -> next -> prev, - comp, MDL); - lease_dereference (&lp -> next, MDL); - } else { - /* XXX are we really supposed to - XXX be doing this? */ - if (comp -> pool -> last_lease) - lease_dereference - (&comp -> pool -> last_lease, - MDL); - lease_reference (&comp -> pool -> last_lease, - comp, MDL); - } - lease_reference (&comp -> prev, lp, MDL); - lease_reference (&lp -> next, comp, MDL); - } - } - if (comp -> pool -> insertion_point) - lease_dereference (&comp -> pool -> insertion_point, MDL); - lease_reference (&comp -> pool -> insertion_point, comp, MDL); -#if defined (FAILOVER_PROTOCOL) - if (comp -> ends <= cur_time && lease -> ends > cur_time) { - if (lease -> flags & PEER_IS_OWNER) - comp -> pool -> peer_leases--; - else - comp -> pool -> local_leases--; - } else if (comp -> ends > cur_time && lease -> ends <= cur_time) { - if (lease -> flags & PEER_IS_OWNER) - comp -> pool -> peer_leases++; - else - comp -> pool -> local_leases++; - } comp -> cltt = lease -> cltt; comp -> tstp = lease -> tstp; comp -> tsfp = lease -> tsfp; #endif /* FAILOVER_PROTOCOL */ comp -> ends = lease -> ends; + comp -> next_binding_state = lease -> next_binding_state; - /* If there's an expiry event on this lease, process it or - queue it. */ -#if !defined (FAILOVER_PROTOCOL) - if (comp -> on_expiry) { -#endif - if (comp -> ends <= cur_time && commit) { - if (comp -> 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, - MDL); - } + 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; - /* 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 !defined (FAILOVER_PROTOCOL) + 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 (&prev -> next, comp -> next, MDL); + lease_dereference (&comp -> next, MDL); + } + } else { + lease_dereference (lq, MDL); + if (comp -> next) { + lease_reference (lq, comp -> next, MDL); + lease_dereference (&comp -> next, MDL); + } + } + + /* 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; + } + + /* Insertion sort the lease onto the appropriate queue. */ + prev = (struct lease *)0; + for (lp = *lq; lp; lp = lp -> next) { + if (lp -> sort_time > comp -> sort_time) + break; + prev = lp; + } + if (prev) { + if (prev -> next) { + lease_reference (&comp -> next, prev -> next, MDL); + lease_dereference (&prev -> next, MDL); + } + lease_reference (&prev -> next, comp, MDL); + } else { + if (*lq) { + lease_reference (&comp -> next, *lq, MDL); + lease_dereference (lq, MDL); + } + lease_reference (lq, comp, MDL); + } + + /* If this is the next lease that will timeout on the pool, + zap the old timeout and set the timeout on this pool to the + time that the lease's next event will happen. + + We do not actually set the timeout unless commit is true - + we don't want to thrash the timer queue when reading the + lease database. Instead, the database code calls the + expiry event on each pool after reading in the lease file, + and the expiry code sets the timer if there's anything left + to expire after it's run any outstanding expiry events on + the pool. */ + if (commit && + comp -> sort_time != MIN_TIME && + comp -> sort_time < cur_time && + comp -> sort_time < comp -> pool -> next_event_time) { + comp -> pool -> next_event_time = comp -> sort_time; + add_timeout (comp -> pool -> next_event_time, + pool_timer, comp -> pool, + (tvref_t)pool_reference, + (tvunref_t)pool_dereference); } -#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)) + && (!propogate || + dhcp_failover_queue_update (comp, pimmediate)) #endif ; } +void process_state_transition (struct lease *lease) +{ + /* If the lease was active and is now no longer active, but isn't + released, then it just expired, so do the expiry event. */ + if (lease -> next_binding_state != lease -> binding_state && + (lease -> binding_state == FTS_ACTIVE || + lease -> binding_state == FTS_BOOTP || + lease -> binding_state == FTS_RESERVED) && + lease -> next_binding_state != FTS_RELEASED) { + if (lease -> on_expiry) { + execute_statements ((struct packet *)0, lease, + (struct option_state *)0, + (struct option_state *)0, /* XXX */ + &lease -> scope, + lease -> on_expiry); + executable_statement_dereference (&lease -> on_expiry, + MDL); + } + + /* No sense releasing a lease after it's expired. */ + if (lease -> on_release) + executable_statement_dereference (&lease -> on_release, + MDL); + /* Send the expiry time to the peer. */ + lease -> tstp = lease -> ends; + } + + /* If the lease was active and is now released, do the release + event. */ + if ((lease -> binding_state == FTS_ACTIVE || + lease -> binding_state == FTS_BOOTP || + lease -> binding_state == FTS_RESERVED) && + lease -> next_binding_state == FTS_RELEASED) { + if (lease -> on_release) { + execute_statements ((struct packet *)0, lease, + (struct option_state *)0, + (struct option_state *)0, /* XXX */ + &lease -> scope, + lease -> on_release); + executable_statement_dereference (&lease -> on_release, + MDL); + } + + /* A released lease can't expire. */ + if (lease -> on_expiry) + executable_statement_dereference (&lease -> on_expiry, + MDL); + + /* Send the release time (should be == cur_time) to the + peer. */ + lease -> tstp = lease -> ends; + } + + lease -> binding_state = lease -> next_binding_state; +} + /* Copy the contents of one lease into another, correctly maintaining reference counts. */ int lease_copy (struct lease **lp, @@ -1242,6 +1190,8 @@ int lease_copy (struct lease **lp, 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; @@ -1252,8 +1202,6 @@ void release_lease (lease, packet) 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) { @@ -1272,21 +1220,26 @@ void release_lease (lease, packet) 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); } } @@ -1299,7 +1252,6 @@ void abandon_lease (lease, message) { struct lease *lt = (struct lease *)0; - lease -> flags |= ABANDONED_LEASE; if (!lease_copy (<, lease, MDL)) return; @@ -1312,8 +1264,9 @@ void abandon_lease (lease, message) /* 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; @@ -1324,7 +1277,7 @@ void abandon_lease (lease, message) 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); } @@ -1349,6 +1302,15 @@ void dissociate_lease (lease) /* 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) @@ -1358,7 +1320,7 @@ void dissociate_lease (lease) 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); } @@ -1367,72 +1329,75 @@ void pool_timer (vpool) 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); - } +#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; - /* If there's an on_release event, blow it away. */ - if (lease -> on_release) - executable_statement_dereference (&lease -> on_release, - MDL); + 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. + lease_reference (&lease, *(lptr [i]), MDL); - 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. + while (lease) { + /* Remember the next lease in the list. */ + if (next) + lease_dereference (&next, MDL); + if (lease -> next) + lease_reference (&next, lease -> next, MDL); - 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 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 (!commit_leases ()) { - log_error ("Error committing after writing lease %s", - piaddr (lease -> ip_addr)); - } -#if defined (FAILOVER_PROTOCOL) - if (lease -> flags & PEER_IS_OWNER) - pool -> peer_leases++; - else - pool -> local_leases++; -#endif + if (next) + lease_dereference (&next, MDL); + if (lease) + lease_dereference (&lease, MDL); } - 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_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... */ @@ -1618,6 +1583,7 @@ void write_leases () struct hash_bucket *hb; int i; int num_written; + struct lease **lptr [5]; /* Write all the dynamically-created group declarations. */ if (group_name_hash) { @@ -1682,18 +1648,25 @@ void write_leases () /* 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 ()) @@ -1712,6 +1685,7 @@ void expire_all_pools () 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. */ @@ -1721,21 +1695,29 @@ void expire_all_pools () #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 } @@ -1748,6 +1730,8 @@ void dump_subnets () 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) { @@ -1757,14 +1741,20 @@ void dump_subnets () } 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); + } } + } } } diff --git a/server/omapi.c b/server/omapi.c index 9938668b..c49660a3 100644 --- a/server/omapi.c +++ b/server/omapi.c @@ -50,7 +50,7 @@ #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" @@ -179,27 +179,21 @@ isc_result_t dhcp_lease_set_value (omapi_object_t *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; + 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; - 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 + if (bar < 1 || bar > FTS_BOOTP) return ISC_R_INVALIDARG; - - foo = lease -> flags; - if (bar) - lease -> flags |= ABANDONED_LEASE; - else - lease -> flags &= ~ABANDONED_LEASE; - if (foo != lease -> flags) - return ISC_R_SUCCESS; + 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; } @@ -226,14 +220,9 @@ isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id, return ISC_R_INVALIDARG; lease = (struct lease *)h; - if (!omapi_ds_strcmp (name, "abandoned")) + if (!omapi_ds_strcmp (name, "state")) return omapi_make_int_value (value, name, - (lease -> flags & - ABANDONED_LEASE) ? 1 : 0, MDL); - else if (!omapi_ds_strcmp (name, "bootpp")) - return omapi_make_int_value (value, name, - (lease -> flags & - BOOTP_LEASE) ? 1 : 0, MDL); + (int)lease -> binding_state, MDL); else if (!omapi_ds_strcmp (name, "ip-address")) return omapi_make_const_value (value, name, lease -> ip_addr.iabuf, @@ -362,7 +351,7 @@ isc_result_t dhcp_lease_signal_handler (omapi_object_t *h, 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; @@ -395,26 +384,13 @@ isc_result_t dhcp_lease_stuff_values (omapi_object_t *c, /* Write out all the values. */ - status = omapi_connection_put_name (c, "abandoned"); + 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, (lease -> flags & - ABANDONED_LEASE) ? 1U : 0U); - if (status != ISC_R_SUCCESS) - return status; - - status = omapi_connection_put_name (c, "bootpp"); - if (status != ISC_R_SUCCESS) - return status; - status = omapi_connection_put_uint32 (c, sizeof (int)); - if (status != ISC_R_SUCCESS) - return status; - status = omapi_connection_put_uint32 (c, ((unsigned) - ((lease -> flags & - BOOTP_LEASE) ? 1 : 0))); + status = omapi_connection_put_uint32 (c, lease -> binding_state); if (status != ISC_R_SUCCESS) return status; diff --git a/server/stables.c b/server/stables.c index 65cc3619..eca393f8 100644 --- a/server/stables.c +++ b/server/stables.c @@ -43,7 +43,7 @@ #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" @@ -176,6 +176,12 @@ const char *dhcp_flink_state_names [] = { }; #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 },