From: Florian Obser Subject: dhcp6leased(8): Set pltime to 0 when upstream interface goes down. To: tech Date: Tue, 24 Dec 2024 13:10:04 +0100 In case of a flash-renumbering event we configure new prefixes with a pltime > 0. Clients should form new addresses and prefer those. Reported & fix tested by Tamas (cstamas at cstamas.hu), thanks! OK? (We can do better here, for example remove the old prefix when we get a new one. That's more complicated to implement and I was short and time and this fixes the issue for now. I also want to double check what the current thinking in the IETF is wrt. flash renumbering.) diff --git engine.c engine.c index 58acebb65b7..887ef551bfc 100644 --- engine.c +++ engine.c @@ -135,6 +135,7 @@ void request_dhcp_discover(struct dhcp6leased_iface *); void request_dhcp_request(struct dhcp6leased_iface *); void configure_interfaces(struct dhcp6leased_iface *); void deconfigure_interfaces(struct dhcp6leased_iface *); +void deprecate_interfaces(struct dhcp6leased_iface *); int prefixcmp(struct prefix *, struct prefix *, int); void send_reconfigure_interface(struct iface_pd_conf *, struct prefix *, enum reconfigure_action); @@ -1049,8 +1050,19 @@ state_transition(struct dhcp6leased_iface *iface, enum if_state new_state) switch (new_state) { case IF_DOWN: + switch (old_state) { + case IF_RENEWING: + case IF_REBINDING: + case IF_REBOOTING: + case IF_BOUND: + deprecate_interfaces(iface); + break; + default: + break; + } /* - * Nothing to do until iface comes up. IP addresses will expire. + * Nothing else to do until iface comes up. + * IP addresses will expire. */ iface->timo.tv_sec = -1; break; @@ -1387,6 +1399,58 @@ deconfigure_interfaces(struct dhcp6leased_iface *iface) memset(iface->pds, 0, sizeof(iface->pds)); } +void +deprecate_interfaces(struct dhcp6leased_iface *iface) +{ + struct iface_conf *iface_conf; + struct iface_ia_conf *ia_conf; + struct iface_pd_conf *pd_conf; + struct timespec now, diff; + uint32_t i; + char ntopbuf[INET6_ADDRSTRLEN]; + char ifnamebuf[IF_NAMESIZE], *if_name; + + + if ((if_name = if_indextoname(iface->if_index, ifnamebuf)) == NULL) { + log_debug("%s: unknown interface %d", __func__, + iface->if_index); + return; + } + if ((iface_conf = find_iface_conf(&engine_conf->iface_list, if_name)) + == NULL) { + log_debug("%s: no interface configuration for %d", __func__, + iface->if_index); + return; + } + + for (i = 0; i < iface_conf->ia_count; i++) { + struct prefix *pd = &iface->pds[i]; + + log_info("%s went down, deprecating prefix delegation #%d %s/%d" + " from server %s", if_name, i, inet_ntop(AF_INET6, + &pd->prefix, ntopbuf, INET6_ADDRSTRLEN), pd->prefix_len, + dhcp_duid2str(iface->serverid_len, iface->serverid)); + } + + clock_gettime(CLOCK_MONOTONIC, &now); + timespecsub(&now, &iface->request_time, &diff); + + SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) { + struct prefix *pd = &iface->pds[ia_conf->id]; + + if (pd->vltime > diff.tv_sec) + pd->vltime -= diff.tv_sec; + else + pd->vltime = 0; + + pd->pltime = 0; + + SIMPLEQ_FOREACH(pd_conf, &ia_conf->iface_pd_list, entry) { + send_reconfigure_interface(pd_conf, pd, CONFIGURE); + } + } +} + int prefixcmp(struct prefix *a, struct prefix *b, int count) { -- In my defence, I have been left unsupervised.