From owner-svn-src-projects@FreeBSD.ORG Sat May 12 16:10:57 2012 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 9B6F41065670; Sat, 12 May 2012 16:10:57 +0000 (UTC) (envelope-from kmacy@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8555F8FC0A; Sat, 12 May 2012 16:10:57 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q4CGAv4H041423; Sat, 12 May 2012 16:10:57 GMT (envelope-from kmacy@svn.freebsd.org) Received: (from kmacy@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q4CGAvvT041410; Sat, 12 May 2012 16:10:57 GMT (envelope-from kmacy@svn.freebsd.org) Message-Id: <201205121610.q4CGAvvT041410@svn.freebsd.org> From: Kip Macy Date: Sat, 12 May 2012 16:10:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r235341 - in projects/rtentry_cache/sys: net netinet netinet6 X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 May 2012 16:10:57 -0000 Author: kmacy Date: Sat May 12 16:10:56 2012 New Revision: 235341 URL: http://svn.freebsd.org/changeset/base/235341 Log: Commit current state of rtentry patch. Modified: projects/rtentry_cache/sys/net/if_ethersubr.c projects/rtentry_cache/sys/net/route.c projects/rtentry_cache/sys/netinet/in_pcb.c projects/rtentry_cache/sys/netinet/in_pcb.h projects/rtentry_cache/sys/netinet/ip_output.c projects/rtentry_cache/sys/netinet/tcp_output.c projects/rtentry_cache/sys/netinet/tcp_usrreq.c projects/rtentry_cache/sys/netinet6/in6_src.c projects/rtentry_cache/sys/netinet6/ip6_forward.c projects/rtentry_cache/sys/netinet6/ip6_output.c projects/rtentry_cache/sys/netinet6/nd6.c projects/rtentry_cache/sys/netinet6/nd6.h Modified: projects/rtentry_cache/sys/net/if_ethersubr.c ============================================================================== --- projects/rtentry_cache/sys/net/if_ethersubr.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/net/if_ethersubr.c Sat May 12 16:10:56 2012 (r235341) @@ -146,9 +146,30 @@ int ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared); static VNET_DEFINE(int, ether_ipfw); #define V_ether_ipfw VNET(ether_ipfw) -#endif +static __inline void +update_cached_lle(struct route *ro, struct llentry *lle, struct ifnet *ifp, + struct sockaddr *dst) +{ + + if (lle == ro->ro_lle || + (ro->ro_flags & RT_CACHING_CONTEXT) == 0) + return; + + IF_AFDATA_RLOCK(ifp); + lle = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + IF_AFDATA_RUNLOCK(ifp); + if (lle != NULL) { + LLE_ADDREF(lle); + LLE_WUNLOCK(lle); + if (ro->ro_lle != NULL) + LLE_FREE(ro->ro_lle); + ro->ro_lle = lle; + } +} +#endif + /* * Ethernet output routine. * Encapsulate a packet of type family for the local net. @@ -198,6 +219,8 @@ ether_output(struct ifnet *ifp, struct m if (error) return (error == EWOULDBLOCK ? 0 : error); type = htons(ETHERTYPE_IP); + if (ro != NULL) + update_cached_lle(ro, lle, ifp, dst); break; case AF_ARP: { @@ -236,6 +259,8 @@ ether_output(struct ifnet *ifp, struct m if (error) return error; type = htons(ETHERTYPE_IPV6); + if (ro != NULL) + update_cached_lle(ro, lle, ifp, dst); break; #endif #ifdef IPX Modified: projects/rtentry_cache/sys/net/route.c ============================================================================== --- projects/rtentry_cache/sys/net/route.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/net/route.c Sat May 12 16:10:56 2012 (r235341) @@ -99,6 +99,11 @@ SYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLA */ TUNABLE_INT("net.fibs", &rt_numfibs); +u_int inpcb_rt_cache_enable = 0; +SYSCTL_UINT(_net, OID_AUTO, conn_rt_cache, CTLFLAG_RW|CTLFLAG_TUN, &inpcb_rt_cache_enable, 0, ""); +TUNABLE_INT("net.conn_rt_cache", &inpcb_rt_cache_enable); + + /* * By default add routes to all fibs for new interfaces. * Once this is set to 0 then only allocate routes on interface @@ -905,6 +910,7 @@ rtexpunge(struct rtentry *rt) * but when callers invoke us blindly it may not (sigh). */ rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh); + atomic_add_int(&rnh->rnh_gen, 1); if (rn == NULL) { error = ESRCH; goto bad; @@ -994,6 +1000,7 @@ rn_mpath_update(int req, struct rt_addri * to the caller */ rn = rnh->rnh_deladdr(dst, netmask, rnh); + atomic_add_int(&rnh->rnh_gen, 1); KASSERT(rt == RNTORT(rn), ("radix node disappeared")); goto gwdelete; } @@ -1117,6 +1124,7 @@ rtrequest1_fib(int req, struct rt_addrin * Complain if it is not there and do no more processing. */ rn = rnh->rnh_deladdr(dst, netmask, rnh); + atomic_add_int(&rnh->rnh_gen, 1); if (rn == NULL) senderr(ESRCH); if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) @@ -1278,6 +1286,7 @@ rtrequest1_fib(int req, struct rt_addrin /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); + atomic_add_int(&rnh->rnh_gen, 1); /* * If it still failed to go into the tree, * then un-make it (this should be a function) Modified: projects/rtentry_cache/sys/netinet/in_pcb.c ============================================================================== --- projects/rtentry_cache/sys/netinet/in_pcb.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet/in_pcb.c Sat May 12 16:10:56 2012 (r235341) @@ -67,6 +67,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include #include #include #include @@ -128,6 +130,8 @@ static VNET_DEFINE(int, ipport_tcplastco #define V_ipport_tcplastcount VNET(ipport_tcplastcount) +extern u_int inpcb_rt_cache_enable; + static void in_pcbremlists(struct inpcb *inp); #ifdef INET static struct inpcb *in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, @@ -466,6 +470,180 @@ in_pcb_lport(struct inpcb *inp, struct i return (0); } + +/* + * in_rt_valid() both checks for, and attempts to ensure, that a cached route + * is present on a socket. It will call in_pcbrtalloc() if conditions are + * right (i.e. routing is enabled on the socket) and required (no route cached + * already or the cached rout is no longer valid). A route can only be + * installed if the caller passes the inp with a write lock, but the route may + * be used if a read lock is held. + */ + +int +in_rt_valid(struct inpcb *inp) +{ + struct radix_node_head *rnh; + + INP_WLOCK_ASSERT(inp); + + if (inpcb_rt_cache_enable == 0) + return (0); + if (inp->inp_socket == NULL) + return (0); + if (inp->inp_socket->so_options & SO_DONTROUTE) + return (0); + if (inp->inp_vflag & INP_IPV6PROTO) + rnh = rt_tables_get_rnh(0, AF_INET6); + else + rnh = rt_tables_get_rnh(inp->inp_inc.inc_fibnum, AF_INET); + if (inp->inp_rt != NULL && + (inp->inp_rt->rt_flags & RTF_UP) && + inp->inp_rt_gen == rnh->rnh_gen) + return (1); + /* + * This will handle selectively replacing one field or the other or + * merely updating the inpcb's routing generation count. + */ + in_pcbrtalloc(inp); + return (inp->inp_rt != NULL && inp->inp_rt->rt_ifp != NULL); +} + +/* + * in_pcbrtalloc will install or update a cached route on an inpcb. + */ + +void +in_pcbrtalloc(struct inpcb *inp) +{ + struct rtentry *rt; + struct radix_node_head *rnh = NULL; + int gen; + struct route_in6 iproute; +#ifdef INET6 + struct route_in6 *sro6 = NULL; + struct sockaddr_in6 *sin6 = NULL; +#endif +#ifdef INET + struct sockaddr_in *sin = NULL; + struct route *sro = NULL; + struct in_ifaddr *ia; +#endif + + INP_WLOCK_ASSERT(inp); + + if (inpcb_rt_cache_enable == 0) + return; + + if (inp->inp_socket->so_options & SO_DONTROUTE) + return; + + if (inp->inp_vflag & INP_IPV6PROTO) { +#ifdef INET6 + sro6 = &iproute; + bzero(sro6, sizeof(*sro6)); + rnh = rt_tables_get_rnh(0, AF_INET6); + sin6 = (struct sockaddr_in6 *)&sro6->ro_dst; + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_addr = inp->in6p_faddr; +#endif + } else { +#ifdef INET + sro = (struct route *)&iproute; + bzero(sro, sizeof(*sro)); + rnh = rt_tables_get_rnh(inp->inp_inc.inc_fibnum, AF_INET); + sin = (struct sockaddr_in *)&sro->ro_dst; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_addr.s_addr = inp->inp_faddr.s_addr; +#endif + + } + if (inp->inp_rt != NULL && + inp->inp_rt_gen == rnh->rnh_gen) { + KASSERT(inp->inp_rt->rt_flags & RTF_UP, + ("gen count unchanged but route invalid")); + rt = inp->inp_rt; + return; + } +resolve: + + gen = rnh->rnh_gen; + + if (inp->inp_vflag & INP_IPV6PROTO) { +#ifdef INET6 +#ifdef RADIX_MPATH + rtalloc_mpath((struct route *)ro, + ntohl(sin6->sin6_addr.s6_addr32[3])); +#else + sro6->ro_rt = rtalloc1(&((struct route *)sro6) + ->ro_dst, 0, 0UL); + if (sro6->ro_rt) + RT_UNLOCK(sro6->ro_rt); +#endif + rt = sro6->ro_rt; +#endif + } else { +#ifdef INET +#ifdef RADIX_MPATH + rtalloc_mpath_fib(sro, ntohl(faddr->s_addr), + inp->inp_inc.inc_fibnum); +#else + rtalloc_ign_fib(sro, 0, inp->inp_inc.inc_fibnum); +#endif + rt = sro->ro_rt; +#endif + } + + if (inp->inp_rt != NULL) { + if (rt == inp->inp_rt) { + /* The route is unchanged so we drop the added + * reference and update reference count. + */ + RTFREE(rt); + inp->inp_rt_gen = gen; + + /* The route has been validated and the generation + * count updated so we're done here. + */ + return; + } +#ifdef INET + /* Drop our reference to the old route */ + ia = ifatoia(inp->inp_rt->rt_ifa); + ifa_free(&ia->ia_ifa); + inp->inp_ifaddr = NULL; +#endif + RTFREE(inp->inp_rt); + inp->inp_rt = NULL; + } + + if (inp->inp_lle != NULL) { + LLE_FREE(inp->inp_lle); + inp->inp_lle = NULL; + } + if (rt == NULL) + return; + + if (gen != rnh->rnh_gen) { + /* + * The routing tree was updated some time after we read its + * generation counter. + */ + RTFREE(rt); + goto resolve; + } + + inp->inp_rt = rt; +#ifdef INET + ia = ifatoia(rt->rt_ifa); + ifa_ref(&ia->ia_ifa); + inp->inp_ifaddr = ia; +#endif + inp->inp_rt_gen = gen; +} + #endif /* INET || INET6 */ #ifdef INET @@ -662,6 +840,7 @@ in_pcbconnect_mbuf(struct inpcb *inp, st inp->inp_laddr.s_addr = laddr; inp->inp_faddr.s_addr = faddr; inp->inp_fport = fport; + in_pcbrehash_mbuf(inp, m); if (anonport) @@ -714,7 +893,7 @@ in_pcbladdr(struct inpcb *inp, struct in * Find out route to destination. */ if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) - in_rtalloc_ign(&sro, 0, inp->inp_inc.inc_fibnum); + rtalloc_ign_fib(&sro, 0, inp->inp_inc.inc_fibnum); /* * If we found a route, use the address corresponding to @@ -1034,6 +1213,19 @@ in_pcbdisconnect(struct inpcb *inp) INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); + if (inp->inp_rt != NULL) { + RTFREE(inp->inp_rt); + inp->inp_rt = NULL; + } + if (inp->inp_ifaddr != NULL) { + ifa_free(&inp->inp_ifaddr->ia_ifa); + inp->inp_ifaddr = NULL; + } + if (inp->inp_lle != NULL) { + LLE_FREE(inp->inp_lle); + inp->inp_lle = NULL; + } + inp->inp_faddr.s_addr = INADDR_ANY; inp->inp_fport = 0; in_pcbrehash(inp); @@ -1165,6 +1357,20 @@ in_pcbfree(struct inpcb *inp) INP_INFO_WLOCK_ASSERT(pcbinfo); INP_WLOCK_ASSERT(inp); + if (inp->inp_rt != NULL) { + RTFREE(inp->inp_rt); + inp->inp_rt = NULL; +#ifdef INET + KASSERT(inp->inp_ifaddr != NULL, ("route valid but ifaddr not set")); + ifa_free(&inp->inp_ifaddr->ia_ifa); + inp->inp_ifaddr = NULL; +#endif + } + if (inp->inp_lle != NULL) { + LLE_FREE(inp->inp_lle); + inp->inp_lle = NULL; + } + /* XXXRW: Do as much as possible here. */ #ifdef IPSEC if (inp->inp_sp != NULL) Modified: projects/rtentry_cache/sys/netinet/in_pcb.h ============================================================================== --- projects/rtentry_cache/sys/netinet/in_pcb.h Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet/in_pcb.h Sat May 12 16:10:56 2012 (r235341) @@ -141,6 +141,7 @@ struct icmp6_filter; * these fields that write locks be held on both the inpcb and global locks. * * Key: + * (a) - Atomically incremented * (c) - Constant after initialization * (g) - Protected by the pcbgroup lock * (i) - Protected by the inpcb lock @@ -179,6 +180,8 @@ struct inpcb { u_char inp_ip_minttl; /* (i) minimum TTL or drop */ uint32_t inp_flowid; /* (x) flow id / queue id */ u_int inp_refcount; /* (i) refcount */ + struct in_ifaddr *inp_ifaddr; /* (i) reference to the local ifaddr */ + u_int inp_rt_gen; /* (a) generation count of routing entry */ void *inp_pspare[5]; /* (x) route caching / general use */ u_int inp_ispare[6]; /* (x) route caching / user cookie / * general use */ @@ -537,8 +540,6 @@ void inp_4tuple_get(struct inpcb *inp, /* * Flags for inp_flags2. */ -#define INP_LLE_VALID 0x00000001 /* cached lle is valid */ -#define INP_RT_VALID 0x00000002 /* cached rtentry is valid */ #define INP_PCBGROUPWILD 0x00000004 /* in pcbgroup wildcard list */ #define INP_REUSEPORT 0x00000008 /* SO_REUSEPORT option is set */ @@ -632,6 +633,8 @@ void in_pcbdrop(struct inpcb *); void in_pcbfree(struct inpcb *); int in_pcbinshash(struct inpcb *); int in_pcbinshash_nopcbgroup(struct inpcb *); +void in_pcbrtalloc(struct inpcb *inp); +int in_rt_valid(struct inpcb *inp); struct inpcb * in_pcblookup_local(struct inpcbinfo *, struct in_addr, u_short, int, struct ucred *); Modified: projects/rtentry_cache/sys/netinet/ip_output.c ============================================================================== --- projects/rtentry_cache/sys/netinet/ip_output.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet/ip_output.c Sat May 12 16:10:56 2012 (r235341) @@ -146,7 +146,6 @@ ip_output(struct mbuf *m, struct mbuf *o if (ro == NULL) { ro = &iproute; bzero(ro, sizeof (*ro)); - #ifdef FLOWTABLE { struct flentry *fle; @@ -163,6 +162,9 @@ ip_output(struct mbuf *m, struct mbuf *o } } #endif + } else { + nortfree = 1; + ia = ro->ro_ia; } if (opt) { @@ -277,6 +279,7 @@ again: inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m)); #endif rte = ro->ro_rt; + nortfree = 0; } if (rte == NULL || rte->rt_ifp == NULL || @@ -672,9 +675,11 @@ passout: IPSTAT_INC(ips_fragmented); done: - if (ro == &iproute && ro->ro_rt && !nortfree) { + if (nortfree) + return (error); + + if (ro->ro_rt) RTFREE(ro->ro_rt); - } if (ia != NULL) ifa_free(&ia->ia_ifa); return (error); Modified: projects/rtentry_cache/sys/netinet/tcp_output.c ============================================================================== --- projects/rtentry_cache/sys/netinet/tcp_output.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet/tcp_output.c Sat May 12 16:10:56 2012 (r235341) @@ -169,6 +169,15 @@ tcp_output(struct tcpcb *tp) struct ip *ip = NULL; struct ipovly *ipov = NULL; struct tcphdr *th; +#ifdef INET + struct sockaddr_in *sin; + struct route iproute, *ro = NULL; +#endif +#ifdef INET6 + struct sockaddr_in6 *sin6; + struct route_in6 iproute6, *ro6 = NULL; +#endif + struct inpcb *inp; u_char opt[TCP_MAXOLEN]; unsigned ipoptlen, optlen, hdrlen; #ifdef IPSEC @@ -189,7 +198,8 @@ tcp_output(struct tcpcb *tp) isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; #endif - INP_WLOCK_ASSERT(tp->t_inpcb); + inp = tp->t_inpcb; + INP_WLOCK_ASSERT(inp); /* * Determine length of data that should be transmitted, @@ -1203,11 +1213,27 @@ timer: */ ip6->ip6_hlim = in6_selecthlim(tp->t_inpcb, NULL); + if (in_rt_valid(inp)) { + ro6 = &iproute6; + sin6 = (struct sockaddr_in6 *)&ro6->ro_dst; + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + memcpy(&sin6->sin6_addr.s6_addr, &inp->in6p_faddr.s6_addr, 16); + ro6->ro_rt = inp->inp_rt; + ro6->ro_lle = inp->inp_lle; + ro6->ro_flags |= RT_CACHING_CONTEXT; + } else + ro6 = NULL; + /* TODO: IPv6 IP6TOS_ECT bit on */ error = ip6_output(m, - tp->t_inpcb->in6p_outputopts, NULL, + tp->t_inpcb->in6p_outputopts, ro6, ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), NULL, NULL, tp->t_inpcb); + if (ro6 != NULL && ro6->ro_lle != NULL && + inp->inp_lle != ro6->ro_lle) + inp->inp_lle = ro6->ro_lle; + } #endif /* INET6 */ #if defined(INET) && defined(INET6) @@ -1231,9 +1257,25 @@ timer: if (V_path_mtu_discovery && tp->t_maxopd > V_tcp_minmss) ip->ip_off |= IP_DF; - error = ip_output(m, tp->t_inpcb->inp_options, NULL, + if (in_rt_valid(inp)) { + ro = &iproute; + sin = (struct sockaddr_in *)&ro->ro_dst; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_addr.s_addr = inp->inp_faddr.s_addr; + ro->ro_rt = inp->inp_rt; + ro->ro_lle = inp->inp_lle; + ro->ro_ia = inp->inp_ifaddr; + ro->ro_flags |= RT_CACHING_CONTEXT; + } else + ro = NULL; + + error = ip_output(m, tp->t_inpcb->inp_options, ro, ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0, tp->t_inpcb); + if (ro != NULL && ro->ro_lle != NULL && inp->inp_lle != ro->ro_lle) + inp->inp_lle = ro->ro_lle; + } #endif /* INET */ if (error) { Modified: projects/rtentry_cache/sys/netinet/tcp_usrreq.c ============================================================================== --- projects/rtentry_cache/sys/netinet/tcp_usrreq.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet/tcp_usrreq.c Sat May 12 16:10:56 2012 (r235341) @@ -1104,6 +1104,7 @@ tcp_connect(struct tcpcb *tp, struct soc goto out; } inp->inp_laddr = laddr; + in_pcbrtalloc(inp); in_pcbrehash(inp); INP_HASH_WUNLOCK(&V_tcbinfo); Modified: projects/rtentry_cache/sys/netinet6/in6_src.c ============================================================================== --- projects/rtentry_cache/sys/netinet6/in6_src.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet6/in6_src.c Sat May 12 16:10:56 2012 (r235341) @@ -662,7 +662,9 @@ selectroute(struct sockaddr_in6 *dstsock ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 || !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst))) { - RTFREE(ro->ro_rt); + + if (!(ro->ro_flags & RT_CACHING_CONTEXT)) + RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)NULL; } if (ro->ro_rt == (struct rtentry *)NULL) { @@ -696,7 +698,8 @@ selectroute(struct sockaddr_in6 *dstsock ifp = ro->ro_rt->rt_ifp; if (ifp == NULL) { /* can this really happen? */ - RTFREE(ro->ro_rt); + if (!(ro->ro_flags & RT_CACHING_CONTEXT)) + RTFREE(ro->ro_rt); ro->ro_rt = NULL; } } Modified: projects/rtentry_cache/sys/netinet6/ip6_forward.c ============================================================================== --- projects/rtentry_cache/sys/netinet6/ip6_forward.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet6/ip6_forward.c Sat May 12 16:10:56 2012 (r235341) @@ -627,7 +627,7 @@ skip_routing: #endif /* IPFIREWALL_FORWARD */ pass: - error = nd6_output(rt->rt_ifp, origifp, m, dst, rt); + error = nd6_output(rt->rt_ifp, origifp, m, dst, &rin6); if (error) { in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard); V_ip6stat.ip6s_cantforward++; Modified: projects/rtentry_cache/sys/netinet6/ip6_output.c ============================================================================== --- projects/rtentry_cache/sys/netinet6/ip6_output.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet6/ip6_output.c Sat May 12 16:10:56 2012 (r235341) @@ -981,7 +981,7 @@ passout: ia6->ia_ifa.if_obytes += m->m_pkthdr.len; ifa_free(&ia6->ia_ifa); } - error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); + error = nd6_output(ifp, origifp, m, dst, ro); goto done; } @@ -1120,7 +1120,7 @@ sendorfree: ia->ia_ifa.if_opackets++; ia->ia_ifa.if_obytes += m->m_pkthdr.len; } - error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); + error = nd6_output(ifp, origifp, m, dst, ro); } else m_freem(m); } Modified: projects/rtentry_cache/sys/netinet6/nd6.c ============================================================================== --- projects/rtentry_cache/sys/netinet6/nd6.c Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet6/nd6.c Sat May 12 16:10:56 2012 (r235341) @@ -1822,10 +1822,10 @@ nd6_slowtimo(void *arg) int nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, - struct sockaddr_in6 *dst, struct rtentry *rt0) + struct sockaddr_in6 *dst, struct route_in6 *ro) { - return (nd6_output_lle(ifp, origifp, m0, dst, rt0, NULL, NULL)); + return (nd6_output_lle(ifp, origifp, m0, dst, ro->ro_rt, ro->ro_lle, NULL)); } @@ -1851,6 +1851,7 @@ nd6_output_lle(struct ifnet *ifp, struct int error = 0; int flags = 0; int ip6len; + struct route ro; #ifdef INVARIANTS if (lle != NULL) { @@ -2078,7 +2079,9 @@ nd6_output_lle(struct ifnet *ifp, struct return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, NULL)); } - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, NULL); + ro.ro_rt = rt0; + ro.ro_lle = ln; + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, &ro); return (error); bad: Modified: projects/rtentry_cache/sys/netinet6/nd6.h ============================================================================== --- projects/rtentry_cache/sys/netinet6/nd6.h Sat May 12 16:08:05 2012 (r235340) +++ projects/rtentry_cache/sys/netinet6/nd6.h Sat May 12 16:10:56 2012 (r235341) @@ -408,7 +408,7 @@ int nd6_ioctl __P((u_long, caddr_t, stru struct llentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *, char *, int, int, int)); int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *, - struct sockaddr_in6 *, struct rtentry *)); + struct sockaddr_in6 *, struct route_in6 *)); int nd6_output_lle __P((struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *, struct rtentry *, struct llentry *, struct mbuf **));