Date: Mon, 14 Sep 2015 19:17:26 +0000 (UTC) From: Eric van Gyzen <vangyzen@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r287798 - in head/sys: net netinet6 Message-ID: <201509141917.t8EJHQIg026210@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@dell.com> in 2012, TC Telkamp <terence_telkamp@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 }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509141917.t8EJHQIg026210>