From: Roy Marples Date: Mon, 15 Sep 2008 15:23:46 +0000 (+0000) Subject: Reboot off the last lease and use the last lease if not expired and user has asked... X-Git-Tag: v5.0.0~251 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a2a9a498da4327ecf2fdec8560bb9a3557490fa9;p=thirdparty%2Fdhcpcd.git Reboot off the last lease and use the last lease if not expired and user has asked for it. Also, add a reboot timeout toggle (default 10 seconds). --- diff --git a/dhcp.c b/dhcp.c index 7b2993e0..0aa13fa6 100644 --- a/dhcp.c +++ b/dhcp.c @@ -1254,7 +1254,6 @@ get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp) { time_t t; - lease->frominfo = 0; lease->addr.s_addr = dhcp->yiaddr; if (get_option_addr(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1) lease->net.s_addr = get_netmask(dhcp->yiaddr); diff --git a/dhcpcd.8.in b/dhcpcd.8.in index f0ae80a5..4905a88c 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 11, 2008 +.Dd September 15, 2008 .Dt DHCPCD 8 SMM .Sh NAME .Nm dhcpcd @@ -42,6 +42,7 @@ .Op Fl t , -timeout Ar seconds .Op Fl u , -userclass Ar class .Op Fl v , -vendor Ar code , Ar value +.Op Fl y , -reboot Ar seconds .Op Fl z , -allowinterfaces Ar pattern .Op Fl C , -nohook Ar hook .Op Fl F , -fqdn Ar FQDN @@ -304,6 +305,14 @@ to deconfigure the and exit. .Nm then waits until this process has exited. +.It Fl y , -reboot Ar seconds +Allow +.Ar reboot +seconds before moving to the discover phase if we have an old lease to use. +The default is 10 seconds. +A setting if 0 seconds causes +.Nm +to skip the reboot phase and go straight into discover. .It Fl D , -duid Generate an .Li RFC 4361 diff --git a/dhcpcd.c b/dhcpcd.c index 53b95f99..47ef462a 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -127,7 +127,7 @@ read_pid(void) static void usage(void) { - printf("usage: "PACKAGE" [-dknpqxADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n" + printf("usage: "PACKAGE" [-dknpqxyADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n" " [-i classID ] [-l leasetime] [-m metric] [-o option] [-r ipaddr]\n" " [-s ipaddr] [-t timeout] [-u userclass] [-F none|ptr|both]\n" " [-I clientID] [-C hookscript] [-Q option] [-X ipaddr] \n"); @@ -326,7 +326,7 @@ start_rebind(void *arg) syslog(LOG_ERR, "%s: failed to renew, attmepting to rebind", iface->name); - iface->state->state = DHS_REBINDING; + iface->state->state = DHS_REBIND; delete_timeout(send_renew, iface); iface->state->lease.server.s_addr = 0; send_rebind(iface); @@ -336,14 +336,20 @@ void start_expire(void *arg) { struct interface *iface = arg; - int ll = IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)); + + if (iface->addr.s_addr == 0) { + /* We failed to reboot, so enter discovery. */ + iface->state->interval = 0; + start_discover(iface); + return; + } syslog(LOG_ERR, "%s: lease expired", iface->name); delete_timeout(NULL, iface); drop_config(iface, "EXPIRE"); iface->state->interval = 0; if (iface->carrier != LINK_DOWN) { - if (ll) + if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr))) start_interface(iface); else start_ipv4ll(iface); @@ -454,7 +460,8 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp) } } - if (type == DHCP_OFFER && state->state == DHS_DISCOVERING) { + if (type == DHCP_OFFER && state->state == DHS_DISCOVER) { + lease->frominfo = 0; lease->addr.s_addr = dhcp->yiaddr; get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID); log_dhcp(LOG_INFO, "offered", iface, dhcp); @@ -477,7 +484,6 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp) * then we can't ARP for duplicate detection. */ addr.s_addr = state->offer->yiaddr; if (!has_address(iface->name, &addr, NULL)) { - state->state = DHS_PROBING; state->claims = 0; state->probes = 0; state->conflicts = 0; @@ -485,7 +491,7 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp) return; } } - state->state = DHS_REQUESTING; + state->state = DHS_REQUEST; send_request(iface); return; } @@ -509,6 +515,7 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp) *dhcpp = NULL; /* Delete all timeouts for this interface. */ delete_timeout(NULL, iface); + lease->frominfo = 0; bind_interface(iface); } @@ -636,7 +643,7 @@ start_discover(void *arg) struct interface *iface = arg; struct if_options *ifo = iface->state->options; - iface->state->state = DHS_DISCOVERING; + iface->state->state = DHS_DISCOVER; iface->state->xid = arc4random(); open_sockets(iface); delete_timeout(NULL, iface); @@ -660,12 +667,22 @@ start_renew(void *arg) syslog(LOG_INFO, "%s: renewing lease of %s", iface->name, inet_ntoa(iface->state->lease.addr)); - iface->state->state = DHS_RENEWING; + iface->state->state = DHS_RENEW; iface->state->xid = arc4random(); open_sockets(iface); send_renew(iface); } +static void +start_timeout(void *arg) +{ + struct interface *iface = arg; + + bind_interface(iface); + iface->state->interval = 0; + start_discover(iface); +} + void start_reboot(struct interface *iface) { @@ -675,15 +692,33 @@ start_reboot(struct interface *iface) syslog(LOG_INFO, "%s: waiting for carrier", iface->name); return; } + if (ifo->reboot == 0) { + start_discover(iface); + return; + } + if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr))) { + if (ifo->options & DHCPCD_IPV4LL) { + iface->state->claims = 0; + send_arp_announce(iface); + } else + start_discover(iface); + return; + } syslog(LOG_INFO, "%s: rebinding lease of %s", iface->name, inet_ntoa(iface->state->lease.addr)); - iface->state->state = DHS_REBINDING; + iface->state->state = DHS_REBOOT; iface->state->xid = arc4random(); iface->state->lease.server.s_addr = 0; delete_timeout(NULL, iface); - add_timeout_sec(ifo->timeout, start_expire, iface); + if (ifo->options & DHCPCD_LASTLEASE && iface->state->lease.frominfo) + add_timeout_sec(ifo->reboot, start_timeout, iface); + else + add_timeout_sec(ifo->reboot, start_expire, iface); open_sockets(iface); - send_rebind(iface); + if (ifo->options & DHCPCD_ARP) + send_arp_probe(iface); + else + send_request(iface); } static void @@ -703,6 +738,9 @@ void start_interface(void *arg) { struct interface *iface = arg; + struct stat st; + struct timeval now; + uint32_t l; if (iface->carrier == LINK_DOWN) { syslog(LOG_INFO, "%s: waiting for carrier", iface->name); @@ -710,9 +748,36 @@ start_interface(void *arg) } iface->start_uptime = uptime(); - if (!iface->state->lease.addr.s_addr) + iface->state->offer = read_lease(iface); +/* if (iface->state->offer) { + if (IN_LINKLOCAL(htonl(iface->state->offer->yiaddr))) { + free(iface->state->offer); + iface->state->offer = NULL; + } + } */ + if (iface->state->offer) { + get_lease(&iface->state->lease, iface->state->offer); + iface->state->lease.frominfo = 1; + /* Offset lease times and check expiry */ + if (stat(iface->leasefile, &st) == 0 && + get_option_uint32(&l, iface->state->offer, DHO_LEASETIME) == 0) + { + gettimeofday(&now, NULL); + if ((time_t)l < now.tv_sec - st.st_mtime) { + free(iface->state->offer); + iface->state->offer = NULL; + } else { + l = now.tv_sec - st.st_mtime; + iface->state->lease.leasetime -= l; + iface->state->lease.renewaltime -= l; + iface->state->lease.rebindtime -= l; + } + } + } + if (!iface->state->offer) start_discover(iface); - else if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr))) + else if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)) && + iface->state->options->options & DHCPCD_IPV4LL) start_ipv4ll(iface); else start_reboot(iface); @@ -861,7 +926,7 @@ handle_signal(_unused void *arg) { struct interface *iface, *ifl; int sig = signal_read(); - int do_reboot = 0, do_release = 0; + int do_release = 0; switch (sig) { case SIGINT: @@ -872,15 +937,17 @@ handle_signal(_unused void *arg) break; case SIGALRM: syslog(LOG_INFO, "received SIGALRM, rebinding lease"); - do_reboot = 1; + for (iface = ifaces; iface; iface = iface->next) + start_reboot(iface); + return; case SIGHUP: syslog(LOG_INFO, "received SIGHUP, releasing lease"); do_release = 1; break; default: - syslog (LOG_ERR, - "received signal %d, but don't know what to do with it", - sig); + syslog(LOG_ERR, + "received signal %d, but don't know what to do with it", + sig); return; } @@ -893,14 +960,10 @@ handle_signal(_unused void *arg) ifl = iface; if (!ifl) break; - if (do_reboot) - start_reboot(ifl); - else { - if (do_release) - send_release(ifl); - if (!(ifl->state->options->options & DHCPCD_PERSISTENT)) - drop_config(ifl, do_release ? "RELEASE" : "STOP"); - } + if (do_release) + send_release(ifl); + if (!(ifl->state->options->options & DHCPCD_PERSISTENT)) + drop_config(ifl, do_release ? "RELEASE" : "STOP"); } exit(EXIT_FAILURE); } @@ -1102,6 +1165,8 @@ main(int argc, char **argv) unlink(pidfile); exit(EXIT_FAILURE); } + if (sig == SIGALRM) + exit(EXIT_SUCCESS); /* Spin until it exits */ syslog(LOG_INFO, "waiting for pid %d to exit", pid); ts.tv_sec = 0; diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index a492855d..d7031310 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 11, 2008 +.Dd September 15, 2008 .Dt DHCPCD.CONF 5 SMM .Sh NAME .Nm dhcpcd.conf @@ -124,6 +124,14 @@ It can be a variable to be used in .Xr dhcpcd-run-hooks 8 or the numerical value. You can specify more options seperated by commas, spaces or more option lines. +.Ic reboot Ar seconds +Allow +.Ar reboot +seconds before moving to the discover phase if we have an old lease to use. +The default is 10 seconds. +A setting if 0 seconds causes +.Nm dhcpcd +to skip the reboot phase and go straight into discover. .It Ic require Ar option Requires the .Ar option diff --git a/dhcpcd.h b/dhcpcd.h index 4bfed04f..ea4a37df 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -39,16 +39,14 @@ enum DHS { DHS_INIT, - DHS_DISCOVERING, - DHS_REQUESTING, + DHS_DISCOVER, + DHS_REQUEST, DHS_BOUND, - DHS_RENEWING, - DHS_REBINDING, + DHS_RENEW, + DHS_REBIND, DHS_REBOOT, DHS_RENEW_REQUESTED, - DHS_INIT_IPV4LL, - DHS_PROBING, - DHS_ANNOUNCING + DHS_INIT_IPV4LL }; #define LINK_UP 1 diff --git a/if-options.c b/if-options.c index 7e2d4faa..da16e4c2 100644 --- a/if-options.c +++ b/if-options.c @@ -48,7 +48,7 @@ /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ -#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:Q:TVX:" +#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLO:Q:TVX:Z:" const struct option cf_options[] = { {"background", no_argument, NULL, 'b'}, @@ -70,6 +70,7 @@ const struct option cf_options[] = { {"userclass", required_argument, NULL, 'u'}, {"vendor", required_argument, NULL, 'v'}, {"exit", no_argument, NULL, 'x'}, + {"reboot", required_argument, NULL, 'y'}, {"allowinterfaces", required_argument, NULL, 'z'}, {"noarp", no_argument, NULL, 'A'}, {"nobackground", no_argument, NULL, 'B'}, @@ -382,7 +383,7 @@ parse_option(struct if_options *ifo, int opt, const char *arg) case 't': ifo->timeout = atoint(arg); if (ifo->timeout < 0) { - syslog (LOG_ERR, "timeout must be a positive value"); + syslog(LOG_ERR, "timeout must be a positive value"); return -1; } break; @@ -435,6 +436,13 @@ parse_option(struct if_options *ifo, int opt, const char *arg) ifo->vendor[0] += s + 2; } break; + case 'y': + ifo->reboot = atoint(arg); + if (ifo->reboot < 0) { + syslog(LOG_ERR, "reboot must be a positive value"); + return -1; + } + break; case 'z': /* We only set this if we haven't got any interfaces */ if (!ifaces) @@ -587,6 +595,7 @@ read_config(const char *file, const char *ifname) ifo->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE; ifo->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK; ifo->timeout = DEFAULT_TIMEOUT; + ifo->reboot = DEFAULT_REBOOT; ifo->metric = -1; gethostname(ifo->hostname + 1, sizeof(ifo->hostname)); if (strcmp(ifo->hostname + 1, "(none)") == 0 || diff --git a/if-options.h b/if-options.h index 0559eec0..80f788da 100644 --- a/if-options.h +++ b/if-options.h @@ -40,6 +40,7 @@ #define IF_OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xz:ABC:DEF:GI:KLO:Q:TVX:Z:" #define DEFAULT_TIMEOUT 30 +#define DEFAULT_REBOOT 10 #define DEFAULT_LEASETIME 3600 /* 1 hour */ #define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */ @@ -76,6 +77,7 @@ struct if_options { uint8_t nomask[256 / 8]; uint32_t leasetime; time_t timeout; + time_t reboot; int options; struct in_addr request_address; diff --git a/ipv4ll.c b/ipv4ll.c index 0ae91005..fcd690e2 100644 --- a/ipv4ll.c +++ b/ipv4ll.c @@ -87,11 +87,16 @@ start_ipv4ll(void *arg) } } - syslog(LOG_INFO, "%s: probing for an IPv4LL address", iface->name); - delete_timeout(NULL, iface); - iface->state->state = DHS_PROBING; - free(iface->state->offer); - iface->state->offer = make_ipv4ll_lease(0); + /* We maybe rebooting of an IPv4LL address. */ + if (!iface->state->offer || + !IN_LINKLOCAL(htonl(iface->state->offer->yiaddr))) + { + syslog(LOG_INFO, "%s: probing for an IPv4LL address", iface->name); + delete_timeout(NULL, iface); + free(iface->state->offer); + iface->state->offer = make_ipv4ll_lease(0); + iface->state->lease.frominfo = 0; + } send_arp_probe(iface); } @@ -102,26 +107,25 @@ handle_ipv4ll_failure(void *arg) time_t up; if (iface->state->fail.s_addr == iface->state->lease.addr.s_addr) { - if (iface->state->state == DHS_PROBING) + up = uptime(); + if (iface->state->defend + DEFEND_INTERVAL > up) { drop_config(iface, "EXPIRE"); - else { - up = uptime(); - if (iface->state->defend + DEFEND_INTERVAL > up) { - drop_config(iface, "EXPIRE"); - iface->state->conflicts = -1; - } else { - iface->state->defend = up; - return; - } + iface->state->conflicts = -1; + } else { + iface->state->defend = up; + return; } } close_sockets(iface); + free(iface->state->offer); + iface->state->offer = NULL; if (++iface->state->conflicts > MAX_CONFLICTS) { syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address", iface->name); iface->state->interval = RATE_LIMIT_INTERVAL / 2; start_discover(iface); - } else + } else { add_timeout_sec(PROBE_WAIT, start_ipv4ll, iface); + } }