On 18/08/15(Tue) 23:22, Martin Pieuchot wrote:
> On 18/08/15(Tue) 14:00, Stuart Henderson wrote:
> > On 2015/08/18 14:27, Martin Pieuchot wrote:
> > > On 18/08/15(Tue) 13:05, Stuart Henderson wrote:
> > > > I'm trying to add v6 to my second ISP connection on pppoe1, unlike my
> > > > first ISP, this one requires autoconf and dhcpv6-pd to pick up addresses
> > > > and have them routed. (They are referring to TR-187,
> > > > https://www.broadband-forum.org/technical/download/TR-187.pdf -
> > > > the "residential gateway" requirements are in section 6.1)
> > > > 
> > > > I haven't got as far as looking at dhcpv6-pd because when I enable
> > > > autoconf, as soon as it picks up the address I lose connected routes
> > > > to my local /64 subnets:
> > > 
> > > Which prefixes (ndp -p) and default routers (ndp -r) do you have before
> > > and after the interface picks up the address?
> > 
> > Before: no default routers showing with ndp -r.
> > 
> > $ ndp -p | paste - - - | sed 's/vltime=infinity, pltime=infinity, 
> > expire=Never, //'
> > [...]
> > 2001:4b10:1002:cc01::/64 if=vlan2       flags=LO ref=1    No advertising 
> > router
> > ... After:
> > 
> > $ ndp -r
> > [...]
> > 2001:4b10:1002:cc01::/64 if=vlan2       flags=LD ref=1    No advertising 
> > router
> 
> See how all your prefix suddenly became detached "D"?  That's a
> limitation of pfxlist_onlink_check() which does not make a difference
> between prefixes added to the global prefix list via an advertisement
> or via manual configuration.
> 
> I'll see if it's possible to split the prefix lists in such way that
> the RS/RA code only mess with its own states.

Diff below is just slightly tested and depends on the diff to
"Kill IN6_IFF_NODAD" but it shows where I'd like to go.

The idea is to use the global prefix list only for AUTOCONF'd addresses.

Since this list is only checked in nd6_is_addr_neighbor() I added a new
case for non-AUTOCONF'd addresses.  With it you should not longer see
the prefix of your manually configured interfaces in the "ndp -p" output
but it's ok since they should always be in your routing table.


diff --git sys/netinet6/in6.c sys/netinet6/in6.c
index 2f5d5a6..e9101dc 100644
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -462,7 +462,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, 
struct ifnet *ifp)
 
        case SIOCAIFADDR_IN6:
        {
-               struct nd_prefix *pr;
                int plen, error = 0;
 
                /* reject read-only flags */
@@ -509,40 +508,19 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, 
struct ifnet *ifp)
                if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
                        nd6_dad_start(&ia6->ia_ifa);
 
-
                plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, NULL);
                if (plen == 128) {
                        dohooks(ifp->if_addrhooks, 0);
                        break;  /* we don't need to install a host route. */
                }
 
