From: Roy Marples Date: Tue, 21 May 2013 09:24:49 +0000 (+0000) Subject: Don't actually remove unreachable routers and prefixes from the routing table. X-Git-Tag: v5.99.7~52 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=99d2575328ed914f44dda510a35ff22044356263;p=thirdparty%2Fdhcpcd.git Don't actually remove unreachable routers and prefixes from the routing table. Instead we just change the interface if they are reachable via another one. --- diff --git a/ipv6.c b/ipv6.c index 9fb159ea..cae5c96f 100644 --- a/ipv6.c +++ b/ipv6.c @@ -641,12 +641,36 @@ ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr) (IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) && \ IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any)) +static void +ipv6_buildroutes1(struct rt6head *dnr, int expired) +{ + struct rt6 *rt; + struct ra *rap; + struct ipv6_addr *addr; + + TAILQ_FOREACH(rap, &ipv6_routers, next) { + if (rap->expired != expired) + continue; + if (options & DHCPCD_IPV6RA_OWN) { + TAILQ_FOREACH(addr, &rap->addrs, next) { + if (!addr->onlink) + continue; + rt = make_prefix(rap->iface, rap, addr); + if (rt) + TAILQ_INSERT_TAIL(dnr, rt, next); + } + } + rt = make_router(rap); + if (rt) + TAILQ_INSERT_TAIL(dnr, rt, next); + } +} + void ipv6_buildroutes(void) { struct rt6head dnr, *nrs; struct rt6 *rt, *rtn, *or; - struct ra *rap; struct ipv6_addr *addr; const struct interface *ifp; const struct dhcp6_state *d6_state; @@ -656,6 +680,12 @@ ipv6_buildroutes(void) return; TAILQ_INIT(&dnr); + + /* First add reachable routers and their prefixes */ + ipv6_buildroutes1(&dnr, 0); + + /* We have no way of knowing if prefixes added by DHCP are reachable + * or not, so we have to assume they are */ TAILQ_FOREACH(ifp, ifaces, next) { d6_state = D6_CSTATE(ifp); if (d6_state && @@ -671,22 +701,11 @@ ipv6_buildroutes(void) } } } - TAILQ_FOREACH(rap, &ipv6_routers, next) { - if (options & DHCPCD_IPV6RA_OWN) { - TAILQ_FOREACH(addr, &rap->addrs, next) { - if (!addr->onlink) - continue; - rt = make_prefix(rap->iface, rap, addr); - if (rt) - TAILQ_INSERT_TAIL(&dnr, rt, next); - } - } - if (!rap->expired) { - rt = make_router(rap); - if (rt) - TAILQ_INSERT_TAIL(&dnr, rt, next); - } - } + + /* Add our non-reachable routers and prefixes + * Unsure if this is needed, but it's a close match to kernel + * behaviour */ + ipv6_buildroutes1(&dnr, 1); nrs = malloc(sizeof(*nrs)); if (nrs == NULL) { diff --git a/ipv6ns.c b/ipv6ns.c index 5a182f82..a0f23843 100644 --- a/ipv6ns.c +++ b/ipv6ns.c @@ -209,6 +209,7 @@ static void ipv6ns_unreachable(void *arg) { struct ra *rap = arg; + struct timeval tv; /* We could add an unreachable flag and persist the information, * but that is more effort than it's probably worth. */ @@ -217,6 +218,16 @@ ipv6ns_unreachable(void *arg) rap->expired = 1; ipv6_buildroutes(); script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */ + + /* We should still test if it's reachable or not so + * incase it comes back to life and it's preferable. */ + if (rap->reachable) { + ms_to_tv(&tv, rap->reachable); + } else { + tv.tv_sec = REACHABLE_TIME; + tv.tv_usec = 0; + } + eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap); } #ifdef LISTEN_DAD @@ -626,6 +637,13 @@ ipv6ns_handledata(__unused void *arg) } if (is_solicited) { + if (rap->expired) { + rap->expired = 0; + syslog(LOG_INFO, "%s: %s is reachable again", + ifp->name, sfrom); + ipv6_buildroutes(); + script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */ + } rap->nsprobes = 0; if (rap->reachable) { ms_to_tv(&tv, rap->reachable);