svn commit: r287798 - in head/sys: net netinet6
Eric van Gyzen
vangyzen at FreeBSD.org
Mon Sep 14 19:17:28 UTC 2015
Author: vangyzen
Date: Mon Sep 14 19:17:25 2015
New Revision: 287798
URL: https://svnweb.freebsd.org/changeset/base/287798
Log:
Fix the handling of IPv6 On-Link Redirects.
On receipt of a redirect message, install an interface route for the
redirected destination. On removal of the corresponding Neighbor Cache
entry, remove the interface route.
This requires changes in rtredirect_fib() to cope with an AF_LINK
address for the gateway and with the absence of RTF_GATEWAY.
This fixes the "Redirected On-Link" test cases in the Tahi IPv6 Ready Logo
Phase 2 test suite.
Unrelated to the above, fix a recursion on the radix node head lock
triggered by the Tahi Redirected to Alternate Router test cases.
When I first wrote this patch in October 2012, all Section 2
(Neighbor Discovery) test cases passed on 10-CURRENT, 9-STABLE,
and 8-STABLE. cem@ recently rebased the 10.x patch onto head and reported
that it passes Tahi. (Thanks!)
These other test cases also passed in 2012:
* the RTF_MODIFIED case, with IPv4 and IPv6 (using a
RTF_HOST|RTF_GATEWAY route for the destination)
* the redirected-to-self case, with IPv4 and IPv6
* a valid IPv4 redirect
All testing in 2012 was done with WITNESS and INVARIANTS.
Tested by: EMC / Isilon Storage Division via Conrad Meyer (cem) in 2015,
Mark Kelley <mark_kelley at dell.com> in 2012,
TC Telkamp <terence_telkamp at dell.com> in 2012
PR: 152791
Reviewed by: melifaro (current rev), bz (earlier rev)
Approved by: kib (mentor)
MFC after: 1 month
Relnotes: yes
Sponsored by: Dell Inc.
Differential Revision: https://reviews.freebsd.org/D3602
Modified:
head/sys/net/if_llatbl.h
head/sys/net/route.c
head/sys/netinet6/icmp6.c
head/sys/netinet6/nd6.c
head/sys/netinet6/nd6_rtr.c
Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h Mon Sep 14 18:59:01 2015 (r287797)
+++ head/sys/net/if_llatbl.h Mon Sep 14 19:17:25 2015 (r287798)
@@ -183,6 +183,7 @@ MALLOC_DECLARE(M_LLTABLE);
#define LLE_STATIC 0x0002 /* entry is static */
#define LLE_IFADDR 0x0004 /* entry is interface addr */
#define LLE_VALID 0x0008 /* ll_addr is valid */
+#define LLE_REDIRECT 0x0010 /* installed by redirect; has host rtentry */
#define LLE_PUB 0x0020 /* publish entry ??? */
#define LLE_LINKED 0x0040 /* linked to lookup structure */
/* LLE request flags */
Modified: head/sys/net/route.c
==============================================================================
--- head/sys/net/route.c Mon Sep 14 18:59:01 2015 (r287797)
+++ head/sys/net/route.c Mon Sep 14 19:17:25 2015 (r287798)
@@ -584,13 +584,20 @@ rtredirect_fib(struct sockaddr *dst,
* we have a routing loop, perhaps as a result of an interface
* going down recently.
*/
- if (!(flags & RTF_DONE) && rt &&
- (!sa_equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
- error = EINVAL;
- else if (ifa_ifwithaddr_check(gateway))
+ if (!(flags & RTF_DONE) && rt) {
+ if (!sa_equal(src, rt->rt_gateway)) {
+ error = EINVAL;
+ goto done;
+ }
+ if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) {
+ error = EINVAL;
+ goto done;
+ }
+ }
+ if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) {
error = EHOSTUNREACH;
- if (error)
goto done;
+ }
/*
* Create a new entry if we just got back a wildcard entry
* or the lookup failed. This is necessary for hosts
@@ -613,7 +620,7 @@ rtredirect_fib(struct sockaddr *dst,
rt0 = rt;
rt = NULL;
- flags |= RTF_GATEWAY | RTF_DYNAMIC;
+ flags |= RTF_DYNAMIC;
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = dst;
info.rti_info[RTAX_GATEWAY] = gateway;
@@ -640,6 +647,8 @@ rtredirect_fib(struct sockaddr *dst,
* Smash the current notion of the gateway to
* this destination. Should check about netmask!!!
*/
+ if ((flags & RTF_GATEWAY) == 0)
+ rt->rt_flags &= ~RTF_GATEWAY;
rt->rt_flags |= RTF_MODIFIED;
flags |= RTF_MODIFIED;
stat = &V_rtstat.rts_newgateway;
@@ -653,7 +662,8 @@ rtredirect_fib(struct sockaddr *dst,
gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED);
RADIX_NODE_HEAD_UNLOCK(rnh);
EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst);
- RTFREE_LOCKED(gwrt);
+ if (gwrt)
+ RTFREE_LOCKED(gwrt);
}
} else
error = EHOSTUNREACH;
Modified: head/sys/netinet6/icmp6.c
==============================================================================
--- head/sys/netinet6/icmp6.c Mon Sep 14 18:59:01 2015 (r287797)
+++ head/sys/netinet6/icmp6.c Mon Sep 14 19:17:25 2015 (r287798)
@@ -2434,27 +2434,39 @@ icmp6_redirect_input(struct mbuf *m, int
nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
- if (!is_onlink) { /* better router case. perform rtredirect. */
- /* perform rtredirect */
+ /*
+ * Install a gateway route in the better-router case or an interface
+ * route in the on-link-destination case.
+ */
+ {
struct sockaddr_in6 sdst;
struct sockaddr_in6 sgw;
struct sockaddr_in6 ssrc;
+ struct sockaddr *gw;
+ int rt_flags;
u_int fibnum;
bzero(&sdst, sizeof(sdst));
- bzero(&sgw, sizeof(sgw));
bzero(&ssrc, sizeof(ssrc));
- sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
- sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
- sizeof(struct sockaddr_in6);
- bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
+ sdst.sin6_family = ssrc.sin6_family = AF_INET6;
+ sdst.sin6_len = ssrc.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
+ rt_flags = RTF_HOST;
+ if (is_router) {
+ bzero(&sgw, sizeof(sgw));
+ sgw.sin6_family = AF_INET6;
+ sgw.sin6_len = sizeof(struct sockaddr_in6);
+ bcopy(&redtgt6, &sgw.sin6_addr,
+ sizeof(struct in6_addr));
+ gw = (struct sockaddr *)&sgw;
+ rt_flags |= RTF_GATEWAY;
+ } else
+ gw = ifp->if_addr->ifa_addr;
for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
- in6_rtredirect((struct sockaddr *)&sdst,
- (struct sockaddr *)&sgw, (struct sockaddr *)NULL,
- RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc,
- fibnum);
+ in6_rtredirect((struct sockaddr *)&sdst, gw,
+ (struct sockaddr *)NULL, rt_flags,
+ (struct sockaddr *)&ssrc, fibnum);
}
/* finally update cached route in each socket via pfctlinput */
{
Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c Mon Sep 14 18:59:01 2015 (r287797)
+++ head/sys/netinet6/nd6.c Mon Sep 14 19:17:25 2015 (r287798)
@@ -132,6 +132,7 @@ static void nd6_setmtu0(struct ifnet *,
static void nd6_slowtimo(void *);
static int regen_tmpaddr(struct in6_ifaddr *);
static struct llentry *nd6_free(struct llentry *, int);
+static void nd6_free_redirect(const struct llentry *);
static void nd6_llinfo_timer(void *);
static void clear_llinfo_pqueue(struct llentry *);
static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
@@ -1223,6 +1224,13 @@ nd6_free(struct llentry *ln, int gc)
defrouter_select();
}
+ /*
+ * If this entry was added by an on-link redirect, remove the
+ * corresponding host route.
+ */
+ if (ln->la_flags & LLE_REDIRECT)
+ nd6_free_redirect(ln);
+
if (ln->ln_router || dr)
LLE_WLOCK(ln);
}
@@ -1256,6 +1264,36 @@ nd6_free(struct llentry *ln, int gc)
}
/*
+ * Remove the rtentry for the given llentry,
+ * both of which were installed by a redirect.
+ */
+static void
+nd6_free_redirect(const struct llentry *ln)
+{
+ int fibnum;
+ struct rtentry *rt;
+ struct radix_node_head *rnh;
+ struct sockaddr_in6 sin6;
+
+ lltable_fill_sa_entry(ln, (struct sockaddr *)&sin6);
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh == NULL)
+ continue;
+
+ RADIX_NODE_HEAD_LOCK(rnh);
+ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0,
+ RTF_RNH_LOCKED, fibnum);
+ if (rt) {
+ if (rt->rt_flags == (RTF_UP | RTF_HOST | RTF_DYNAMIC))
+ rt_expunge(rnh, rt);
+ RTFREE_LOCKED(rt);
+ }
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ }
+}
+
+/*
* Upper-layer reachability hint for Neighbor Unreachability Detection.
*
* XXX cost-effective methods?
@@ -1746,8 +1784,11 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
*/
if (code == ND_REDIRECT_ROUTER)
ln->ln_router = 1;
- else if (is_newentry) /* (6-7) */
- ln->ln_router = 0;
+ else {
+ if (is_newentry) /* (6-7) */
+ ln->ln_router = 0;
+ ln->la_flags |= LLE_REDIRECT;
+ }
break;
case ND_ROUTER_SOLICIT:
/*
Modified: head/sys/netinet6/nd6_rtr.c
==============================================================================
--- head/sys/netinet6/nd6_rtr.c Mon Sep 14 18:59:01 2015 (r287797)
+++ head/sys/netinet6/nd6_rtr.c Mon Sep 14 19:17:25 2015 (r287798)
@@ -2105,7 +2105,7 @@ rt6_deleteroute(struct rtentry *rt, void
return (0);
return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
- rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum));
+ rt_mask(rt), rt->rt_flags | RTF_RNH_LOCKED, NULL, rt->rt_fibnum));
#undef SIN6
}
More information about the svn-src-all
mailing list