Date: Mon, 13 Jan 2014 15:36:40 +0000 From: Roy Marples <roy@marples.name> To: freebsd-net@freebsd.org Subject: IPv6: report address flag changes to userland Message-ID: <b9c07882a45edb3ad04b9f9ad092b268@mail.marples.name>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] Hi List There is zero point as I see it in announcing newly added tentative addresses to userland. It's not as if userland can actually use the address at this point. However, there is immense benefit in announcing address flag changes, such as removal of tentative, or addition of the other flags. The main benefit for this patch is so that dhcpcd(8) listen for when the kernel has completed DAD and has announced the result. dhcpcd can then react immediately instead of having to wait for the full time as dictated by the RFC. The attached patch addresses the above and was cut from FreeBSD-9 - there is a small adjustment needed for -current which is noted in the patch. The patch is based on the work I did in NetBSD a few months ago documented here: http://netbsd.2816.n7.nabble.com/PATCH-to-only-announce-RTM-NEWADDR-once-IPv6-DAD-completes-tp281110.html Comments? Roy [-- Attachment #2 --] Index: sys/netinet6/in6.c =================================================================== --- sys/netinet6/in6.c (revision 255235) +++ sys/netinet6/in6.c (working copy) @@ -140,8 +140,9 @@ #define ia62ifa(ia6) (&((ia6)->ia_ifa)) void -in6_ifaddloop(struct ifaddr *ifa) +in6_ifdoloop(struct ifaddr *ifa, int llflags) { + int announcing; struct sockaddr_dl gateway; struct sockaddr_in6 mask, addr; struct rtentry rt; @@ -151,73 +152,63 @@ ia = ifa2ia6(ifa); ifp = ifa->ifa_ifp; - IF_AFDATA_LOCK(ifp); - ifa->ifa_rtrequest = NULL; - - /* XXX QL - * we need to report rt_newaddrmsg - */ - ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | - LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); - IF_AFDATA_UNLOCK(ifp); - if (ln != NULL) { - ln->la_expire = 0; /* for IPv6 this means permanent */ - ln->ln_state = ND6_LLINFO_REACHABLE; - /* - * initialize for rtmsg generation - */ + /* Don't report new tentative addresses to the routing socket */ + announcing = (llflags & LLE_DELETE || + ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0)); + if (announcing) { + memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); + memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); bzero(&gateway, sizeof(gateway)); gateway.sdl_len = sizeof(gateway); gateway.sdl_family = AF_LINK; gateway.sdl_nlen = 0; - gateway.sdl_alen = 6; - memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, - sizeof(ln->ll_addr)); - LLE_WUNLOCK(ln); + bzero(&rt, sizeof(rt)); + rt.rt_gateway = (struct sockaddr *)&gateway; + rt.rt_flags = RTF_HOST | RTF_STATIC; + rt_mask(&rt) = (struct sockaddr *)&mask; + rt_key(&rt) = (struct sockaddr *)&addr; } - bzero(&rt, sizeof(rt)); - rt.rt_gateway = (struct sockaddr *)&gateway; - memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); - memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); - rt_mask(&rt) = (struct sockaddr *)&mask; - rt_key(&rt) = (struct sockaddr *)&addr; - rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC; - rt_newaddrmsg(RTM_ADD, ifa, 0, &rt); -} + if (llflags & LLE_DELETE) { + lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, + (struct sockaddr *)&mask, LLE_STATIC); + gateway.sdl_alen = ifp->if_addrlen; + } else { + llflags |= LLE_IFADDR; + IF_AFDATA_LOCK(ifp); + if (llflags & LLE_CREATE) { + llflags |= LLE_EXCLUSIVE; + ifa->ifa_rtrequest = NULL; // -current use nd6_rtrequest + } + ln = lla_lookup(LLTABLE6(ifp), llflags, + (struct sockaddr *)&ia->ia_addr); + IF_AFDATA_UNLOCK(ifp); + if (ln != NULL) { + if (llflags & LLE_CREATE) { + ln->la_expire = 0; /* permanent */ + ln->ln_state = ND6_LLINFO_REACHABLE; + } + if (announcing) { + gateway.sdl_alen = 6; + memcpy(gateway.sdl_data, + &ln->ll_addr.mac_aligned, + sizeof(ln->ll_addr)); + } + if (llflags & LLE_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + } + } -void -in6_ifremloop(struct ifaddr *ifa) -{ - struct sockaddr_dl gateway; - struct sockaddr_in6 mask, addr; - struct rtentry rt0; - struct in6_ifaddr *ia; - struct ifnet *ifp; - - ia = ifa2ia6(ifa); - ifp = ifa->ifa_ifp; - IF_AFDATA_LOCK(ifp); - lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR), - (struct sockaddr *)&ia->ia_addr); - IF_AFDATA_UNLOCK(ifp); - - /* - * initialize for rtmsg generation - */ - bzero(&gateway, sizeof(gateway)); - gateway.sdl_len = sizeof(gateway); - gateway.sdl_family = AF_LINK; - gateway.sdl_nlen = 0; - gateway.sdl_alen = ifp->if_addrlen; - bzero(&rt0, sizeof(rt0)); - rt0.rt_gateway = (struct sockaddr *)&gateway; - memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); - memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); - rt_mask(&rt0) = (struct sockaddr *)&mask; - rt_key(&rt0) = (struct sockaddr *)&addr; - rt0.rt_flags = RTF_HOST | RTF_STATIC; - rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0); + if (announcing) { + if (llflags & LLE_DELETE) + rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt); + else { + rt.rt_flags |= RTF_UP; + rt_newaddrmsg(RTM_ADD, ifa, 0, &rt); + } + } } int @@ -1021,10 +1012,6 @@ } else ia->ia6_lifetime.ia6t_preferred = 0; - /* reset the interface and routing table appropriately. */ - if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) - goto unlink; - /* * configure address flags. */ @@ -1050,6 +1037,10 @@ if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) ia->ia6_flags |= IN6_IFF_TENTATIVE; + /* reset the interface and routing table appropriately. */ + if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) + goto unlink; + /* * We are done if we have simply modified an existing address. */ @@ -1885,6 +1876,8 @@ /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ if (newhost) in6_ifaddloop(&(ia->ia_ifa)); + else + nd6_newaddrmsg(&(ia->ia_ifa)); return (error); } Index: sys/netinet6/in6_var.h =================================================================== --- sys/netinet6/in6_var.h (revision 255235) +++ sys/netinet6/in6_var.h (working copy) @@ -775,8 +775,9 @@ int in6_prefix_add_ifid __P((int, struct in6_ifaddr *)); void in6_prefix_remove_ifid __P((int, struct in6_ifaddr *)); void in6_purgeprefix __P((struct ifnet *)); -void in6_ifremloop(struct ifaddr *); -void in6_ifaddloop(struct ifaddr *); +void in6_ifdoloop(struct ifaddr *, int); +#define in6_ifaddloop(ifa) in6_ifdoloop((ifa), LLE_CREATE) +#define in6_ifremloop(ifa) in6_ifdoloop((ifa), LLE_DELETE) int in6_is_addr_deprecated __P((struct sockaddr_in6 *)); struct inpcb; Index: sys/netinet6/nd6.c =================================================================== --- sys/netinet6/nd6.c (revision 255235) +++ sys/netinet6/nd6.c (working copy) @@ -632,7 +632,10 @@ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; - ia6->ia6_flags |= IN6_IFF_DEPRECATED; + if ((oldflags & IN6_IFF_DEPRECATED) == 0) { + ia6->ia6_flags |= IN6_IFF_DEPRECATED; + nd6_newaddrmsg((struct ifaddr *)ia6); + } /* * If a temporary address has just become deprecated, @@ -663,7 +666,10 @@ * A new RA might have made a deprecated address * preferred. */ - ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; + if (ia6->ia6_flags & IN6_IFF_DEPRECATED) { + ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; + nd6_newaddrmsg((struct ifaddr *)ia6); + } } } Index: sys/netinet6/nd6.h =================================================================== --- sys/netinet6/nd6.h (revision 255235) +++ sys/netinet6/nd6.h (working copy) @@ -428,6 +428,7 @@ void nd6_ns_output __P((struct ifnet *, const struct in6_addr *, const struct in6_addr *, struct llentry *, int)); caddr_t nd6_ifptomac __P((struct ifnet *)); +#define nd6_newaddrmsg(ifa) in6_ifdoloop((ifa), 0) void nd6_dad_start __P((struct ifaddr *, int)); void nd6_dad_stop __P((struct ifaddr *)); void nd6_dad_duplicated __P((struct ifaddr *)); Index: sys/netinet6/nd6_nbr.c =================================================================== --- sys/netinet6/nd6_nbr.c (revision 255235) +++ sys/netinet6/nd6_nbr.c (working copy) @@ -1218,14 +1218,11 @@ ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); return; } - if (ia->ia6_flags & IN6_IFF_ANYCAST) { + if (ia->ia6_flags & IN6_IFF_ANYCAST || !V_ip6_dad_count) { ia->ia6_flags &= ~IN6_IFF_TENTATIVE; + nd6_newaddrmsg(ifa); return; } - if (!V_ip6_dad_count) { - ia->ia6_flags &= ~IN6_IFF_TENTATIVE; - return; - } if (ifa->ifa_ifp == NULL) panic("nd6_dad_start: ifa->ifa_ifp == NULL"); if (!(ifa->ifa_ifp->if_flags & IFF_UP)) { @@ -1383,6 +1380,7 @@ * No duplicate address found. */ ia->ia6_flags &= ~IN6_IFF_TENTATIVE; + nd6_newaddrmsg(ifa); nd6log((LOG_DEBUG, "%s: DAD complete for %s - no duplicates found\n", @@ -1432,6 +1430,9 @@ log(LOG_ERR, "%s: manual intervention required\n", if_name(ifp)); + /* Inform the routing socket that DAD has completed */ + nd6_newaddrmsg(ifa); + /* * If the address is a link-local address formed from an interface * identifier based on the hardware address which is supposed to be Index: sys/netinet6/nd6_rtr.c =================================================================== --- sys/netinet6/nd6_rtr.c (revision 255235) +++ sys/netinet6/nd6_rtr.c (working copy) @@ -1525,9 +1525,15 @@ ifa->ia6_flags &= ~IN6_IFF_DETACHED; ifa->ia6_flags |= IN6_IFF_TENTATIVE; nd6_dad_start((struct ifaddr *)ifa, 0); + /* We will notify the routing socket of + * the DAD result, so no need to + * here */ } } else { - ifa->ia6_flags |= IN6_IFF_DETACHED; + if ((ifa->ia6_flags & IN6_IFF_DETACHED) == 0) { + ifa->ia6_flags |= IN6_IFF_DETACHED; + nd6_newaddrmsg((struct ifaddr *)ifa); + } } } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?b9c07882a45edb3ad04b9f9ad092b268>
