Mercurial > hg > dhcpcd
changeset 961:1cd8de49352c draft
Sort interfaces according to preference and pass this to dhcpcd-run-hooks so we can prefer configs.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Tue, 09 Sep 2008 17:07:48 +0000 |
| parents | 2bf1fef43ace |
| children | 8cb8068f0275 |
| files | Makefile configure.c dhcpcd-run-hooks.in dhcpcd.c dhcpcd.h if-bsd.c if-pref.c if-pref.h net.c |
| diffstat | 9 files changed, 222 insertions(+), 40 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Tue Sep 09 15:36:50 2008 +0000 +++ b/Makefile Tue Sep 09 17:07:48 2008 +0000 @@ -4,7 +4,7 @@ PROG= dhcpcd SRCS= arp.c bind.c common.c control.c dhcp.c dhcpcd.c duid.c eloop.c -SRCS+= if-options.c ipv4ll.c net.c signals.c +SRCS+= if-options.c if-pref.c ipv4ll.c net.c signals.c SRCS+= configure.c SRCS+= ${SRC_IF} ${SRC_PF}
--- a/configure.c Tue Sep 09 15:36:50 2008 +0000 +++ b/configure.c Tue Sep 09 17:07:48 2008 +0000 @@ -43,6 +43,7 @@ #include "configure.h" #include "dhcpf.h" #include "if-options.h" +#include "if-pref.h" #include "net.h" #include "signals.h" @@ -83,17 +84,18 @@ { char *const argv[2] = { UNCONST(iface->state->options->script), NULL }; char **env = NULL, **ep; - char *path; - ssize_t e, elen; + char *path, *p; + ssize_t e, elen, l; pid_t pid; int status = 0; const struct if_options *ifo = iface->state->options; + const struct interface *ifp; syslog(LOG_DEBUG, "%s: executing `%s', reason %s", iface->name, argv[0], reason); /* Make our env */ - elen = 5; + elen = 6; env = xmalloc(sizeof(char *) * (elen + 1)); path = getenv("PATH"); if (path) { @@ -113,6 +115,21 @@ snprintf(env[3], e, "pid=%d", getpid()); env[4] = xmalloc(e); snprintf(env[4], e, "metric=%d", iface->metric); + l = e = strlen("interface_order="); + for (ifp = ifaces; ifp; ifp = ifp->next) + e += strlen(ifp->name) + 1; + p = env[5] = xmalloc(e); + strlcpy(p, "interface_order=", e); + e -= l; + p += l; + for (ifp = ifaces; ifp; ifp = ifp->next) { + l = strlcpy(p, ifp->name, e); + p += l; + e -= l; + *p++ = ' '; + e--; + } + *--p = '\0'; if (iface->state->old) { e = configure_env(NULL, NULL, iface->state->old, ifo); if (e > 0) { @@ -326,6 +343,10 @@ struct in_addr gate; #endif + /* As we are now adjusting an interface, we need to ensure + * we have them in the right order for routing and configuration. */ + sort_interfaces(); + /* Grab our IP config */ if (dhcp) { addr.s_addr = dhcp->yiaddr;
--- a/dhcpcd-run-hooks.in Tue Sep 09 15:36:50 2008 +0000 +++ b/dhcpcd-run-hooks.in Tue Sep 09 17:07:48 2008 +0000 @@ -25,15 +25,26 @@ } # List interface config files in a dir -# We may wish to control the order at some point rather than just lexical +# If dhcpcd is running as a single instance then it will have a list of +# interfaces in the preferred order. +# Otherwise we just use what we have. list_interfaces() { - local x= interfaces= + local i= x= ifaces= + for i in ${interface_order}; do + [ -e "$1"/${i} ] && ifaces="${ifaces}${ifaces:+ }${i}" + done for x in "$1"/*; do [ -e "${x}" ] || continue - interfaces="${interfaces}${interfaces:+ }${x##*/}" + for i in ${interface_order}; do + if [ ${i} = "${x##*/}" ]; then + unset x + break + fi + done + [ -n "${x}" ] && ifaces="${ifaces}${ifaces:+ }${x##*/}" done - echo "${interfaces}" + echo "${ifaces}" } # We normally use sed to extract values using a key from a list of files
--- a/dhcpcd.c Tue Sep 09 15:36:50 2008 +0000 +++ b/dhcpcd.c Tue Sep 09 17:07:48 2008 +0000 @@ -57,6 +57,7 @@ #include "duid.h" #include "eloop.h" #include "if-options.h" +#include "if-pref.h" #include "ipv4ll.h" #include "net.h" #include "signals.h" @@ -66,12 +67,13 @@ int options = 0; int pidfd = -1; +struct interface *ifaces = NULL; + static char **ifv = NULL; static int ifc = 0; static int linkfd = -1; static char *cffile = NULL; static char *pidfile; -static struct interface *ifaces = NULL; struct dhcp_op { uint8_t value; @@ -329,7 +331,7 @@ delete_timeout(NULL, iface); drop_config(iface, "EXPIRE"); iface->state->interval = 0; - if (iface->state->carrier != LINK_DOWN) { + if (iface->carrier != LINK_DOWN) { if (ll) start_interface(iface); else @@ -599,16 +601,16 @@ syslog(LOG_ERR, "carrier_status: %m"); break; case 0: - if (iface->state->carrier != LINK_DOWN) { - iface->state->carrier = LINK_DOWN; + if (iface->carrier != LINK_DOWN) { + iface->carrier = LINK_DOWN; syslog(LOG_INFO, "%s: carrier lost", iface->name); close_sockets(iface); delete_timeouts(iface, start_expire, NULL); } break; default: - if (iface->state->carrier != LINK_UP) { - iface->state->carrier = LINK_UP; + if (iface->carrier != LINK_UP) { + iface->carrier = LINK_UP; syslog(LOG_INFO, "%s: carrier acquired", iface->name); start_interface(iface); } @@ -657,7 +659,7 @@ { struct if_options *ifo = iface->state->options; - if (ifo->options & DHCPCD_LINK && iface->state->carrier == LINK_DOWN) { + if (ifo->options & DHCPCD_LINK && iface->carrier == LINK_DOWN) { syslog(LOG_INFO, "%s: waiting for carrier", iface->name); return; } @@ -690,6 +692,11 @@ { struct interface *iface = arg; + if (iface->carrier == LINK_DOWN) { + syslog(LOG_INFO, "%s: waiting for carrier", iface->name); + return; + } + iface->start_uptime = uptime(); if (!iface->state->lease.addr.s_addr) start_discover(iface); @@ -763,26 +770,19 @@ ifs->nakoff = 1; configure_interface(iface, argc, argv); - if (!(options & DHCPCD_TEST)) - run_script(iface, "PREINIT"); - if (ifs->options->options & DHCPCD_LINK) { switch (carrier_status(iface->name)) { case 0: - ifs->carrier = LINK_DOWN; + iface->carrier = LINK_DOWN; break; case 1: - ifs->carrier = LINK_UP; + iface->carrier = LINK_UP; break; default: - ifs->carrier = LINK_UNKNOWN; + iface->carrier = LINK_UNKNOWN; } - } - - if (ifs->carrier == LINK_DOWN) - syslog(LOG_INFO, "%s: waiting for carrier", iface->name); - else - start_interface(iface); + } else + iface->carrier = LINK_UNKNOWN; } static void @@ -812,6 +812,8 @@ if (ifn) continue; init_state(ifp, 2, UNCONST(argv)); + run_script(ifp, "PREINIT"); + start_interface(ifp); if (ifl) ifl->next = ifp; else @@ -859,7 +861,6 @@ case SIGALRM: syslog(LOG_INFO, "received SIGALRM, rebinding lease"); do_reboot = 1; - break; case SIGHUP: syslog(LOG_INFO, "received SIGHUP, releasing lease"); do_release = 1; @@ -871,9 +872,13 @@ return; } - for (iface = ifaces; iface; iface = iface->next) { - if (!iface->state) - continue; + /* As drop_config could re-arrange the order, we do it like this. */ + for (;;) { + for (iface = ifaces; iface; iface = iface->next) + if (iface->state && iface->state->new) + break; + if (!iface) + break; if (do_reboot) start_reboot(iface); else { @@ -940,6 +945,7 @@ start_reboot(ifp); } } + sort_interfaces(); return 0; } @@ -954,12 +960,15 @@ } if (!ifn) { init_state(ifp, argc, argv); + run_script(ifp, "PREINIT"); + start_interface(ifp); if (ifl) ifl->next = ifp; else ifaces = ifp; } } + sort_interfaces(); } return 0; } @@ -1165,14 +1174,21 @@ ifc = argc - optind; ifv = argv + optind; ifaces = discover_interfaces(ifc, ifv); - for (iface = ifaces; iface; iface = iface->next) - init_state(iface, argc, argv); if (!ifaces && ifc == 1) { syslog(LOG_ERR, "interface `%s' does not exist", ifv[0]); exit(EXIT_FAILURE); } if (options & DHCPCD_BACKGROUND) daemonise(); + for (iface = ifaces; iface; iface = iface->next) + init_state(iface, argc, argv); + sort_interfaces(); + if (!(options & DHCPCD_TEST)) { + for (iface = ifaces; iface; iface = iface->next) { + run_script(iface, "PREINIT"); + start_interface(iface); + } + } start_eloop(); /* NOTREACHED */ }
--- a/dhcpcd.h Tue Sep 09 15:36:50 2008 +0000 +++ b/dhcpcd.h Tue Sep 09 17:07:48 2008 +0000 @@ -67,7 +67,6 @@ time_t nakoff; uint32_t xid; int socket; - int carrier; int probes; int claims; int conflicts; @@ -84,6 +83,7 @@ unsigned char hwaddr[HWADDR_LEN]; size_t hwlen; int metric; + int carrier; int arpable; int raw_fd; @@ -106,6 +106,7 @@ extern int pidfd; extern int options; +extern struct interface *ifaces; int handle_args(int, char **); void handle_exit_timeout(void *);
--- a/if-bsd.c Tue Sep 09 15:36:50 2008 +0000 +++ b/if-bsd.c Tue Sep 09 17:07:48 2008 +0000 @@ -248,8 +248,8 @@ struct interface * discover_interfaces(int argc, char * const *argv) { - struct interface *ifaces = NULL; + struct interface *ifs = NULL; - do_interface(NULL, &ifaces, argc, argv, NULL, NULL, 2); - return ifaces; + do_interface(NULL, &ifs, argc, argv, NULL, NULL, 2); + return ifs; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/if-pref.c Tue Sep 09 17:07:48 2008 +0000 @@ -0,0 +1,99 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples <roy@marples.name> + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" +#include "dhcpcd.h" +#include "if-pref.h" + +/* Interface comparer for working out ordering. */ +static int +ifcmp(struct interface *si, struct interface *ti) +{ + int sill, till; + + /* If one has a lease and the other not, it takes precedence. */ + if (si->state->new && !ti->state->new) + return -1; + if (!si->state->new && ti->state->new) + return 1; + /* If we are either, they neither have a lease, or they both have. + * We need to check for IPv4LL and make it non-preferred. */ + if (si->state->new) { + sill = IN_LINKLOCAL(htonl(si->state->new->yiaddr)); + till = IN_LINKLOCAL(htonl(ti->state->new->yiaddr)); + if (!sill && till) + return -1; + if (sill && !till) + return 1; + } + /* Then carrier status. */ + if (si->carrier > ti->carrier) + return -1; + if (si->carrier < ti->carrier) + return 1; + /* Finally, metric */ + if (si->metric < ti->metric) + return -1; + if (si->metric > ti->metric) + return 1; + return 0; +} + +/* Sort the interfaces into a preferred order - best first, worst last. */ +void +sort_interfaces(void) +{ + struct interface *sorted, *ifp, *ifn, *ift; + + if (!ifaces || !ifaces->next) + return; + sorted = ifaces; + ifaces = ifaces->next; + sorted->next = NULL; + for (ifp = ifaces; ifp && (ifn = ifp->next, 1); ifp = ifn) { + /* Are we the new head? */ + if (ifcmp(ifp, sorted) == -1) { + ifp->next = sorted; + sorted = ifp; + continue; + } + /* Do we fit in the middle? */ + for (ift = sorted; ift->next; ift = ift->next) { + if (ifcmp(ifp, ift->next) == -1) { + ifp->next = ift->next; + ift->next = ifp; + break; + } + } + /* We must be at the end */ + if (!ift->next) { + ift->next = ifp; + ifp->next = NULL; + } + } + ifaces = sorted; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/if-pref.h Tue Sep 09 17:07:48 2008 +0000 @@ -0,0 +1,34 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples <roy@marples.name> + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IF_PREF_H +#define IF_PREF_H + +#include "dhcpcd.h" + +void sort_interfaces(void); +#endif
--- a/net.c Tue Sep 09 15:36:50 2008 +0000 +++ b/net.c Tue Sep 09 17:07:48 2008 +0000 @@ -315,7 +315,7 @@ int do_interface(const char *ifname, - _unused struct interface **ifaces, + _unused struct interface **ifs, _unused int argc, _unused char * const *argv, struct in_addr *addr, struct in_addr *net, int act) { @@ -385,7 +385,7 @@ #ifdef AF_LINK /* Interface discovery for BSD's */ if (act == 2 && ifr->ifr_addr.sa_family == AF_LINK) { - for (ifp = *ifaces; ifp; ifp = ifp->next) { + for (ifp = *ifs; ifp; ifp = ifp->next) { ifl = ifp; if (strcmp(ifp->name, ifr->ifr_name) == 0) break; @@ -405,7 +405,7 @@ if (ifl) ifp = ifl->next = ifn; else - ifp = *ifaces = ifn; + ifp = *ifs = ifn; sdl = xmalloc(ifr->ifr_addr.sa_len); memcpy(sdl, &ifr->ifr_addr, ifr->ifr_addr.sa_len); ifp->hwlen = sdl->sdl_alen;
