On 06/06/16(Mon) 16:40, Martin Pieuchot wrote:
> Various functions in our ND implementation look at the type of the
> sending interface to decide what they should do. Recently sthen@
> found a regression on his p2p link because nd6_output() was doing
> a check that only makes sense for Ethernet interfaces.
>
> So instead of "skipping" p2p interface in nd6_output() let's move
> the ND resolution code to ether_output().
>
> Diff below does that by introducing nd6_resolve() which has the
> same semantic as arpresolve().
>
> I'll properly kill nd6_output() in another diff.
Here's the complete diff as pointed out by mikeb@ and sthen@
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.237
diff -u -p -r1.237 if_ethersubr.c
--- net/if_ethersubr.c 31 May 2016 07:48:19 -0000 1.237
+++ net/if_ethersubr.c 6 Jun 2016 14:20:22 -0000
@@ -225,9 +225,9 @@ ether_output(struct ifnet *ifp, struct m
break;
#ifdef INET6
case AF_INET6:
- error = nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst);
+ error = nd6_resolve(ifp, rt, m, dst, edst);
if (error)
- return (error);
+ return (error == EAGAIN ? 0 : error);
etype = htons(ETHERTYPE_IPV6);
break;
#endif
Index: netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.184
diff -u -p -r1.184 nd6.c
--- netinet6/nd6.c 6 Jun 2016 10:16:23 -0000 1.184
+++ netinet6/nd6.c 6 Jun 2016 14:26:00 -0000
@@ -1492,16 +1492,22 @@ int
nd6_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr_in6 *dst,
struct rtentry *rt0)
{
- struct mbuf *m = m0;
- struct rtentry *rt = rt0;
- struct llinfo_nd6 *ln = NULL;
- int error = 0;
+ return (ifp->if_output(ifp, m0, sin6tosa(dst), rt0));
+}
- if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
- goto sendpkt;
+int
+nd6_resolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
+ struct sockaddr *dst, u_char *desten)
+{
+ struct sockaddr_dl *sdl;
+ struct rtentry *rt;
+ struct llinfo_nd6 *ln = NULL;
+ int error;
- if (nd6_need_cache(ifp) == 0)
- goto sendpkt;
+ if (m->m_flags & M_MCAST) {
+ ETHER_MAP_IPV6_MULTICAST(&satosin6(dst)->sin6_addr, desten);
+ return (0);
+ }
error = rt_checkgate(rt0, &rt);
if (error) {
@@ -1524,6 +1530,12 @@ nd6_output(struct ifnet *ifp, struct mbu
return (EINVAL);
}
+ if (rt->rt_gateway->sa_family != AF_LINK) {
+ printf("%s: something odd happens\n", __func__);
+ m_freem(m);
+ return (EINVAL);
+ }
+
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
KASSERT(ln != NULL);
@@ -1553,8 +1565,21 @@ nd6_output(struct ifnet *ifp, struct mbu
* (i.e. its link-layer address is already resolved), just
* send the packet.
*/
- if (ln->ln_state > ND6_LLINFO_INCOMPLETE)
- goto sendpkt;
+ if (ln->ln_state > ND6_LLINFO_INCOMPLETE) {
+ sdl = satosdl(rt->rt_gateway);
+ if (sdl->sdl_alen != ETHER_ADDR_LEN) {
+ char addr[INET6_ADDRSTRLEN];
+ log(LOG_DEBUG, "%s: %s: incorrect nd6 information\n",
+ __func__,
+ inet_ntop(AF_INET6, &satosin6(dst)->sin6_addr,
+ addr, sizeof(addr)));
+ m_freem(m);
+ return (EINVAL);
+ }
+
+ bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
+ return (0);
+ }
/*
* There is a neighbor cache entry, but no ethernet address
@@ -1565,6 +1590,7 @@ nd6_output(struct ifnet *ifp, struct mbu
ln->ln_state = ND6_LLINFO_INCOMPLETE;
m_freem(ln->ln_hold);
ln->ln_hold = m;
+
/*
* If there has been no NS for the neighbor after entering the
* INCOMPLETE state, send the first solicitation.
@@ -1572,13 +1598,9 @@ nd6_output(struct ifnet *ifp, struct mbu
if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
ln->ln_asked++;
nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans / 1000);
- nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
+ nd6_ns_output(ifp, NULL, &satosin6(dst)->sin6_addr, ln, 0);
}
- return (0);
-
- sendpkt:
- error = ifp->if_output(ifp, m, sin6tosa(dst), rt);
- return (error);
+ return (EAGAIN);
}
int
@@ -1596,53 +1618,6 @@ nd6_need_cache(struct ifnet *ifp)
default:
return (0);
}
-}
-
-int
-nd6_storelladdr(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
- struct sockaddr *dst, u_char *desten)
-{
- struct sockaddr_dl *sdl;
- struct rtentry *rt;
- int error;
-
- if (m->m_flags & M_MCAST) {
- switch (ifp->if_type) {
- case IFT_ETHER:
- case IFT_CARP:
- ETHER_MAP_IPV6_MULTICAST(&satosin6(dst)->sin6_addr,
- desten);
- return (0);
- break;
- default:
- m_freem(m);
- return (EINVAL);
- }
- }
-
- error = rt_checkgate(rt0, &rt);
- if (error) {
- m_freem(m);
- return (error);
- }
-
- if (rt->rt_gateway->sa_family != AF_LINK) {
- printf("%s: something odd happens\n", __func__);
- m_freem(m);
- return (EINVAL);
- }
- sdl = satosdl(rt->rt_gateway);
- if (sdl->sdl_alen != ETHER_ADDR_LEN) {
- char addr[INET6_ADDRSTRLEN];
- log(LOG_DEBUG, "%s: %s: incorrect nd6 information\n", __func__,
- inet_ntop(AF_INET6, &satosin6(dst)->sin6_addr,
- addr, sizeof(addr)));
- m_freem(m);
- return (EINVAL);
- }
-
- bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
- return (0);
}
/*
Index: netinet6/nd6.h
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.h,v
retrieving revision 1.60
diff -u -p -r1.60 nd6.h
--- netinet6/nd6.h 1 Jun 2016 23:45:19 -0000 1.60
+++ netinet6/nd6.h 6 Jun 2016 14:16:33 -0000
@@ -271,7 +271,7 @@ int nd6_ioctl(u_long, caddr_t, struct if
void nd6_cache_lladdr(struct ifnet *, struct in6_addr *, char *, int, int,
int);
int nd6_output(struct ifnet *, struct mbuf *, struct sockaddr_in6 *,
struct rtentry *);
-int nd6_storelladdr(struct ifnet *, struct rtentry *, struct mbuf *,
+int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *,
struct sockaddr *, u_char *);
int nd6_sysctl(int, void *, size_t *, void *, size_t);
int nd6_need_cache(struct ifnet *);