On 08/19/15 17:51, Martin Pieuchot wrote:
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.
That problem sthen@ describes here, sounds very similar to my home situation.
My router has IPv6 /48 HE tunnel, and on the wired network, i have /64 subnet
where all hosts have statically configured IPv6 addresses, incl. default route.
The router is also WLAN AP, where it has rtadvd running on the WLAN if,
and announcing a different /64 subnet.
Notebooks and other gear, that might have WLAN and network interfaces, when
connected to the wired network, and autoconf on the WLAN interface kicked in,
the IPv6 connection to the local /64 network were gone.
With the patch below, together with the other patch you mention above,
my problem is gone, network works as I expect it.
cheers,
Sebastian
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];