The work done in this timer should be considerably reduced when we'll move autoconf out of the kernel. However we'll always need to check for IPv6 address life time expiration. This use case doesn't justify a specific global data structure.
So let's iterate over the global list of interfaces instead. This also prepare the work to split the NET_LOCK(). Since the ioctl(2) are per-ifp it makes sense to serialize write operations on a per interface basis. ok? Index: netinet6/nd6.c =================================================================== RCS file: /cvs/src/sys/netinet6/nd6.c,v retrieving revision 1.203 diff -u -p -r1.203 nd6.c --- netinet6/nd6.c 9 Feb 2017 15:23:35 -0000 1.203 +++ netinet6/nd6.c 1 Mar 2017 11:30:52 -0000 @@ -435,7 +435,7 @@ nd6_timer_work(void *null) { struct nd_defrouter *dr, *ndr; struct nd_prefix *pr, *npr; - struct in6_ifaddr *ia6, *nia6; + struct ifnet *ifp; int s; NET_LOCK(s); @@ -453,18 +453,26 @@ nd6_timer_work(void *null) * However, from a stricter spec-conformance standpoint, we should * rather separate address lifetimes and prefix lifetimes. */ - TAILQ_FOREACH_SAFE(ia6, &in6_ifaddr, ia_list, nia6) { - /* check address lifetime */ - if (IFA6_IS_INVALID(ia6)) { - in6_purgeaddr(&ia6->ia_ifa); - } else if (IFA6_IS_DEPRECATED(ia6)) { - ia6->ia6_flags |= IN6_IFF_DEPRECATED; - } else { - /* - * A new RA might have made a deprecated address - * preferred. - */ - ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; + TAILQ_FOREACH(ifp, &ifnet, if_list) { + struct ifaddr *ifa, *nifa; + struct in6_ifaddr *ia6; + + TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, nifa) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ia6 = ifatoia6(ifa); + /* check address lifetime */ + if (IFA6_IS_INVALID(ia6)) { + in6_purgeaddr(&ia6->ia_ifa); + } else if (IFA6_IS_DEPRECATED(ia6)) { + ia6->ia6_flags |= IN6_IFF_DEPRECATED; + } else { + /* + * A new RA might have made a deprecated address + * preferred. + */ + ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; + } } }