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];