On 2015/11/01 17:41, Yury Shefer wrote:
> I'm having trouble with enabling IPv6 routing on my 5.8 gateway.
>
> (Internet)----[DHCPv6+PD]----(em0-GW-axe0)----[SLAAC/rtadvd]
>
> My box is connected to Comcast, I'm getting IPv6 address assignment over
> DHCPv6 (wide dhcp6c) on WAN interface(em0) together with prefix delegation
> and assigning this prefix to axe0 (internal interface).
>
> On axe0 i'm running rtadvd. My clients are getting IPv6 addresses properly
> assigned and i'm able to ping link-local address of my gw. but if I check
> ipv6 neighbors on my gw I see that there are no global addresses except
> permanent (GW-owned addresses).
This (static v6 addresses on a system using SLAAC) is broken in 5.8.
The following diff backported from -current may fix it, but is untested
(may not even compile, I don't have a handy 5.8 system and config(8) has
changed).
Index: sys/net/if_spppsubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_spppsubr.c,v
retrieving revision 1.136
diff -u -p -r1.136 if_spppsubr.c
--- sys/net/if_spppsubr.c 18 Jul 2015 15:51:16 -0000 1.136
+++ sys/net/if_spppsubr.c 2 Nov 2015 09:20:03 -0000
@@ -4790,9 +4790,6 @@ sppp_set_ip6_addr(struct sppp *sp, const
*/
ifra->ifra_prefixmask.sin6_family = AF_UNSPEC;
- /* DAD is redundant after an IPv6CP exchange. */
- ifra->ifra_flags |= IN6_IFF_NODAD;
-
task_add(systq, &sp->ipv6cp.set_addr_task);
}
Index: sys/netinet6/in6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.161
diff -u -p -r1.161 in6.c
--- sys/netinet6/in6.c 18 Jul 2015 15:05:32 -0000 1.161
+++ sys/netinet6/in6.c 2 Nov 2015 09:20:03 -0000
@@ -462,7 +462,6 @@ in6_control(struct socket *so, u_long cm
case SIOCAIFADDR_IN6:
{
- struct nd_prefix *pr;
int plen, error = 0;
/* reject read-only flags */
@@ -492,39 +491,24 @@ in6_control(struct socket *so, u_long cm
break;
}
+ /* Perform DAD, if needed. */
+ 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++;
- }
-
s = splsoftnet();
- /*
- * this might affect the status of autoconfigured addresses,
- * that is, this address might make other addresses detached.
- */
- pfxlist_onlink_check();
-
+ 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);
+ splx(s);
+ return (error);
+ }
dohooks(ifp->if_addrhooks, 0);
splx(s);
break;
@@ -946,17 +930,6 @@ in6_update_ifa(struct ifnet *ifp, struct
LIST_INSERT_HEAD(&ia6->ia6_memberships, imm, i6mm_chain);
}
- /*
- * Perform DAD, if needed.
- * XXX It may be of use, if we can administratively
- * disable DAD.
- */
- if (hostIsNew && in6if_do_dad(ifp) &&
- (ifra->ifra_flags & IN6_IFF_NODAD) == 0)
- {
- nd6_dad_start(&ia6->ia_ifa, NULL);
- }
-
return (error);
unlink:
@@ -1022,24 +995,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);
Index: sys/netinet6/in6_ifattach.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_ifattach.c,v
retrieving revision 1.90
diff -u -p -r1.90 in6_ifattach.c
--- sys/netinet6/in6_ifattach.c 18 Jul 2015 15:05:32 -0000 1.90
+++ sys/netinet6/in6_ifattach.c 2 Nov 2015 09:20:03 -0000
@@ -292,9 +292,9 @@ success:
int
in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid)
{
- struct in6_ifaddr *ia6;
struct in6_aliasreq ifra;
- int s, error;
+ struct in6_ifaddr *ia6;
+ int s, error;
/*
* configure link-local address.
@@ -338,12 +338,6 @@ in6_ifattach_linklocal(struct ifnet *ifp
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
/*
- * Do not let in6_update_ifa() do DAD, since we need a random delay
- * before sending an NS at the first time the interface becomes up.
- */
- ifra.ifra_flags |= IN6_IFF_NODAD;
-
- /*
* Now call in6_update_ifa() to do a bunch of procedures to configure
* a link-local address. In the case of CARP, we may be called after
* one has already been configured, so check if it's already there
@@ -368,36 +362,23 @@ in6_ifattach_linklocal(struct ifnet *ifp
return (-1);
}
+ ia6 = in6ifa_ifpforlinklocal(ifp, 0);
+
/*
- * Adjust ia6_flags so that in6_ifattach() will perform DAD.
+ * Perform DAD.
+ *
* XXX: Some P2P interfaces seem not to send packets just after
* becoming up, so we skip p2p interfaces for safety.
*/
- ia6 = in6ifa_ifpforlinklocal(ifp, 0); /* ia6 must not be NULL */
-#ifdef DIAGNOSTIC
- if (!ia6) {
- panic("ia6 == NULL in in6_ifattach_linklocal");
- /* NOTREACHED */
- }
-#endif
- if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) ||
- (ifp->if_type == IFT_CARP)) == 0) {
- ia6->ia6_flags &= ~IN6_IFF_NODAD;
+ 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
@@ -435,9 +416,6 @@ in6_ifattach_loopback(struct ifnet *ifp)
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
- /* we don't need to perform DAD on loopback interfaces. */
- ifra.ifra_flags |= IN6_IFF_NODAD;
-
/*
* We are sure that this is a newly assigned address, so we can set
* NULL to the 3rd arg.
@@ -504,9 +482,6 @@ in6_nigroup(struct ifnet *ifp, const cha
int
in6_ifattach(struct ifnet *ifp)
{
- struct ifaddr *ifa;
- int dad_delay = 0; /* delay ticks before DAD output */
-
/* some of the interfaces are inherently not IPv6 capable */
switch (ifp->if_type) {
case IFT_BRIDGE:
@@ -541,14 +516,6 @@ in6_ifattach(struct ifnet *ifp)
return (0);
return (in6_ifattach_loopback(ifp));
- }
-
- /* Perform DAD. */
- TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
- if (ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- if (ifatoia6(ifa)->ia6_flags & IN6_IFF_TENTATIVE)
- nd6_dad_start(ifa, &dad_delay);
}
if (ifp->if_xflags & IFXF_AUTOCONF6)
Index: sys/netinet6/in6_var.h
===================================================================
RCS file: /cvs/src/sys/netinet6/in6_var.h,v
retrieving revision 1.52
diff -u -p -r1.52 in6_var.h
--- sys/netinet6/in6_var.h 8 Jul 2015 08:48:34 -0000 1.52
+++ sys/netinet6/in6_var.h 2 Nov 2015 09:20:03 -0000
@@ -433,9 +433,6 @@ struct in6_rrenumreq {
#define IN6_IFF_DUPLICATED 0x04 /* DAD detected duplicate */
#define IN6_IFF_DETACHED 0x08 /* may be detached from the link */
#define IN6_IFF_DEPRECATED 0x10 /* deprecated address */
-#define IN6_IFF_NODAD 0x20 /* don't perform DAD on this address
- * (used only at first SIOC* call)
- */
#define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */
#define IN6_IFF_PRIVACY 0x80 /* RFC 4941 temporary address */
Index: sys/netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.143
diff -u -p -r1.143 nd6.c
--- sys/netinet6/nd6.c 16 Jul 2015 15:31:35 -0000 1.143
+++ sys/netinet6/nd6.c 2 Nov 2015 09:20:03 -0000
@@ -730,6 +730,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;
/*
@@ -741,6 +743,22 @@ nd6_is_addr_neighbor(struct sockaddr_in6
if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) &&
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
Index: sys/netinet6/nd6.h
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.h,v
retrieving revision 1.44
diff -u -p -r1.44 nd6.h
--- sys/netinet6/nd6.h 18 Jul 2015 15:05:32 -0000 1.44
+++ sys/netinet6/nd6.h 2 Nov 2015 09:20:03 -0000
@@ -291,7 +291,7 @@ void nd6_ns_input(struct mbuf *, int, in
void nd6_ns_output(struct ifnet *, struct in6_addr *,
struct in6_addr *, struct llinfo_nd6 *, int);
caddr_t nd6_ifptomac(struct ifnet *);
-void nd6_dad_start(struct ifaddr *, int *);
+void nd6_dad_start(struct ifaddr *);
void nd6_dad_stop(struct ifaddr *);
void nd6_ra_input(struct mbuf *, int, int);
@@ -315,7 +315,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);
Index: sys/netinet6/nd6_nbr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.91
diff -u -p -r1.91 nd6_nbr.c
--- sys/netinet6/nd6_nbr.c 16 Jul 2015 15:28:38 -0000 1.91
+++ sys/netinet6/nd6_nbr.c 2 Nov 2015 09:20:03 -0000
@@ -1128,15 +1128,14 @@ nd6_dad_stoptimer(struct dadq *dp)
/*
* Start Duplicated Address Detection (DAD) for specified interface address.
- *
- * tick - minimum delay ticks for IFF_UP event
*/
void
-nd6_dad_start(struct ifaddr *ifa, int *tick)
+nd6_dad_start(struct ifaddr *ifa)
{
struct in6_ifaddr *ia6 = ifatoia6(ifa);
struct dadq *dp;
char addr[INET6_ADDRSTRLEN];
+ int s;
if (!dad_init) {
TAILQ_INIT(&dadq);
@@ -1149,31 +1148,15 @@ nd6_dad_start(struct ifaddr *ifa, int *t
* - DAD is disabled (ip6_dad_count == 0)
* - the interface address is anycast
*/
- if (!(ia6->ia6_flags & IN6_IFF_TENTATIVE)) {
- log(LOG_DEBUG,
- "nd6_dad_start: called with non-tentative address "
- "%s(%s)\n",
- inet_ntop(AF_INET6, &ia6->ia_addr.sin6_addr,
- addr, sizeof(addr)),
- ifa->ifa_ifp ? ifa->ifa_ifp->if_xname : "???");
- return;
- }
- if (ia6->ia6_flags & IN6_IFF_ANYCAST) {
- ia6->ia6_flags &= ~IN6_IFF_TENTATIVE;
- return;
- }
- if (!ip6_dad_count) {
+ KASSERT(ia6->ia6_flags & IN6_IFF_TENTATIVE);
+ if ((ia6->ia6_flags & IN6_IFF_ANYCAST) || (!ip6_dad_count)) {
ia6->ia6_flags &= ~IN6_IFF_TENTATIVE;
return;
}
- if (!ifa->ifa_ifp)
- panic("nd6_dad_start: ifa->ifa_ifp == NULL");
- if (!(ifa->ifa_ifp->if_flags & IFF_UP))
- return;
- if (nd6_dad_find(ifa) != NULL) {
- /* DAD already in progress */
+
+ /* DAD already in progress */
+ if (nd6_dad_find(ifa) != NULL)
return;
- }
dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT | M_ZERO);
if (dp == NULL) {
@@ -1185,6 +1168,8 @@ nd6_dad_start(struct ifaddr *ifa, int *t
return;
}
bzero(&dp->dad_timer_ch, sizeof(dp->dad_timer_ch));
+
+ s = splsoftnet();
TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
ip6_dad_pending++;
@@ -1202,21 +1187,10 @@ nd6_dad_start(struct ifaddr *ifa, int *t
dp->dad_count = ip6_dad_count;
dp->dad_ns_icount = dp->dad_na_icount = 0;
dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
- if (tick == NULL) {
- nd6_dad_ns_output(dp, ifa);
- nd6_dad_starttimer(dp,
- (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
- } else {
- int ntick;
-
- if (*tick == 0)
- ntick = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY *
- hz);
- else
- ntick = *tick + arc4random_uniform(hz / 2);
- *tick = ntick;
- nd6_dad_starttimer(dp, ntick);
- }
+ nd6_dad_ns_output(dp, ifa);
+ nd6_dad_starttimer(dp,
+ (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+ splx(s);
}
/*
Index: sys/netinet6/nd6_rtr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.113
diff -u -p -r1.113 nd6_rtr.c
--- sys/netinet6/nd6_rtr.c 18 Jul 2015 15:51:17 -0000 1.113
+++ sys/netinet6/nd6_rtr.c 2 Nov 2015 09:20:03 -0000
@@ -1077,7 +1077,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;
@@ -1104,7 +1104,7 @@ nd6_prefix_add(struct ifnet *ifp, struct
* 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;
@@ -1194,14 +1194,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];
@@ -2109,7 +2102,7 @@ in6_ifadd(struct nd_prefix *pr, int priv
/* XXX: scope zone ID? */
- ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
+ ifra.ifra_flags |= IN6_IFF_AUTOCONF|IN6_IFF_TENTATIVE;
/* allocate ifaddr structure, link into chain, etc. */
s = splsoftnet();
@@ -2128,7 +2121,13 @@ in6_ifadd(struct nd_prefix *pr, int priv
}
/* this is always non-NULL */
- return (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr));
+ ia6 = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
+
+ /* Perform DAD, if needed. */
+ if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
+ nd6_dad_start(&ia6->ia_ifa);
+
+ return (ia6);
}
int