On Fri, Mar 17, 2023 at 1:54 AM Christian Marangi <ansuels...@gmail.com> wrote: > > This fix a specific and corner case when the following error and similar > is printed in the log: > > Failed to send to ff02::1%br-lan (Address not available) > > The cause for this was tracked down to the lack of the interface of a > configured LINK-LOCAL IPV6 address resulting in odhcpd_send() always > failing. > > A LINK-LOCAL IPV6 address is assigned only after the interface has > carrier and is set to IFF_RUNNING and require some time for the address > to be assigned due to DAD logic. > > In the case where an interface was just UP, odhcpd RA may fail since the > LINK-LOCAL IPV6 address still needs to be assigned as it still need to > be "trained". From the kernel view this is flagged in the IPV6 interface > address with the flag IFA_F_TENTATIVE, that means the address still > needs to be checked and follow DAD process. > > This is only a transient problem and the DAD process is required only > once till the interface is not set DOWN. > > To handle this, add some check to verify if the address has to be > checked and add an additional bool to flag if the interface have a > LINK-LOCAL assigned. > > Skip sending RA if the interface still doesn't have finished the DAD > process and retry at the next RA. > A notice log is added to track this special case to track problematic > case and even more corner case. > > Logic to check if interface have LINK-LOCAL are: > - When interface is setup, on scanning for the interface ipv6 address > check if at least one address is NOT in IFA_F_TENTATIVE state. > - With interface already up but with still no LINK-LOCAL react on the > RTM_NEWADDR event and set LINK-LOCAL if the addrs added by the event > is a LINK-LOCAL reflecting that the interface finally ended the DAD > process and have a correct address. > > Signed-off-by: Christian Marangi <ansuels...@gmail.com> > --- > src/config.c | 9 +++++++++ > src/netlink.c | 11 ++++++++++- > src/odhcpd.h | 2 ++ > src/router.c | 6 ++++++ > 4 files changed, 27 insertions(+), 1 deletion(-) > > diff --git a/src/config.c b/src/config.c > index 30da879..ee7219f 100644 > --- a/src/config.c > +++ b/src/config.c > @@ -594,6 +594,15 @@ int config_parse_interface(void *data, size_t len, const > char *name, bool overwr > if (len > 0) > iface->addr6_len = len; > > + for (size_t i = 0; i < iface->addr6_len; i++) { > + struct odhcpd_ipaddr *addr = &iface->addr6[i]; > + > + if (!addr->tentative) { > + iface->have_link_local = true; > + break; > + } > + } > + > len = netlink_get_interface_addrs(iface->ifindex, > false, &iface->addr4); > if (len > 0) > diff --git a/src/netlink.c b/src/netlink.c > index 4a352a6..0a2da03 100644 > --- a/src/netlink.c > +++ b/src/netlink.c > @@ -386,7 +386,7 @@ static int handle_rtm_addr(struct nlmsghdr *hdr, bool add) > > nla_memcpy(&event_info.addr, nla[IFA_ADDRESS], > sizeof(event_info.addr)); > > - if (IN6_IS_ADDR_LINKLOCAL(&event_info.addr) || > IN6_IS_ADDR_MULTICAST(&event_info.addr)) > + if (IN6_IS_ADDR_MULTICAST(&event_info.addr)) > return NL_SKIP; > > inet_ntop(AF_INET6, &event_info.addr, buf, sizeof(buf)); > @@ -395,6 +395,11 @@ static int handle_rtm_addr(struct nlmsghdr *hdr, bool > add) > if (iface->ifindex != (int)ifa->ifa_index) > continue; > > + if (add && IN6_IS_ADDR_LINKLOCAL(&event_info.addr)) { > + iface->have_link_local = true; > + return NL_SKIP; > + } > + > syslog(LOG_DEBUG, "Netlink %s %s on %s", add ? > "newaddr" : "deladdr", > buf, iface->name); > > @@ -625,6 +630,10 @@ static int cb_addr_valid(struct nl_msg *msg, void *arg) > if (ifa->ifa_flags & IFA_F_DEPRECATED) > addrs[ctxt->ret].preferred = 0; > > + if (ifa->ifa_family == AF_INET6 && > + ifa->ifa_flags & IFA_F_TENTATIVE) > + addrs[ctxt->ret].tentative = true; > + > ctxt->ret++; > *(ctxt->addrs) = addrs; > > diff --git a/src/odhcpd.h b/src/odhcpd.h > index d829033..0550bc2 100644 > --- a/src/odhcpd.h > +++ b/src/odhcpd.h > @@ -131,6 +131,7 @@ struct odhcpd_ipaddr { > struct { > uint8_t dprefix; > uint8_t invalid_advertisements; > + bool tentative; > }; > > /* ipv4 only */ > @@ -300,6 +301,7 @@ struct interface { > bool ra_useleasetime; > bool ra_dns; > bool no_dynamic_dhcp; > + bool have_link_local; > uint8_t pio_filter_length; > struct in6_addr pio_filter_addr; > int default_router; > diff --git a/src/router.c b/src/router.c > index 7e66e3c..5c518b1 100644 > --- a/src/router.c > +++ b/src/router.c > @@ -621,6 +621,11 @@ static int send_router_advert(struct interface *iface, > const struct in6_addr *fr > msecs = calc_adv_interval(iface, minvalid, &maxival); > lifetime = calc_ra_lifetime(iface, maxival); > > + if (!iface->have_link_local) { > + syslog(LOG_NOTICE, "Skip sending a RA on %s as still not > ready", iface->name); Log the real reason of the failure by replacing "still not ready" by "no link local address is available" > + goto out; > + } > + > if (default_route && valid_prefix) { > adv.h.nd_ra_router_lifetime = htons(lifetime < UINT16_MAX ? > lifetime : UINT16_MAX); > } else { > @@ -782,6 +787,7 @@ static int send_router_advert(struct interface *iface, > const struct in6_addr *fr > if (odhcpd_send(iface->router_event.uloop.fd, &dest, iov, > ARRAY_SIZE(iov), iface) > 0) > iface->ra_sent++; > > +out: > free(pfxs); > free(routes); > > -- > 2.39.2 > > > _______________________________________________ > openwrt-devel mailing list > openwrt-devel@lists.openwrt.org > https://lists.openwrt.org/mailman/listinfo/openwrt-devel
_______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel