Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 May 2012 16:10:57 +0000 (UTC)
From:      Kip Macy <kmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r235341 - in projects/rtentry_cache/sys: net netinet netinet6
Message-ID:  <201205121610.q4CGAvvT041410@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <vm/uma.h>
 
 #include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_llatbl.h>
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/vnet.h>
@@ -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 **));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205121610.q4CGAvvT041410>