-               /*
-                * then, make the prefix on-link on the interface.
-                * XXX: we'd rather create the prefix before the address, but
-                * we need at least one address to install the corresponding
-                * interface route, so we configure the address first.
-                */
-               pr = nd6_prefix_add(ifp, &ifra->ifra_addr,
-                   &ifra->ifra_prefixmask, &ifra->ifra_lifetime,
-                   ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0));
-               if (pr == NULL) {
-                       log(LOG_ERR, "cannot add prefix\n");
-                       return (EINVAL); /* XXX panic here? */
-               }
-
-               /* relate the address to the prefix */
-               if (ia6->ia6_ndpr == NULL) {
-                       ia6->ia6_ndpr = pr;
-                       pr->ndpr_refcnt++;
+               error = rt_ifa_add(&ia6->ia_ifa,
+                   RTF_UP|RTF_CLONING|RTF_CONNECTED, ia6->ia_ifa.ifa_addr);
+               if (error) {
+                       in6_purgeaddr(&ia6->ia_ifa);
+                       return (error);
                }
-
                s = splsoftnet();
-               /*
-                * this might affect the status of autoconfigured addresses,
-                * that is, this address might make other addresses detached.
-                */
-               pfxlist_onlink_check();
-
                dohooks(ifp->if_addrhooks, 0);
                splx(s);
                break;
@@ -977,24 +955,19 @@ in6_purgeaddr(struct ifaddr *ifa)
 void
 in6_unlink_ifa(struct in6_ifaddr *ia6, struct ifnet *ifp)
 {
+       struct ifaddr *ifa = &ia6->ia_ifa;
+
        splsoftassert(IPL_SOFTNET);
 
-       ifa_del(ifp, &ia6->ia_ifa);
+       ifa_del(ifp, ifa);
 
        TAILQ_REMOVE(&in6_ifaddr, ia6, ia_list);
 
        /* Release the reference to the base prefix. */
        if (ia6->ia6_ndpr == NULL) {
-               char addr[INET6_ADDRSTRLEN];
-
-               if (!IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia6)) &&
-                   !IN6_IS_ADDR_LOOPBACK(IA6_IN6(ia6)) &&
-                   !IN6_ARE_ADDR_EQUAL(IA6_MASKIN6(ia6), &in6mask128))
-                       log(LOG_NOTICE, "in6_unlink_ifa: interface address "
-                           "%s has no prefix\n",
-                           inet_ntop(AF_INET6, IA6_IN6(ia6), addr,
-                               sizeof(addr)));
+               rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED, ifa->ifa_addr);
        } else {
+               KASSERT(ia6->ia6_flags & IN6_IFF_AUTOCONF);
                ia6->ia6_flags &= ~IN6_IFF_AUTOCONF;
                if (--ia6->ia6_ndpr->ndpr_refcnt == 0)
                        prelist_remove(ia6->ia6_ndpr);
diff --git sys/netinet6/in6_ifattach.c sys/netinet6/in6_ifattach.c
index 58a0493..425851e 100644
--- sys/netinet6/in6_ifattach.c
+++ sys/netinet6/in6_ifattach.c
@@ -293,7 +293,8 @@ int
 in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid)
 {
        struct in6_aliasreq ifra;
-       int  s, error;
+       struct in6_ifaddr *ia6;
+       int s, error;
 
        /*
         * configure link-local address.
@@ -355,32 +356,23 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr 
*ifid)
                return (-1);
        }
 
+       ia6 = in6ifa_ifpforlinklocal(ifp, 0);
+
        /*
         * Perform DAD.
         *
         * XXX: Some P2P interfaces seem not to send packets just after
         * becoming up, so we skip p2p interfaces for safety.
         */
-       if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) ||
-           (ifp->if_type == IFT_CARP)) == 0) {
-               struct in6_ifaddr *ia6;
-               ia6 = in6ifa_ifpforlinklocal(ifp, 0);
+       if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) == 0)) {
                ia6->ia6_flags |= IN6_IFF_TENTATIVE;
                nd6_dad_start(&ia6->ia_ifa);
        }
 
-       /*
-        * Make the link-local prefix (fe80::/64%link) as on-link.
-        * Since we'd like to manage prefixes separately from addresses,
-        * we make an ND6 prefix structure for the link-local prefix,
-        * and add it to the prefix list as a never-expire prefix.
-        * XXX: this change might affect some existing code base...
-        */
-       if (nd6_prefix_add(ifp, &ifra.ifra_addr, &ifra.ifra_prefixmask,
-               &ifra.ifra_lifetime, 1) == NULL)
-               return (EINVAL);
+       error = rt_ifa_add(&ia6->ia_ifa, RTF_UP|RTF_CLONING|RTF_CONNECTED,
+           ia6->ia_ifa.ifa_addr);
 
-       return (0);
+       return (error);
 }
 
 int
