Mercurial > hg > dhcpcd
changeset 5040:c44b319ae036 draft
inet6: Ensure expired routers are cleared after a carrier loss
When we lose carrier, mark all RAs as willexpire and add
the timeout to expire to it's own queue.
On receipt of a matching RA, clear the willexpire flag.
When the above timeout occours, set doexpire on all
RA's with withexpire and then call the general expirera function.
This is needed because expirera can be called at any point.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Thu, 06 Feb 2020 12:54:11 +0000 |
| parents | 1e35e845790a |
| children | dac9291f82f0 |
| files | src/ipv6nd.c src/ipv6nd.h |
| diffstat | 2 files changed, 37 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ipv6nd.c Thu Feb 06 12:50:31 2020 +0000 +++ b/src/ipv6nd.c Thu Feb 06 12:54:11 2020 +0000 @@ -391,10 +391,8 @@ if (state->rsprobes++ < MAX_RTR_SOLICITATIONS) eloop_timeout_add_sec(ifp->ctx->eloop, RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp); - else { + else logwarnx("%s: no IPv6 Routers available", ifp->name); - ipv6nd_drop(ifp); - } } #ifdef ND6_ADVERTISE @@ -554,19 +552,13 @@ { struct interface *ifp = arg; struct ra *rap; - struct ipv6_addr *ia; - struct timespec now = { .tv_sec = 1 }; if (ifp->ctx->ra_routers == NULL) return; TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { - if (rap->iface != ifp) - continue; - rap->acquired = now; - TAILQ_FOREACH(ia, &rap->addrs, next) { - ia->acquired = now; - } + if (rap->iface == ifp && rap->willexpire) + rap->doexpire = true; } ipv6nd_expirera(ifp); } @@ -574,9 +566,17 @@ void ipv6nd_startexpire(struct interface *ifp) { + struct ra *rap; - eloop_timeout_add_sec(ifp->ctx->eloop, RTR_CARRIER_EXPIRE, - ipv6nd_expire, ifp); + if (ifp->ctx->ra_routers == NULL) + return; + + TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { + if (rap->iface == ifp) + rap->willexpire = true; + } + eloop_q_timeout_add_sec(ifp->ctx->eloop, ELOOP_IPV6RA_EXPIRE, + RTR_CARRIER_EXPIRE, ipv6nd_expire, ifp); } static int @@ -607,10 +607,12 @@ while ((ra1 = TAILQ_FIRST(ctx->ra_routers)) != NULL) { TAILQ_REMOVE(ctx->ra_routers, ra1, next); TAILQ_FOREACH(ra2, &sorted_routers, next) { - if (ra1->iface->metric < ra2->iface->metric) + if (ra1->iface->metric > ra2->iface->metric) continue; if (ra1->expired && !ra2->expired) continue; + if (ra1->willexpire && !ra2->willexpire) + continue; if (ra1->lifetime == 0 && ra2->lifetime != 0) continue; if (!ra1->isreachable && ra2->reachable) @@ -1137,7 +1139,7 @@ rap->retrans = ntohl(nd_ra->nd_ra_retransmit); else rap->retrans = RETRANS_TIMER; - rap->expired = false; + rap->expired = rap->willexpire = rap->doexpire = false; rap->hasdns = false; rap->isreachable = true; has_address = false; @@ -1416,7 +1418,8 @@ if (ifp->ctx->ra_routers) { TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) - if (rap->iface == ifp && !rap->expired && + if (rap->iface == ifp && + !rap->expired && (!lifetime ||rap->lifetime)) return true; } @@ -1424,15 +1427,16 @@ } bool -ipv6nd_hasradhcp(const struct interface *ifp) +ipv6nd_hasradhcp(const struct interface *ifp, bool managed) { const struct ra *rap; if (ifp->ctx->ra_routers) { TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { if (rap->iface == ifp && - !rap->expired && - (rap->flags &(ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER))) + !rap->expired && !rap->willexpire && + ((managed && rap->flags & ND_RA_FLAG_MANAGED) || + (!managed && rap->flags & ND_RA_FLAG_OTHER))) return true; } } @@ -1622,7 +1626,7 @@ if (rap->lifetime) { elapsed = (uint32_t)eloop_timespec_diff(&now, &rap->acquired, NULL); - if (elapsed > rap->lifetime) { + if (elapsed > rap->lifetime || rap->doexpire) { if (!rap->expired) { logwarnx("%s: %s: router expired", ifp->name, rap->sfrom); @@ -1643,13 +1647,15 @@ TAILQ_FOREACH(ia, &rap->addrs, next) { if (ia->prefix_vltime == 0) continue; - if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) { + if (ia->prefix_vltime == ND6_INFINITE_LIFETIME && + !rap->doexpire) + { valid = true; continue; } elapsed = (uint32_t)eloop_timespec_diff(&now, &ia->acquired, NULL); - if (elapsed > ia->prefix_vltime) { + if (elapsed > ia->prefix_vltime || rap->doexpire) { if (ia->flags & IPV6_AF_ADDED) { logwarnx("%s: expired %s %s", ia->iface->name, @@ -1720,6 +1726,10 @@ if (ltime == 0) continue; + if (rap->doexpire) { + expired = true; + continue; + } if (ltime == ND6_INFINITE_LIFETIME) { valid = true; continue; @@ -1750,7 +1760,8 @@ eloop_timeout_add_sec(ifp->ctx->eloop, next, ipv6nd_expirera, ifp); if (expired) { - logwarnx("%s: part of Router Advertisement expired", ifp->name); + logwarnx("%s: part of a Router Advertisement expired", + ifp->name); rt_build(ifp->ctx, AF_INET6); script_runreason(ifp, "ROUTERADVERT"); }
--- a/src/ipv6nd.h Thu Feb 06 12:50:31 2020 +0000 +++ b/src/ipv6nd.h Thu Feb 06 12:54:11 2020 +0000 @@ -54,6 +54,8 @@ struct ipv6_addrhead addrs; bool hasdns; bool expired; + bool willexpire; + bool doexpire; bool isreachable; }; @@ -114,7 +116,7 @@ void ipv6nd_expirera(void *arg); bool ipv6nd_hasralifetime(const struct interface *, bool); #define ipv6nd_hasra(i) ipv6nd_hasralifetime((i), false) -bool ipv6nd_hasradhcp(const struct interface *); +bool ipv6nd_hasradhcp(const struct interface *, bool); void ipv6nd_handleifa(int, struct ipv6_addr *, pid_t); int ipv6nd_dadcompleted(const struct interface *); void ipv6nd_advertise(struct ipv6_addr *);