diff --git sys/netinet6/nd6.c sys/netinet6/nd6.c
index 47ebfc6..8fabab0 100644
--- sys/netinet6/nd6.c
+++ sys/netinet6/nd6.c
@@ -728,6 +728,8 @@ int
 nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
 {
        struct nd_prefix *pr;
+       struct in6_ifaddr *ia6;
+       struct ifaddr *ifa;
        struct rtentry *rt;
 
        /*
@@ -740,6 +742,22 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct 
ifnet *ifp)
            ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index)
                return (1);
 
+       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+               if (ifa->ifa_addr->sa_family != AF_INET6)
+                       continue;
+
+               ia6 = ifatoia6(ifa);
+
+               /* Prefix check down below. */
+               if (ia6->ia6_flags & IN6_IFF_AUTOCONF)
+                       continue;
+
+               if (IN6_ARE_MASKED_ADDR_EQUAL(&addr->sin6_addr,
+                   &ia6->ia_addr.sin6_addr,
+                   &ia6->ia_prefixmask.sin6_addr))
+                       return (1);
+       }
+
        /*
         * If the address matches one of our on-link prefixes, it should be a
         * neighbor.
diff --git sys/netinet6/nd6.h sys/netinet6/nd6.h
index 42b70d5..a4e643e 100644
--- sys/netinet6/nd6.h
+++ sys/netinet6/nd6.h
@@ -313,7 +313,7 @@ void pfxlist_onlink_check(void);
 struct nd_defrouter *defrouter_lookup(struct in6_addr *, struct ifnet *);
 
 struct nd_prefix *nd6_prefix_add(struct ifnet *, struct sockaddr_in6 *,
-    struct sockaddr_in6 *, struct in6_addrlifetime *, int);
+    struct sockaddr_in6 *, struct in6_addrlifetime *);
 struct nd_prefix *nd6_prefix_lookup(struct nd_prefix *);
 int in6_ifdel(struct ifnet *, struct in6_addr *);
 int in6_init_prefix_ltimes(struct nd_prefix *ndpr);
diff --git sys/netinet6/nd6_rtr.c sys/netinet6/nd6_rtr.c
index fb574d9..fb72964 100644
--- sys/netinet6/nd6_rtr.c
+++ sys/netinet6/nd6_rtr.c
@@ -1078,7 +1078,7 @@ purge_detached(struct ifnet *ifp)
 
 struct nd_prefix *
 nd6_prefix_add(struct ifnet *ifp, struct sockaddr_in6 *addr,
-    struct sockaddr_in6 *mask, struct in6_addrlifetime *lt, int autoconf)
+    struct sockaddr_in6 *mask, struct in6_addrlifetime *lt)
 {
        struct nd_prefix pr0, *pr;
        int i;
@@ -1105,7 +1105,7 @@ nd6_prefix_add(struct ifnet *ifp, struct sockaddr_in6 
*addr,
         * an intended behavior.
         */
        pr0.ndpr_raf_onlink = 1; /* should be configurable? */
-       pr0.ndpr_raf_auto = autoconf;
+       pr0.ndpr_raf_auto = 1;
        pr0.ndpr_vltime = lt->ia6t_vltime;
        pr0.ndpr_pltime = lt->ia6t_pltime;
 
@@ -1195,14 +1195,7 @@ prelist_remove(struct nd_prefix *pr)
        /* make sure to invalidate the prefix until it is really freed. */
        pr->ndpr_vltime = 0;
        pr->ndpr_pltime = 0;
-#if 0
-       /*
-        * Though these flags are now meaningless, we'd rather keep the value
-        * not to confuse users when executing "ndp -p".
-        */
-       pr->ndpr_raf_onlink = 0;
-       pr->ndpr_raf_auto = 0;
-#endif
+
        if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
            (e = nd6_prefix_offlink(pr)) != 0) {
                char addr[INET6_ADDRSTRLEN];

Reply via email to