Subject: Re: works in progress: route cache invalidation, RADIX_MPATH
To: None <tech-net@NetBSD.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 12/09/2006 03:04:30
--oTHb8nViIGeoXxdp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Dec 08, 2006 at 11:21:00PM -0600, David Young wrote:
> On Sat, Dec 09, 2006 at 01:09:16AM +0100, Joerg Sonnenberger wrote:
> > On Thu, Nov 16, 2006 at 01:33:30PM -0600, David Young wrote:
> > > * Route-cache invalidation
> > 
> > ftp://ftp.netbsd.org/pub/NetBSD/misc/joerg/rtcache.diff 
> > 
> > This is part one to actually do this. The difference to David's approach
> > is that I want to actually abstract the route cache (re)validation and
> > ultimately avoid doing the domain specific flushing.
> > 
> > The patch starts this by changing all the proper rtfree calls to the new
> > API and starts to adjust the various updates. The next part will add
> > rtcache_check() calls in the various places where the cached route is
> > accessed and enforcing the calls to rtcache_init(). 
> 
> Joerg,
> 
> I like what you have done here, but your work (and by that I mean the
> analysis of the code, and to a lesser extent, the subroutines extracted)
> and mine appear to be essentially the same.  I am going to commit my
> work, which I have tested and found to solve the problem it was designed
> to solve, and then begin the mechanical changes that are necessary to
> reconcile your patches with mine.  I hope to avoid impeding your work
> at abstracting the route cache, which is very desirable, but it may be
> necessary for me to sleep before I finish reconciling the patches.

I applied your patch manually.  Here are diffs against -current of
9 December.  I can compile GENERIC/i386, but that's not the best
compile-test.  I haven't tried running these patches, yet.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933

--oTHb8nViIGeoXxdp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="rtcache-2.diff"

Index: dist/ipf/netinet/ip_fil_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_fil_netbsd.c,v
retrieving revision 1.29
diff -p -u -u -p -r1.29 ip_fil_netbsd.c
--- dist/ipf/netinet/ip_fil_netbsd.c	9 Dec 2006 05:33:06 -0000	1.29
+++ dist/ipf/netinet/ip_fil_netbsd.c	9 Dec 2006 08:56:26 -0000
@@ -1424,9 +1424,7 @@ done:
 	else
 		fr_frouteok[1]++;
 
-	if (ro->ro_rt != NULL) {
-		rtflush(ro);
-	}
+	rtcache_free(ro);
 	*mpp = NULL;
 	return error;
 bad:
@@ -1521,9 +1519,7 @@ frdest_t *fdp;
 		}
 	}
 bad:
-	if (ro->ro_rt != NULL) {
-		rtflush((struct route *)ro);
-	}
+	rtcache_free((struct route *)ro);
 	return error;
 }
 #endif
Index: dist/pf/net/pf.c
===================================================================
RCS file: /cvsroot/src/sys/dist/pf/net/pf.c,v
retrieving revision 1.32
diff -p -u -u -p -r1.32 pf.c
--- dist/pf/net/pf.c	9 Dec 2006 05:33:06 -0000	1.32
+++ dist/pf/net/pf.c	9 Dec 2006 08:56:28 -0000
@@ -2736,14 +2736,14 @@ pf_calc_mss(struct pf_addr *addr, sa_fam
 #ifdef __OpenBSD__
 	rtalloc_noclone(rop, NO_CLONING);
 #else
-	rtalloc(rop);
+	rtcache_init(rop);
 #endif
-	rt = rop->ro_rt;
+	rt = rt;
 
-	if (rt && rt->rt_ifp) {
-		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
+	if (rop->ro_rt != NULL) {
+		mss = rop->ro_rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
 		mss = max(tcp_mssdflt, mss);
-		RTFREE(rt);
+		rtcache_free(rop);
 	}
 	mss = min(mss, offer);
 	mss = max(mss, 64);		/* sanity - at least max opt space */
@@ -5302,14 +5302,18 @@ pf_routable(struct pf_addr *addr, sa_fam
 
 #ifdef __OpenBSD__
 	rtalloc_noclone((struct route *)&ro, NO_CLONING);
-#else
-	rtalloc((struct route *)&ro);
-#endif
 
 	if (ro.ro_rt != NULL) {
-		rtflush((struct route *)&ro);
+		RTFREE((struct route *)&ro);
 		return (1);
 	}
+#else
+	rtcache_init((struct route *)&ro);
+	if (ro.ro_rt != NULL) {
+		rtcache_free((struct route *)&ro);
+		return (1);
+	}
+#endif
 
 	return (0);
 }
@@ -5318,6 +5322,7 @@ int
 pf_rtlabel_match(struct pf_addr *addr, sa_family_t af,
     struct pf_addr_wrap *aw)
 {
+#if 0
 	struct sockaddr_in	*dst;
 #ifdef INET6
 	struct sockaddr_in6	*dst6;
@@ -5350,7 +5355,7 @@ pf_rtlabel_match(struct pf_addr *addr, s
 #ifdef __OpenBSD__
 	rtalloc_noclone((struct route *)&ro, NO_CLONING);
 #else
-	rtalloc((struct route *)&ro);
+	rtcache_init((struct route *)&ro);
 #endif
 
 	if (ro.ro_rt != NULL) {
@@ -5362,6 +5367,9 @@ pf_rtlabel_match(struct pf_addr *addr, s
 	}
 
 	return (ret);
+#else
+	return 0;
+#endif
 }
 
 #ifdef INET
@@ -5427,8 +5435,8 @@ pf_route(struct mbuf **m, struct pf_rule
 	dst->sin_addr = ip->ip_dst;
 
 	if (r->rt == PF_FASTROUTE) {
-		rtalloc(ro);
-		if (ro->ro_rt == 0) {
+		rtcache_init(ro);
+		if (ro->ro_rt == NULL) {
 			ipstat.ips_noroute++;
 			goto bad;
 		}
@@ -5575,8 +5583,8 @@ pf_route(struct mbuf **m, struct pf_rule
 done:
 	if (r->rt != PF_DUPTO)
 		*m = NULL;
-	if (ro == &iproute && ro->ro_rt)
-		rtflush(ro);
+	if (ro != NULL)
+		rtcache_free(ro);
 	return;
 
 bad:
Index: net/if_etherip.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_etherip.c,v
retrieving revision 1.3
diff -p -u -u -p -r1.3 if_etherip.c
--- net/if_etherip.c	24 Nov 2006 01:04:30 -0000	1.3
+++ net/if_etherip.c	9 Dec 2006 08:56:29 -0000
@@ -216,7 +216,6 @@ etherip_attach(struct device *parent, st
 #endif
 	sc->sc_src = NULL;
 	sc->sc_dst = NULL;
-	sc->sc_route_expire = 0;
 
 	/*
 	 * In order to obtain unique initial Ethernet address on a host,
Index: net/if_etherip.h
===================================================================
RCS file: /cvsroot/src/sys/net/if_etherip.h,v
retrieving revision 1.1
diff -p -u -u -p -r1.1 if_etherip.h
--- net/if_etherip.h	23 Nov 2006 04:07:07 -0000	1.1
+++ net/if_etherip.h	9 Dec 2006 08:56:29 -0000
@@ -56,7 +56,6 @@ struct etherip_softc {
                 struct route_in6 scr_ro6;       /* cached inet6 route         */
 #endif
         } sc_scr;
-        long sc_route_expire;
 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
         void *sc_si;                            /* softintr handle            */
 #endif
Index: net/if_gre.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_gre.c,v
retrieving revision 1.79
diff -p -u -u -p -r1.79 if_gre.c
--- net/if_gre.c	9 Dec 2006 06:32:58 -0000	1.79
+++ net/if_gre.c	9 Dec 2006 08:56:29 -0000
@@ -1023,8 +1023,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 				closef(sc->sc_fp, l);
 				sc->sc_fp = NULL;
 			}
-			if (sc->route.ro_rt != NULL)
-				rtflush(&sc->route);
+			rtcache_free(&sc->route);
 			if (sc->sc_proto == IPPROTO_UDP)
 				error = gre_kick(sc);
 			else if (gre_compute_route(sc) == 0)
Index: net/if_stf.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_stf.c,v
retrieving revision 1.55
diff -p -u -u -p -r1.55 if_stf.c
--- net/if_stf.c	9 Dec 2006 05:33:06 -0000	1.55
+++ net/if_stf.c	9 Dec 2006 08:56:29 -0000
@@ -418,17 +418,16 @@ stf_output(struct ifnet *ifp, struct mbu
 
 	dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst;
 	if (dst4->sin_family != AF_INET ||
-	    bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) {
-		/* cache route doesn't match */
+	    bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0)
+		rtcache_free(&sc->sc_ro);
+	else
+		rtcache_check(&sc->sc_ro);
+
+	if (sc->sc_ro.ro_rt == NULL) {
 		dst4->sin_family = AF_INET;
 		dst4->sin_len = sizeof(struct sockaddr_in);
 		bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr));
-		if (sc->sc_ro.ro_rt != NULL)
-			rtflush(&sc->sc_ro);
-	}
-
-	if (sc->sc_ro.ro_rt == NULL) {
-		rtalloc(&sc->sc_ro);
+		rtcache_init(&sc->sc_ro);
 		if (sc->sc_ro.ro_rt == NULL) {
 			m_freem(m);
 			ifp->if_oerrors++;
@@ -436,6 +435,14 @@ stf_output(struct ifnet *ifp, struct mbu
 		}
 	}
 
+	/* If the route constitutes infinite encapsulation, punt. */
+	if (sc->sc_ro.ro_rt->rt_ifp == ifp) {
+		rtcache_free(&sc->sc_ro);
+		m_freem(m);
+		ifp->if_oerrors++;
+		return ENETUNREACH;
+	}
+
 	ifp->if_opackets++;
 	return ip_output(m, NULL, &sc->sc_ro, 0,
 	    (struct ip_moptions *)NULL, (struct socket *)NULL);
Index: net/route.c
===================================================================
RCS file: /cvsroot/src/sys/net/route.c,v
retrieving revision 1.82
diff -p -u -u -p -r1.82 route.c
--- net/route.c	9 Dec 2006 05:33:06 -0000	1.82
+++ net/route.c	9 Dec 2006 08:56:32 -0000
@@ -1084,3 +1084,30 @@ rt_timer_timer(void *arg)
 
 	callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
 }
+
+void
+rtcache_init(struct route *ro)
+{
+	ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
+}
+
+void
+rtcache_init_noclone(struct route *ro)
+{
+	ro->ro_rt = rtalloc1(&ro->ro_dst, 0);
+}
+
+void
+rtcache_free(struct route *ro)
+{
+	if (ro->ro_rt != NULL)
+		rtfree(ro->ro_rt);
+	ro->ro_rt = NULL;
+}
+
+void
+rtcache_update(struct route *ro)
+{
+	rtcache_free(ro);
+	rtcache_init(ro);
+}
Index: net/route.h
===================================================================
RCS file: /cvsroot/src/sys/net/route.h,v
retrieving revision 1.48
diff -p -u -u -p -r1.48 route.h
--- net/route.h	9 Dec 2006 05:33:06 -0000	1.48
+++ net/route.h	9 Dec 2006 08:56:32 -0000
@@ -334,5 +334,21 @@ RTFREE(struct rtentry *rt)
 struct ifaddr	*rt_get_ifa(struct rtentry *);
 void	rt_replace_ifa(struct rtentry *, struct ifaddr *);
 
+void	rtcache_init(struct route *);
+void	rtcache_init_noclone(struct route *);
+void	rtcache_update(struct route *);
+void	rtcache_free(struct route *);
+
+static inline void
+rtcache_check(struct route *ro)
+{
+	/* XXX The rt_ifp check should be asserted. */
+	if (ro->ro_rt != NULL &&
+	    ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+	     ro->ro_rt->rt_ifp == NULL))
+		rtcache_update(ro);
+	KASSERT(ro->ro_rt == NULL || ro->ro_rt->rt_ifp != NULL);
+}
+
 #endif /* _KERNEL */
 #endif /* !_NET_ROUTE_H_ */
Index: netatalk/ddp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netatalk/ddp_input.c,v
retrieving revision 1.11
diff -p -u -u -p -r1.11 ddp_input.c
--- netatalk/ddp_input.c	11 Dec 2005 12:24:54 -0000	1.11
+++ netatalk/ddp_input.c	9 Dec 2006 08:56:33 -0000
@@ -267,16 +267,12 @@ ddp_input(m, ifp, elh, phase)
 			m_freem(m);
 			return;
 		}
-		if (forwro.ro_rt &&
-		    (satosat(&forwro.ro_dst)->sat_addr.s_net !=
-		     to.sat_addr.s_net ||
-		     satosat(&forwro.ro_dst)->sat_addr.s_node !=
-		     to.sat_addr.s_node)) {
-			RTFREE(forwro.ro_rt);
-			forwro.ro_rt = (struct rtentry *) 0;
-		}
-		if (forwro.ro_rt == (struct rtentry *) 0 ||
-		    forwro.ro_rt->rt_ifp == (struct ifnet *) 0) {
+		if (satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net ||
+		    satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node)
+			rtcache_free(&forwro);
+		else
+			rtcache_check(&forwro);
+		if (forwro.ro_rt == NULL) {
 			bzero(&forwro.ro_dst, sizeof(struct sockaddr_at));
 			forwro.ro_dst.sa_len = sizeof(struct sockaddr_at);
 			forwro.ro_dst.sa_family = AF_APPLETALK;
@@ -284,7 +280,7 @@ ddp_input(m, ifp, elh, phase)
 			    to.sat_addr.s_net;
 			satosat(&forwro.ro_dst)->sat_addr.s_node =
 			    to.sat_addr.s_node;
-			rtalloc(&forwro);
+			rtcache_init(&forwro);
 		}
 		if (to.sat_addr.s_net !=
 		    satosat(&forwro.ro_dst)->sat_addr.s_net &&
Index: netinet/in_gif.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_gif.c,v
retrieving revision 1.52
diff -p -u -u -p -r1.52 in_gif.c
--- netinet/in_gif.c	9 Dec 2006 05:33:04 -0000	1.52
+++ netinet/in_gif.c	9 Dec 2006 08:56:33 -0000
@@ -180,28 +180,27 @@ in_gif_output(struct ifnet *ifp, int fam
 	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
 
 	if (dst->sin_family != sin_dst->sin_family ||
-	    !in_hosteq(dst->sin_addr, sin_dst->sin_addr)) {
-		/* cache route doesn't match */
+	    !in_hosteq(dst->sin_addr, sin_dst->sin_addr))
+		rtcache_free(&sc->gif_ro);
+	else
+		rtcache_check(&sc->gif_ro);
+
+	if (sc->gif_ro.ro_rt == NULL) {
 		bzero(dst, sizeof(*dst));
 		dst->sin_family = sin_dst->sin_family;
 		dst->sin_len = sizeof(struct sockaddr_in);
 		dst->sin_addr = sin_dst->sin_addr;
-		if (sc->gif_ro.ro_rt != NULL)
-			rtflush(&sc->gif_ro);
-	}
-
-	if (sc->gif_ro.ro_rt == NULL) {
-		rtalloc(&sc->gif_ro);
+		rtcache_init(&sc->gif_ro);
 		if (sc->gif_ro.ro_rt == NULL) {
 			m_freem(m);
 			return ENETUNREACH;
 		}
+	}
 
-		/* if it constitutes infinite encapsulation, punt. */
-		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
-			m_freem(m);
-			return ENETUNREACH;	/*XXX*/
-		}
+	/* if it constitutes infinite encapsulation, punt. */
+	if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+		m_freem(m);
+		return ENETUNREACH;	/*XXX*/
 	}
 
 	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
@@ -409,8 +408,7 @@ in_gif_detach(struct gif_softc *sc)
 	if (error == 0)
 		sc->encap_cookie4 = NULL;
 
-	if (sc->gif_ro.ro_rt != NULL)
-		rtflush(&sc->gif_ro);
+	rtcache_free(&sc->gif_ro);
 
 	return error;
 }
Index: netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.111
diff -p -u -u -p -r1.111 in_pcb.c
--- netinet/in_pcb.c	9 Dec 2006 05:33:04 -0000	1.111
+++ netinet/in_pcb.c	9 Dec 2006 08:56:33 -0000
@@ -495,8 +495,7 @@ in_pcbdetach(void *v)
 	sofree(so);
 	if (inp->inp_options)
 		(void)m_free(inp->inp_options);
-	if (inp->inp_route.ro_rt != NULL)
-		rtflush(&inp->inp_route);
+	rtcache_free(&inp->inp_route);
 	ip_freemoptions(inp->inp_moptions);
 	s = splnet();
 	in_pcbstate(inp, INP_ATTACHED);
@@ -688,7 +687,7 @@ in_losing(struct inpcb *inp)
 		 * A new route can be allocated
 		 * the next time output is attempted.
 		 */
-		rtflush(&inp->inp_route);
+		rtcache_free(&inp->inp_route);
 	}
 }
 
@@ -703,8 +702,7 @@ in_rtchange(struct inpcb *inp, int errno
 	if (inp->inp_af != AF_INET)
 		return;
 
-	if (inp->inp_route.ro_rt != NULL)
-		rtflush(&inp->inp_route);
+	rtcache_free(&inp->inp_route);
 	/* XXX SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
 }
 
@@ -881,15 +879,16 @@ in_pcbrtentry(struct inpcb *inp)
 
 	ro = &inp->inp_route;
 
-	if (ro->ro_rt != NULL && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-	    !in_hosteq(satosin(&ro->ro_dst)->sin_addr, inp->inp_faddr)))
-		rtflush(ro);
+	if (!in_hosteq(satosin(&ro->ro_dst)->sin_addr, inp->inp_faddr))
+		rtcache_free(ro);
+	else
+		rtcache_check(ro);
 	if (ro->ro_rt == NULL && !in_nullhost(inp->inp_faddr)) {
 		bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
 		ro->ro_dst.sa_family = AF_INET;
 		ro->ro_dst.sa_len = sizeof(ro->ro_dst);
 		satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
-		rtalloc(ro);
+		rtcache_init(ro);
 	}
 	return ro->ro_rt;
 }
@@ -907,19 +906,20 @@ in_selectsrc(struct sockaddr_in *sin, st
 	 * Note that we should check the address family of the cached
 	 * destination, in case of sharing the cache with IPv6.
 	 */
-	if (ro->ro_rt != NULL &&
-	    (ro->ro_dst.sa_family != AF_INET ||
+	if (ro->ro_dst.sa_family != AF_INET ||
 	    !in_hosteq(satosin(&ro->ro_dst)->sin_addr, sin->sin_addr) ||
-	    soopts & SO_DONTROUTE))
-		rtflush(ro);
+	    soopts & SO_DONTROUTE)
+		rtcache_free(ro);
+	else
+		rtcache_check(ro);
 	if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/
-	    (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
+	    ro->ro_rt == NULL) {
 		/* No route yet, so try to acquire one */
 		bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
 		ro->ro_dst.sa_family = AF_INET;
 		ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
 		satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
-		rtalloc(ro);
+		rtcache_init(ro);
 	}
 	/*
 	 * If we found a route, use the address
Index: netinet/ip_etherip.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_etherip.c,v
retrieving revision 1.2
diff -p -u -u -p -r1.2 ip_etherip.c
--- netinet/ip_etherip.c	6 Dec 2006 21:42:38 -0000	1.2
+++ netinet/ip_etherip.c	9 Dec 2006 08:56:33 -0000
@@ -153,34 +153,30 @@ ip_etherip_output(struct ifnet *ifp, str
 		m = m_pullup(m, sizeof(struct ip));
 	memcpy(mtod(m, struct ip *), &iphdr, sizeof(struct ip));
 
-	if (sc->sc_route_expire - time_second <= 0 ||
-	    dst->sin_family != sin_dst->sin_family ||
+	if (dst->sin_family != sin_dst->sin_family ||
 	    !in_hosteq(dst->sin_addr, sin_dst->sin_addr)) {
-		/* cache route doesn't match */
+		rtcache_free(&sc->sc_ro);
+	} else {
+		rtcache_check(&sc->sc_ro);
+	}
+
+	if (sc->sc_ro.ro_rt == NULL) {
 		memset(dst, 0, sizeof(struct sockaddr_in));
 		dst->sin_family = sin_dst->sin_family;
 		dst->sin_len    = sizeof(struct sockaddr_in);
 		dst->sin_addr   = sin_dst->sin_addr;
-		if (sc->sc_ro.ro_rt) {
-			RTFREE(sc->sc_ro.ro_rt);
-			sc->sc_ro.ro_rt = NULL;
-		}
-	}
-
-	if (sc->sc_ro.ro_rt == NULL) {
-		rtalloc(&sc->sc_ro);
+		rtcache_init(&sc->sc_ro);
 		if (sc->sc_ro.ro_rt == NULL) {
 			m_freem(m);
 			return ENETUNREACH ;
 		}
+	}
 
-		/* if it constitutes infinite encapsulation, punt. */
-		if (sc->sc_ro.ro_rt->rt_ifp == ifp) {
-			m_freem(m);
-			return ENETUNREACH;     /*XXX*/
-		}
-
-		sc->sc_route_expire = time_second + ETHERIP_ROUTE_TTL;
+	/* if it constitutes infinite encapsulation, punt. */
+	if (sc->sc_ro.ro_rt->rt_ifp == ifp) {
+		rtcache_free(&sc->sc_ro);
+		m_freem(m);
+		return ENETUNREACH;     /*XXX*/
 	}
 
 	error = ip_output(m, NULL, &sc->sc_ro, 0, NULL, NULL);
Index: netinet/ip_flow.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_flow.c,v
retrieving revision 1.37
diff -p -u -u -p -r1.37 ip_flow.c
--- netinet/ip_flow.c	9 Dec 2006 05:33:04 -0000	1.37
+++ netinet/ip_flow.c	9 Dec 2006 08:56:33 -0000
@@ -196,9 +196,9 @@ ipflow_fastforward(struct mbuf *m)
 	/*
 	 * Route and interface still up?
 	 */
+	rtcache_check(&ipf->ipf_ro);
 	rt = ipf->ipf_ro.ro_rt;
-	if (rt == NULL || (rt->rt_flags & RTF_UP) == 0 ||
-	    (rt->rt_ifp->if_flags & IFF_UP) == 0)
+	if (rt == NULL || (rt->rt_ifp->if_flags & IFF_UP) == 0)
 		return 0;
 
 	/*
@@ -269,6 +269,7 @@ ipflow_fastforward(struct mbuf *m)
 static void
 ipflow_addstats(struct ipflow *ipf)
 {
+	rtcache_check(&ipf->ipf_ro);
 	if (ipf->ipf_ro.ro_rt != NULL)
 		ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
 	ipstat.ips_cantforward += ipf->ipf_errors + ipf->ipf_dropped;
@@ -290,8 +291,7 @@ ipflow_free(struct ipflow *ipf)
 	IPFLOW_REMOVE(ipf);
 	splx(s);
 	ipflow_addstats(ipf);
-	if (ipf->ipf_ro.ro_rt != NULL)
-		rtflush(&ipf->ipf_ro);
+	rtcache_free(&ipf->ipf_ro);
 	ipflow_inuse--;
 	s = splnet();
 	pool_put(&ipflow_pool, ipf);
@@ -307,14 +307,12 @@ ipflow_reap(int just_one)
 
 		ipf = LIST_FIRST(&ipflowlist);
 		while (ipf != NULL) {
-			struct route *ro = &ipf->ipf_ro;
-
 			/*
 			 * If this no longer points to a valid route
 			 * reclaim it.
 			 */
-			if (ro->ro_rt == NULL ||
-			    (ro->ro_rt->rt_flags & RTF_UP) == 0)
+			rtcache_check(&ipf->ipf_ro);
+			if (ipf->ipf_ro.ro_rt == NULL)
 				goto done;
 			/*
 			 * choose the one that's been least recently
@@ -339,8 +337,7 @@ ipflow_reap(int just_one)
 		IPFLOW_REMOVE(ipf);
 		splx(s);
 		ipflow_addstats(ipf);
-		if (ipf->ipf_ro.ro_rt != NULL)
-			rtflush(&ipf->ipf_ro);
+		rtcache_free(&ipf->ipf_ro);
 		if (just_one)
 			return ipf;
 		pool_put(&ipflow_pool, ipf);
@@ -356,6 +353,7 @@ ipflow_slowtimo(void)
 
 	for (ipf = LIST_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) {
 		next_ipf = LIST_NEXT(ipf, ipf_list);
+		rtcache_check(&ipf->ipf_ro);
 		if (PRT_SLOW_ISEXPIRED(ipf->ipf_timer) ||
 		    ipf->ipf_ro.ro_rt == NULL) {
 			ipflow_free(ipf);
@@ -406,8 +404,7 @@ ipflow_create(const struct route *ro, st
 		IPFLOW_REMOVE(ipf);
 		splx(s);
 		ipflow_addstats(ipf);
-		if (ipf->ipf_ro.ro_rt != NULL)
-			rtflush(&ipf->ipf_ro);
+		rtcache_free(&ipf->ipf_ro);
 		ipf->ipf_uses = ipf->ipf_last_uses = 0;
 		ipf->ipf_errors = ipf->ipf_dropped = 0;
 	}
Index: netinet/ip_icmp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.106
diff -p -u -u -p -r1.106 ip_icmp.c
--- netinet/ip_icmp.c	9 Dec 2006 05:33:04 -0000	1.106
+++ netinet/ip_icmp.c	9 Dec 2006 08:56:34 -0000
@@ -730,8 +730,7 @@ icmp_reflect(struct mbuf *m)
 		errornum = 0;
 		sin = in_selectsrc(&sin_dst, &icmproute, 0, NULL, &errornum);
 		/* errornum is never used */
-		if (icmproute.ro_rt != NULL)
-			rtflush(&icmproute);
+		rtcache_free(&icmproute);
 		/* check to make sure sin is a source address on rcvif */
 		if (sin) {
 			t = sin->sin_addr;
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.239
diff -p -u -u -p -r1.239 ip_input.c
--- netinet/ip_input.c	9 Dec 2006 05:33:04 -0000	1.239
+++ netinet/ip_input.c	9 Dec 2006 08:56:34 -0000
@@ -1679,17 +1679,19 @@ ip_rtaddr(struct in_addr dst)
 
 	sin = satosin(&ipforward_rt.ro_dst);
 
-	if (ipforward_rt.ro_rt == NULL || !in_hosteq(dst, sin->sin_addr)) {
-		if (ipforward_rt.ro_rt != NULL)
-			rtflush(&ipforward_rt);
+	if (!in_hosteq(dst, sin->sin_addr))
+		rtcache_free(&ipforward_rt);
+	else
+		rtcache_check(&ipforward_rt);
+	if (ipforward_rt.ro_rt != NULL) {
 		sin->sin_family = AF_INET;
 		sin->sin_len = sizeof(*sin);
 		sin->sin_addr = dst;
 
-		rtalloc(&ipforward_rt);
+		rtcache_init(&ipforward_rt);
+		if (ipforward_rt.ro_rt == NULL)
+			return NULL;
 	}
-	if (ipforward_rt.ro_rt == NULL)
-		return NULL;
 	return ifatoia(ipforward_rt.ro_rt->rt_ifa);
 }
 
@@ -1871,21 +1873,22 @@ ip_forward(struct mbuf *m, int srcrt)
 	}
 
 	sin = satosin(&ipforward_rt.ro_dst);
-	if ((rt = ipforward_rt.ro_rt) == NULL ||
-	    !in_hosteq(ip->ip_dst, sin->sin_addr)) {
-		if (ipforward_rt.ro_rt != NULL)
-			rtflush(&ipforward_rt);
+	if (!in_hosteq(ip->ip_dst, sin->sin_addr))
+		rtcache_free(&ipforward_rt);
+	else
+		rtcache_check(&ipforward_rt);
+	if (ipforward_rt.ro_rt == NULL) {
 		sin->sin_family = AF_INET;
 		sin->sin_len = sizeof(struct sockaddr_in);
 		sin->sin_addr = ip->ip_dst;
 
-		rtalloc(&ipforward_rt);
+		rtcache_init(&ipforward_rt);
 		if (ipforward_rt.ro_rt == NULL) {
 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, dest, 0);
 			return;
 		}
-		rt = ipforward_rt.ro_rt;
 	}
+	rt = ipforward_rt.ro_rt;
 
 	/*
 	 * Save at most 68 bytes of the packet in case
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_output.c,v
retrieving revision 1.170
diff -p -u -u -p -r1.170 ip_output.c
--- netinet/ip_output.c	9 Dec 2006 05:33:04 -0000	1.170
+++ netinet/ip_output.c	9 Dec 2006 08:56:34 -0000
@@ -299,10 +299,10 @@ ip_output(struct mbuf *m0, ...)
 	 * The address family should also be checked in case of sharing the
 	 * cache with IPv6.
 	 */
-	if (ro->ro_rt != NULL && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-	    dst->sin_family != AF_INET ||
-	    !in_hosteq(dst->sin_addr, ip->ip_dst)))
-		rtflush(ro);
+	if (dst->sin_family != AF_INET || !in_hosteq(dst->sin_addr, ip->ip_dst))
+		rtcache_free(ro);
+	else
+		rtcache_check(ro);
 	if (ro->ro_rt == NULL) {
 		bzero(dst, sizeof(*dst));
 		dst->sin_family = AF_INET;
@@ -330,7 +330,7 @@ ip_output(struct mbuf *m0, ...)
 		IFP_TO_IA(ifp, ia);
 	} else {
 		if (ro->ro_rt == NULL)
-			rtalloc(ro);
+			rtcache_init(ro);
 		if (ro->ro_rt == NULL) {
 			ipstat.ips_noroute++;
 			error = EHOSTUNREACH;
@@ -963,8 +963,8 @@ spd_done:
 	if (error == 0)
 		ipstat.ips_fragmented++;
 done:
-	if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt != NULL)
-		rtflush(ro);
+	if (ro == &iproute && (flags & IP_ROUTETOIF) == 0)
+		rtcache_free(ro);
 
 #ifdef IPSEC
 	if (sp != NULL) {
@@ -1764,13 +1764,13 @@ ip_setmoptions(int optname, struct ip_mo
 			dst->sin_len = sizeof(*dst);
 			dst->sin_family = AF_INET;
 			dst->sin_addr = mreq->imr_multiaddr;
-			rtalloc(&ro);
+			rtcache_init(&ro);
 			if (ro.ro_rt == NULL) {
 				error = EADDRNOTAVAIL;
 				break;
 			}
 			ifp = ro.ro_rt->rt_ifp;
-			rtflush(&ro);
+			rtcache_free(&ro);
 		} else {
 			ifp = ip_multicast_if(&mreq->imr_interface, NULL);
 		}
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v
retrieving revision 1.258
diff -p -u -u -p -r1.258 tcp_input.c
--- netinet/tcp_input.c	9 Dec 2006 05:33:04 -0000	1.258
+++ netinet/tcp_input.c	9 Dec 2006 08:56:35 -0000
@@ -3208,8 +3208,7 @@ do {									\
 do {									\
 	if ((sc)->sc_ipopts)						\
 		(void) m_free((sc)->sc_ipopts);				\
-	if ((sc)->sc_route4.ro_rt != NULL)				\
-		rtflush(&(sc)->sc_route4);				\
+	rtcache_free(&(sc)->sc_route4);					\
 	if (callout_invoking(&(sc)->sc_timer))				\
 		(sc)->sc_flags |= SCF_DEAD;				\
 	else								\
Index: netinet6/frag6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/frag6.c,v
retrieving revision 1.32
diff -p -u -u -p -r1.32 frag6.c
--- netinet6/frag6.c	9 Dec 2006 05:33:07 -0000	1.32
+++ netinet6/frag6.c	9 Dec 2006 08:56:35 -0000
@@ -200,17 +200,17 @@ frag6_input(struct mbuf **mp, int *offp,
 #ifdef IN6_IFSTAT_STRICT
 	/* find the destination interface of the packet. */
 	dst = (struct sockaddr_in6 *)&ro.ro_dst;
-	if (ro.ro_rt != NULL &&
-	    ((ro.ro_rt->rt_flags & RTF_UP) == 0 ||
-	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst)))
-		rtflush((struct route *)&ro);
+	if (!IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))
+		rtcache_free((struct route *)&ro);
+	else
+		rtcache_check((struct route *)&ro);
 	if (ro.ro_rt == NULL) {
 		bzero(dst, sizeof(*dst));
 		dst->sin6_family = AF_INET6;
 		dst->sin6_len = sizeof(struct sockaddr_in6);
 		dst->sin6_addr = ip6->ip6_dst;
+		rtcache_init((struct route *)&ro);
 	}
-	rtalloc((struct route *)&ro);
 	if (ro.ro_rt != NULL && ro.ro_rt->rt_ifa != NULL)
 		dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp;
 #else
@@ -738,10 +738,8 @@ frag6_slowtimo()
 	 * make sure we notice eventually, even if forwarding only for one
 	 * destination and the cache is never replaced.
 	 */
-	if (ip6_forward_rt.ro_rt != NULL)
-		rtflush(&ip6_forward_rt);
-	if (ipsrcchk_rt.ro_rt != NULL)
-		rtflush(&ipsrcchk_rt);
+	rtcache_free(&ip6_forward_rt);
+	rtcache_free(&ipsrcchk_rt);
 #endif
 
 	splx(s);
Index: netinet6/icmp6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/icmp6.c,v
retrieving revision 1.124
diff -p -u -u -p -r1.124 icmp6.c
--- netinet6/icmp6.c	9 Dec 2006 05:33:07 -0000	1.124
+++ netinet6/icmp6.c	9 Dec 2006 08:56:36 -0000
@@ -2066,8 +2066,7 @@ icmp6_reflect(m, off)
 
 		bzero(&ro, sizeof(ro));
 		src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &e);
-		if (ro.ro_rt != NULL)
-			rtflush((struct route *)&ro);
+		rtcache_free((struct route *)&ro);
 		if (src == NULL) {
 			nd6log((LOG_DEBUG,
 			    "icmp6_reflect: source can't be determined: "
Index: netinet6/in6_gif.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_gif.c,v
retrieving revision 1.46
diff -p -u -u -p -r1.46 in6_gif.c
--- netinet6/in6_gif.c	9 Dec 2006 05:33:07 -0000	1.46
+++ netinet6/in6_gif.c	9 Dec 2006 08:56:36 -0000
@@ -184,28 +184,27 @@ in6_gif_output(ifp, family, m)
 	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
 
 	if (dst->sin6_family != sin6_dst->sin6_family ||
-	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
-		/* cache route doesn't match */
+	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr))
+		rtcache_free((struct route *)&sc->gif_ro6);
+	else
+		rtcache_check((struct route *)&sc->gif_ro6);
+
+	if (sc->gif_ro6.ro_rt == NULL) {
 		bzero(dst, sizeof(*dst));
 		dst->sin6_family = sin6_dst->sin6_family;
 		dst->sin6_len = sizeof(struct sockaddr_in6);
 		dst->sin6_addr = sin6_dst->sin6_addr;
-		if (sc->gif_ro6.ro_rt != NULL)
-			rtflush((struct route *)&sc->gif_ro6);
-	}
-
-	if (sc->gif_ro6.ro_rt == NULL) {
-		rtalloc((struct route *)&sc->gif_ro6);
+		rtcache_init((struct route *)&sc->gif_ro6);
 		if (sc->gif_ro6.ro_rt == NULL) {
 			m_freem(m);
 			return ENETUNREACH;
 		}
+	}
 
-		/* if it constitutes infinite encapsulation, punt. */
-		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
-			m_freem(m);
-			return ENETUNREACH;	/* XXX */
-		}
+	/* if it constitutes infinite encapsulation, punt. */
+	if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+		m_freem(m);
+		return ENETUNREACH;	/* XXX */
 	}
 
 #ifdef IPV6_MINMTU
@@ -418,8 +417,7 @@ in6_gif_detach(sc)
 	if (error == 0)
 		sc->encap_cookie6 = NULL;
 
-	if (sc->gif_ro6.ro_rt != NULL)
-		rtflush((struct route *)&sc->gif_ro6);
+	rtcache_free((struct route *)&sc->gif_ro6);
 
 	return error;
 }
@@ -474,6 +472,6 @@ in6_gif_ctlinput(cmd, sa, d)
 		dst6 = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
 		/* XXX scope */
 		if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr))
-			rtflush((struct route *)&sc->gif_ro6);
+			rtcache_free((struct route *)&sc->gif_ro6);
 	}
 }
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.79
diff -p -u -u -p -r1.79 in6_pcb.c
--- netinet6/in6_pcb.c	9 Dec 2006 05:33:07 -0000	1.79
+++ netinet6/in6_pcb.c	9 Dec 2006 08:56:36 -0000
@@ -513,15 +513,13 @@ in6_pcbdetach(in6p)
 	if (in6p->in6p_options)
 		m_freem(in6p->in6p_options);
 	if (in6p->in6p_outputopts) {
-		if (in6p->in6p_outputopts->ip6po_rthdr &&
-		    in6p->in6p_outputopts->ip6po_route.ro_rt != NULL)
-			rtflush((struct route *)&in6p->in6p_outputopts->ip6po_route);
+		if (in6p->in6p_outputopts->ip6po_rthdr != NULL)
+			rtcache_free((struct route *)&in6p->in6p_outputopts->ip6po_route);
 		if (in6p->in6p_outputopts->ip6po_m)
 			(void)m_free(in6p->in6p_outputopts->ip6po_m);
 		free(in6p->in6p_outputopts, M_IP6OPT);
 	}
-	if (in6p->in6p_route.ro_rt != NULL)
-		rtflush((struct route *)&in6p->in6p_route);
+	rtcache_free((struct route *)&in6p->in6p_route);
 	ip6_freemoptions(in6p->in6p_moptions);
 	s = splnet();
 	in6_pcbstate(in6p, IN6P_ATTACHED);
@@ -825,7 +823,7 @@ in6_losing(in6p)
 		 * A new route can be allocated
 		 * the next time output is attempted.
 		 */
-		rtflush((struct route *)&in6p->in6p_route);
+		rtcache_free((struct route *)&in6p->in6p_route);
 	}
 }
 
@@ -839,8 +837,7 @@ in6_rtchange(struct in6pcb *in6p, int er
 	if (in6p->in6p_af != AF_INET6)
 		return;
 
-	if (in6p->in6p_route.ro_rt != NULL)
-		rtflush((struct route *)&in6p->in6p_route);
+	rtcache_free((struct route *)&in6p->in6p_route);
 }
 
 struct in6pcb *
@@ -944,9 +941,10 @@ in6_pcbrtentry(in6p)
 	if (in6p->in6p_af != AF_INET6)
 		return (NULL);
 
-	if (ro->ro_rt != NULL && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-	    !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &in6p->in6p_faddr)))
-		rtflush((struct route *)ro);
+	if (!IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &in6p->in6p_faddr))
+		rtcache_free((struct route *)ro);
+	else
+		rtcache_check((struct route *)ro);
 #ifdef INET
 	if (ro->ro_rt == NULL && IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
 		struct sockaddr_in *dst = (struct sockaddr_in *)&ro->ro_dst;
@@ -956,7 +954,7 @@ in6_pcbrtentry(in6p)
 		dst->sin_len = sizeof(struct sockaddr_in);
 		bcopy(&in6p->in6p_faddr.s6_addr32[3], &dst->sin_addr,
 		    sizeof(dst->sin_addr));
-		rtalloc((struct route *)ro);
+		rtcache_init((struct route *)ro);
 	} else
 #endif
 	if (ro->ro_rt == NULL && !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
@@ -964,7 +962,7 @@ in6_pcbrtentry(in6p)
 		dst6->sin6_family = AF_INET6;
 		dst6->sin6_len = sizeof(struct sockaddr_in6);
 		dst6->sin6_addr = in6p->in6p_faddr;
-		rtalloc((struct route *)ro);
+		rtcache_init((struct route *)ro);
 	}
 	return ro->ro_rt;
 }
Index: netinet6/in6_src.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_src.c,v
retrieving revision 1.32
diff -p -u -u -p -r1.32 in6_src.c
--- netinet6/in6_src.c	9 Dec 2006 05:33:08 -0000	1.32
+++ netinet6/in6_src.c	9 Dec 2006 08:56:36 -0000
@@ -667,27 +667,22 @@ selectroute(dstsock, opts, mopts, ro, re
 		 * by that address must be a neighbor of the sending host.
 		 */
 		ron = &opts->ip6po_nextroute;
+		/* XXX Careful, Joerg, this checks RTF_GATEWAY! --dyoung */
 		if ((ron->ro_rt != NULL &&
-		    (ron->ro_rt->rt_flags & (RTF_UP | RTF_GATEWAY)) !=
-		    RTF_UP) ||
+		    (ron->ro_rt->rt_flags & RTF_GATEWAY) != 0) ||
 		    !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr,
 		    &sin6_next->sin6_addr)) {
-			if (ron->ro_rt != NULL)
-				rtflush((struct route *)ron);
-			*satosin6(&ron->ro_dst) = *sin6_next;
-		}
+			rtcache_free((struct route *)ron);
+		} else
+			rtcache_check((struct route *)ron);
 		if (ron->ro_rt == NULL) {
-			rtalloc((struct route *)ron); /* multi path case? */
-			if (ron->ro_rt == NULL ||
-			    (ron->ro_rt->rt_flags & RTF_GATEWAY)) {
-				if (ron->ro_rt != NULL)
-					rtflush((struct route *)ron);
-				error = EHOSTUNREACH;
-				goto done;
-			}
+			*satosin6(&ron->ro_dst) = *sin6_next;
+			rtcache_init((struct route *)ron); /* multi path case?*/
 		}
-		if (!nd6_is_addr_neighbor(sin6_next, ron->ro_rt->rt_ifp)) {
-			rtflush((struct route *)ron);
+		if (ron->ro_rt == NULL ||
+		    (ron->ro_rt->rt_flags & RTF_GATEWAY) != 0 ||
+		    !nd6_is_addr_neighbor(sin6_next, ron->ro_rt->rt_ifp)) {
+			rtcache_free((struct route *)ron);
 			error = EHOSTUNREACH;
 			goto done;
 		}
@@ -709,12 +704,11 @@ selectroute(dstsock, opts, mopts, ro, re
 	 * cached destination, in case of sharing the cache with IPv4.
 	 */
 	if (ro != NULL) {
-		if (ro->ro_rt != NULL &&
-		    (!(ro->ro_rt->rt_flags & RTF_UP) ||
-		     ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 ||
-		     !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
-		     dst)))
-			rtflush((struct route *)ro);
+		if (((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 ||
+		    !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst))
+			rtcache_free((struct route *)ro);
+		else
+			rtcache_check((struct route *)ro);
 		if (ro->ro_rt == NULL) {
 			struct sockaddr_in6 *sa6;
 
@@ -723,25 +717,21 @@ selectroute(dstsock, opts, mopts, ro, re
 			sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
 			*sa6 = *dstsock;
 			sa6->sin6_scope_id = 0;
-			if (clone) {
 #ifdef RADIX_MPATH
+			if (clone) {
 				rtalloc_mpath((struct route *)ro,
 				    ntohl(sa6->sin6_addr.s6_addr32[3]));
-#else
-				rtalloc((struct route *)ro);
-#endif /* RADIX_MPATH */
 			} else {
-#ifdef RADIX_MPATH
 				/* XXX rtalloc_mpath1(, 0) */
 				rtalloc_mpath((struct route *)ro,
 				    ntohl(sa6->sin6_addr.s6_addr32[3]));
+			}
 #else
-				ro->ro_rt =
-				    rtalloc1(&((struct route *)ro)->ro_dst, 0);
-				if (ro->ro_rt != NULL)
-					rtcache((struct route *)ro);
+			if (clone)
+				rtcache_init((struct route *)ro);
+			else
+				rtcache_init_noclone((struct route *)ro);
 #endif /* RADIX_MPATH */
-			}
 		}
 
 		/*
@@ -751,14 +741,10 @@ selectroute(dstsock, opts, mopts, ro, re
 		if (opts && opts->ip6po_nexthop)
 			goto done;
 
-		if (ro->ro_rt != NULL) {
-			ifp = ro->ro_rt->rt_ifp;
-
-			if (ifp == NULL) /* can this really happen? */
-				rtflush((struct route *)ro);
-		}
 		if (ro->ro_rt == NULL)
 			error = EHOSTUNREACH;
+		else
+			ifp = ro->ro_rt->rt_ifp;
 		rt = ro->ro_rt;
 
 		/*
Index: netinet6/ip6_etherip.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_etherip.c,v
retrieving revision 1.2
diff -p -u -u -p -r1.2 ip6_etherip.c
--- netinet6/ip6_etherip.c	6 Dec 2006 21:42:38 -0000	1.2
+++ netinet6/ip6_etherip.c	9 Dec 2006 08:56:36 -0000
@@ -158,34 +158,28 @@ ip6_etherip_output(struct ifnet *ifp, st
 		return ENETUNREACH;
 	}
 
-	if (sc->sc_route_expire - time_second <= 0 ||
-	    dst->sin6_family != sin6_dst->sin6_family ||
-	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
-		/* cache route doesn't match */
+	if (dst->sin6_family != sin6_dst->sin6_family ||
+	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr))
+		rtcache_free((struct route *)&sc->sc_ro6);
+	else
+		rtcache_check((struct route *)&sc->sc_ro6);
+
+	if (sc->sc_ro6.ro_rt == NULL) {
 		memset(dst, 0, sizeof(*dst));
 		dst->sin6_family = sin6_dst->sin6_family;
 		dst->sin6_len    = sizeof(struct sockaddr_in6);
 		dst->sin6_addr   = sin6_dst->sin6_addr;
-		if (sc->sc_ro6.ro_rt) {
-			RTFREE(sc->sc_ro6.ro_rt);
-			sc->sc_ro6.ro_rt = NULL;
-		}
-	}
-
-	if (sc->sc_ro6.ro_rt == NULL) {
-		rtalloc((struct route *)&sc->sc_ro6);
+		rtcache_init((struct route *)&sc->sc_ro6);
 		if (sc->sc_ro6.ro_rt == NULL) {
 			m_freem(m);
 			return ENETUNREACH;
 		}
-
-		/* if it constitutes infinite encapsulation, punt. */
-		if (sc->sc_ro.ro_rt->rt_ifp == ifp) {
-			m_freem(m);
-			return ENETUNREACH;     /* XXX */
-		}
-
-		sc->sc_route_expire = time_second + ETHERIP_ROUTE_TTL;
+	}
+	/* if it constitutes infinite encapsulation, punt. */
+	if (sc->sc_ro.ro_rt->rt_ifp == ifp) {
+		rtcache_free((struct route *)&sc->sc_ro6);
+		m_freem(m);
+		return ENETUNREACH;     /* XXX */
 	}
 
 	/*
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_forward.c,v
retrieving revision 1.51
diff -p -u -u -p -r1.51 ip6_forward.c
--- netinet6/ip6_forward.c	9 Dec 2006 05:33:08 -0000	1.51
+++ netinet6/ip6_forward.c	9 Dec 2006 08:56:36 -0000
@@ -338,14 +338,10 @@ ip6_forward(m, srcrt)
 		/*
 		 * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
 		 */
-		if (ip6_forward_rt.ro_rt == NULL ||
-		    (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
-			if (ip6_forward_rt.ro_rt != NULL)
-				rtflush((struct route *)&ip6_forward_rt);
-			/* this probably fails but give it a try again */
-			rtalloc((struct route *)&ip6_forward_rt);
-		}
+		rtcache_check((struct route *)&ip6_forward_rt);
 
+		if (ip6_forward_rt.ro_rt == NULL)
+			rtcache_init((struct route *)&ip6_forward_rt);
 		if (ip6_forward_rt.ro_rt == NULL) {
 			ip6stat.ip6s_noroute++;
 			/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
@@ -356,16 +352,19 @@ ip6_forward(m, srcrt)
 			m_freem(m);
 			return;
 		}
-	} else if ((rt = ip6_forward_rt.ro_rt) == NULL ||
-		 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
-		if (ip6_forward_rt.ro_rt != NULL)
-			rtflush((struct route *)&ip6_forward_rt);
-		bzero(dst, sizeof(*dst));
-		dst->sin6_len = sizeof(struct sockaddr_in6);
-		dst->sin6_family = AF_INET6;
-		dst->sin6_addr = ip6->ip6_dst;
+	} else {
+		if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr))
+			rtcache_free((struct route *)&ip6_forward_rt);
+		else
+			rtcache_check((struct route *)&ip6_forward_rt);
+		if (ip6_forward_rt.ro_rt == NULL) {
+			bzero(dst, sizeof(*dst));
+			dst->sin6_len = sizeof(struct sockaddr_in6);
+			dst->sin6_family = AF_INET6;
+			dst->sin6_addr = ip6->ip6_dst;
+			rtcache_init((struct route *)&ip6_forward_rt);
+		}
 
-		rtalloc((struct route *)&ip6_forward_rt);
 		if (ip6_forward_rt.ro_rt == NULL) {
 			ip6stat.ip6s_noroute++;
 			/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.92
diff -p -u -u -p -r1.92 ip6_input.c
--- netinet6/ip6_input.c	9 Dec 2006 05:33:08 -0000	1.92
+++ netinet6/ip6_input.c	9 Dec 2006 08:56:36 -0000
@@ -461,7 +461,7 @@ ip6_input(m)
 		if (ip6_forward_rt.ro_rt != NULL) {
 			/* route is down or destination is different */
 			ip6stat.ip6s_forward_cachemiss++;
-			rtflush((struct route *)&ip6_forward_rt);
+			rtcache_free((struct route *)&ip6_forward_rt);
 		}
 
 		bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6));
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.108
diff -p -u -u -p -r1.108 ip6_output.c
--- netinet6/ip6_output.c	9 Dec 2006 05:33:08 -0000	1.108
+++ netinet6/ip6_output.c	9 Dec 2006 08:56:37 -0000
@@ -1137,10 +1137,11 @@ sendorfree:
 		ip6stat.ip6s_fragmented++;
 
 done:
-	if (ro == &ip6route && ro->ro_rt != NULL)
-		rtflush((struct route *)ro);
-	else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt != NULL)
-		rtflush((struct route *)ro_pmtu);
+	/* XXX Second if is invariant? */
+	if (ro == &ip6route)
+		rtcache_free((struct route *)ro);
+	else if (ro_pmtu == &ip6route)
+		rtcache_free((struct route *)ro_pmtu);
 
 #ifdef IPSEC
 	if (sp != NULL)
@@ -1376,17 +1377,16 @@ ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup,
 		/* The first hop and the final destination may differ. */
 		struct sockaddr_in6 *sa6_dst =
 		    (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
-		if (ro_pmtu->ro_rt != NULL &&
-		    ((ro_pmtu->ro_rt->rt_flags & RTF_UP) == 0 ||
-		      !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst)))
-			rtflush((struct route *)ro_pmtu);
+		if (!IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst))
+			rtcache_free((struct route *)ro_pmtu);
+		else
+			rtcache_check((struct route *)ro_pmtu);
 		if (ro_pmtu->ro_rt == NULL) {
 			bzero(sa6_dst, sizeof(*sa6_dst)); /* for safety */
 			sa6_dst->sin6_family = AF_INET6;
 			sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
 			sa6_dst->sin6_addr = *dst;
-
-			rtalloc((struct route *)ro_pmtu);
+			rtcache_init((struct route *)ro_pmtu);
 		}
 	}
 	if (ro_pmtu->ro_rt != NULL) {
@@ -2330,8 +2330,7 @@ ip6_clearpktopts(struct ip6_pktopts *pkt
 	if (optname == -1 || optname == IPV6_TCLASS)
 		pktopt->ip6po_tclass = -1;
 	if (optname == -1 || optname == IPV6_NEXTHOP) {
-		if (pktopt->ip6po_nextroute.ro_rt != NULL)
-			rtflush((struct route *)&pktopt->ip6po_nextroute);
+		rtcache_free((struct route *)&pktopt->ip6po_nextroute);
 		if (pktopt->ip6po_nexthop)
 			free(pktopt->ip6po_nexthop, M_IP6OPT);
 		pktopt->ip6po_nexthop = NULL;
@@ -2350,8 +2349,7 @@ ip6_clearpktopts(struct ip6_pktopts *pkt
 		if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
 			free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
 		pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
-		if (pktopt->ip6po_route.ro_rt != NULL)
-			rtflush((struct route *)&pktopt->ip6po_route);
+		rtcache_free((struct route *)&pktopt->ip6po_route);
 	}
 	if (optname == -1 || optname == IPV6_DSTOPTS) {
 		if (pktopt->ip6po_dest2)
@@ -2588,7 +2586,7 @@ ip6_setmoptions(optname, im6op, m)
 				break;
 			}
 			ifp = ro.ro_rt->rt_ifp;
-			rtflush((struct route *)&ro);
+			rtcache_free((struct route *)&ro);
 		} else {
 			/*
 			 * If the interface is specified, validate it.
Index: netinet6/ipsec.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ipsec.c,v
retrieving revision 1.112
diff -p -u -u -p -r1.112 ipsec.c
--- netinet6/ipsec.c	9 Dec 2006 05:33:08 -0000	1.112
+++ netinet6/ipsec.c	9 Dec 2006 08:56:37 -0000
@@ -2732,20 +2732,20 @@ ipsec4_output(struct ipsec_output_state 
 			state->ro = &isr->sav->sah->sa_route;
 			state->dst = (struct sockaddr *)&state->ro->ro_dst;
 			dst4 = (struct sockaddr_in *)state->dst;
-			if (state->ro->ro_rt != NULL &&
-			    ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-			     dst4->sin_addr.s_addr != ip->ip_dst.s_addr))
-				rtflush((struct route *)state->ro);
+			if (dst4->sin_addr.s_addr != ip->ip_dst.s_addr)
+				rtcache_free((struct route *)state->ro);
+			else
+				rtcache_check((struct route *)state->ro);
 			if (state->ro->ro_rt == NULL) {
 				dst4->sin_family = AF_INET;
 				dst4->sin_len = sizeof(*dst4);
 				dst4->sin_addr = ip->ip_dst;
-				rtalloc(state->ro);
-			}
-			if (state->ro->ro_rt == NULL) {
-				ipstat.ips_noroute++;
-				error = EHOSTUNREACH;
-				goto bad;
+				rtcache_init(state->ro);
+				if (state->ro->ro_rt == NULL) {
+					ipstat.ips_noroute++;
+					error = EHOSTUNREACH;
+					goto bad;
+				}
 			}
 
 			/* adjust state->dst if tunnel endpoint is offlink */
@@ -3120,23 +3120,22 @@ ipsec6_output_tunnel(struct ipsec_output
 			state->ro = &isr->sav->sah->sa_route;
 			state->dst = (struct sockaddr *)&state->ro->ro_dst;
 			dst6 = (struct sockaddr_in6 *)state->dst;
-			if (state->ro->ro_rt != NULL &&
-			    ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-			     !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
-			                         &ip6->ip6_dst)))
-				rtflush((struct route *)state->ro);
+			if (!IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))
+				rtcache_free((struct route *)state->ro);
+			else
+				rtcache_check((struct route *)state->ro);
 			if (state->ro->ro_rt == NULL) {
 				bzero(dst6, sizeof(*dst6));
 				dst6->sin6_family = AF_INET6;
 				dst6->sin6_len = sizeof(*dst6);
 				dst6->sin6_addr = ip6->ip6_dst;
-				rtalloc(state->ro);
-			}
-			if (state->ro->ro_rt == NULL) {
-				ip6stat.ip6s_noroute++;
-				ipsec6stat.out_noroute++;
-				error = EHOSTUNREACH;
-				goto bad;
+				rtcache_init(state->ro);
+				if (state->ro->ro_rt == NULL) {
+					ip6stat.ip6s_noroute++;
+					ipsec6stat.out_noroute++;
+					error = EHOSTUNREACH;
+					goto bad;
+				}
 			}
 
 			/* adjust state->dst if tunnel endpoint is offlink */
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.67
diff -p -u -u -p -r1.67 nd6_nbr.c
--- netinet6/nd6_nbr.c	9 Dec 2006 05:33:08 -0000	1.67
+++ netinet6/nd6_nbr.c	9 Dec 2006 08:56:37 -0000
@@ -527,13 +527,11 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, d
 	icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
 	icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
 
-	if (ro.ro_rt != NULL)		/* we don't cache this route. */
-		rtflush((struct route *)&ro);
+	rtcache_free((struct route *)&ro);
 	return;
 
   bad:
-	if (ro.ro_rt != NULL)
-		rtflush((struct route *)&ro);
+	rtcache_free((struct route *)&ro);
 	m_freem(m);
 	return;
 }
@@ -1005,13 +1003,11 @@ nd6_na_output(ifp, daddr6_0, taddr6, fla
 	icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
 	icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
 
-	if (ro.ro_rt != NULL)		/* we don't cache this route. */
-		rtflush((struct route *)&ro);
+	rtcache_free((struct route *)&ro);
 	return;
 
   bad:
-	if (ro.ro_rt != NULL)
-		rtflush((struct route *)&ro);
+	rtcache_free((struct route *)&ro);
 	m_freem(m);
 	return;
 }
Index: netipsec/ipsec_output.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_output.c,v
retrieving revision 1.18
diff -p -u -u -p -r1.18 ipsec_output.c
--- netipsec/ipsec_output.c	9 Dec 2006 05:33:09 -0000	1.18
+++ netipsec/ipsec_output.c	9 Dec 2006 08:56:38 -0000
@@ -741,22 +741,22 @@ ipsec6_output_tunnel(
 		state->ro = &isr->sav->sah->sa_route;
 		state->dst = (struct sockaddr *)&state->ro->ro_dst;
 		dst6 = (struct sockaddr_in6 *)state->dst;
-		if (state->ro->ro_rt != NULL &&
-		    ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-		     !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst)))
-			rtflush(state->ro);
+		if (!IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))
+			rtcache_free(state->ro);
+		else
+			rtcache_check(state->ro);
 		if (state->ro->ro_rt == NULL) {
 			bzero(dst6, sizeof(*dst6));
 			dst6->sin6_family = AF_INET6;
 			dst6->sin6_len = sizeof(*dst6);
 			dst6->sin6_addr = ip6->ip6_dst;
-			rtalloc(state->ro);
-		}
-		if (state->ro->ro_rt == NULL) {
-			ip6stat.ip6s_noroute++;
-			newipsecstat.ips_out_noroute++;
-			error = EHOSTUNREACH;
-			goto bad;
+			rtcache_init(state->ro);
+			if (state->ro->ro_rt == NULL) {
+				ip6stat.ip6s_noroute++;
+				newipsecstat.ips_out_noroute++;
+				error = EHOSTUNREACH;
+				goto bad;
+			}
 		}
 
 		/* adjust state->dst if tunnel endpoint is offlink */
Index: netipsec/key.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/key.c,v
retrieving revision 1.31
diff -p -u -u -p -r1.31 key.c
--- netipsec/key.c	9 Dec 2006 05:33:09 -0000	1.31
+++ netipsec/key.c	9 Dec 2006 08:56:39 -0000
@@ -2818,8 +2818,7 @@ key_delsah(sah)
 		return;
 	}
 
-	if (sah->sa_route.ro_rt != NULL)
-		rtflush(&sah->sa_route);
+	rtcache_free(&sah->sa_route);
 
 	/* remove from tree of SA index */
 	if (__LIST_CHAINED(sah))
@@ -7537,9 +7536,9 @@ key_sa_routechange(dst)
 
 	LIST_FOREACH(sah, &sahtree, chain) {
 		ro = &sah->sa_route;
-		if (ro->ro_rt != NULL && dst->sa_len == ro->ro_dst.sa_len
-		 && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0)
-			rtflush(ro);
+		if (dst->sa_len == ro->ro_dst.sa_len &&
+		    bcmp(dst, &ro->ro_dst, dst->sa_len) == 0)
+			rtcache_free(ro);
 	}
 
 	return;
Index: netiso/clnp_er.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/clnp_er.c,v
retrieving revision 1.19
diff -p -u -u -p -r1.19 clnp_er.c
--- netiso/clnp_er.c	9 Dec 2006 05:33:09 -0000	1.19
+++ netiso/clnp_er.c	9 Dec 2006 08:56:39 -0000
@@ -378,8 +378,7 @@ bad:
 
 done:
 	/* free route if it is a temp */
-	if (route.ro_rt != NULL)
-		rtflush((struct route *)&route);
+	rtcache_free((struct route *)&route);
 }
 
 int
Index: netiso/clnp_raw.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/clnp_raw.c,v
retrieving revision 1.25
diff -p -u -u -p -r1.25 clnp_raw.c
--- netiso/clnp_raw.c	9 Dec 2006 05:33:09 -0000	1.25
+++ netiso/clnp_raw.c	9 Dec 2006 08:56:39 -0000
@@ -313,8 +313,7 @@ clnp_usrreq(struct socket *so, int req, 
 	case PRU_DETACH:
 		if (rp->risop_isop.isop_options)
 			m_freem(rp->risop_isop.isop_options);
-		if (rp->risop_isop.isop_route.ro_rt != NULL)
-			rtflush((struct route *)&rp->risop_isop.isop_route);
+		rtcache_free((struct route *)&rp->risop_isop.isop_route);
 		if (rp->risop_rcb.rcb_laddr)
 			rp->risop_rcb.rcb_laddr = 0;
 		/* free clnp cached hdr if necessary */
Index: netiso/clnp_subr.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/clnp_subr.c,v
retrieving revision 1.23
diff -p -u -u -p -r1.23 clnp_subr.c
--- netiso/clnp_subr.c	9 Dec 2006 05:33:09 -0000	1.23
+++ netiso/clnp_subr.c	9 Dec 2006 08:56:39 -0000
@@ -402,8 +402,7 @@ done:
 	/*
 	 *	Free route
 	 */
-	if (route.ro_rt != NULL)
-		rtflush((struct route *)&route);
+	rtcache_free((struct route *)&route);
 }
 
 #ifdef	notdef
@@ -468,8 +467,7 @@ clnp_route(
 	if (flags & SO_DONTROUTE) {
 		struct iso_ifaddr *ia;
 
-		if (ro->ro_rt != NULL)
-			rtflush((struct route *)ro);
+		rtcache_free((struct route *)ro);
 		bzero((caddr_t) & ro->ro_dst, sizeof(ro->ro_dst));
 		bcopy((caddr_t) dst, (caddr_t) & ro->ro_dst.siso_addr,
 		      1 + (unsigned) dst->isoa_len);
@@ -488,26 +486,10 @@ clnp_route(
 	 *	If there is a cached route, check that it is still up and to
 	 *	the same destination. If not, free it and try again.
 	 */
-	if (ro->ro_rt != NULL && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-	  (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
-#ifdef ARGO_DEBUG
-		if (argo_debug[D_ROUTE]) {
-			printf("clnp_route: freeing old route: ro->ro_rt %p\n",
-			    ro->ro_rt);
-			printf("clnp_route: old route refcnt: 0x%x\n",
-			    ro->ro_rt->rt_refcnt);
-		}
-#endif
-
-		/* free old route entry */
-		rtflush((struct route *)ro);
-	} else {
-#ifdef ARGO_DEBUG
-		if (argo_debug[D_ROUTE]) {
-			printf("clnp_route: OK route exists\n");
-		}
-#endif
-	}
+	if (bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len) != 0)
+		rtcache_free((struct route *)ro);
+	else
+		rtcache_check((struct route *)ro);
 
 	if (ro->ro_rt == NULL) {
 		/* set up new route structure */
@@ -522,10 +504,10 @@ clnp_route(
 			    clnp_iso_addrp(dst));
 		}
 #endif
-		rtalloc((struct route *)ro);
+		rtcache_init((struct route *)ro);
+		if (ro->ro_rt == NULL)
+			return (ENETUNREACH);	/* rtalloc failed */
 	}
-	if (ro->ro_rt == NULL)
-		return (ENETUNREACH);	/* rtalloc failed */
 	ro->ro_rt->rt_use++;
 	if (ifa)
 		if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
Index: netiso/if_eon.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/if_eon.c,v
retrieving revision 1.53
diff -p -u -u -p -r1.53 if_eon.c
--- netiso/if_eon.c	9 Dec 2006 05:33:09 -0000	1.53
+++ netiso/if_eon.c	9 Dec 2006 08:56:39 -0000
@@ -221,18 +221,15 @@ eoniphdr(struct eon_iphdr *hdr, const vo
 	sin->sin_family = AF_INET;
 	sin->sin_len = sizeof(*sin);
 	(void)memcpy(&sin->sin_addr, loc, sizeof(struct in_addr));
-	/*
-	 * If there is a cached route,
-	 * check that it is to the same destination
-	 * and is still up.  If not, free it and try again.
-	 */
+	/* XXX Does this check make any sense? */
+	rtcache_check(ro);
 	if (ro->ro_rt != NULL) {
 		struct sockaddr_in *dst = satosin(rt_key(ro->ro_rt));
-		if ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
-		    sin->sin_addr.s_addr != dst->sin_addr.s_addr)
-			rtflush(ro);
+		if (sin->sin_addr.s_addr != dst->sin_addr.s_addr)
+			rtcache_free(ro);
 	}
-	rtalloc(ro);
+	if (ro->ro_rt == NULL)
+		rtcache_init(ro);
 	if (ro->ro_rt != NULL)
 		ro->ro_rt->rt_use++;
 	hdr->ei_ip.ip_dst = sin->sin_addr;
@@ -277,8 +274,7 @@ eonrtrequest(int cmd, struct rtentry *rt
 	case RTM_DELETE:
 		if (el) {
 			remque(&(el->el_qhdr));
-			if (el->el_iproute.ro_rt != NULL)
-				rtflush(&el->el_iproute);
+			rtcache_free(&el->el_iproute);
 			Free(el);
 			rt->rt_llinfo = 0;
 		}
Index: netiso/iso_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/iso_pcb.c,v
retrieving revision 1.34
diff -p -u -u -p -r1.34 iso_pcb.c
--- netiso/iso_pcb.c	9 Dec 2006 05:33:09 -0000	1.34
+++ netiso/iso_pcb.c	9 Dec 2006 08:56:39 -0000
@@ -511,8 +511,7 @@ iso_pcbdetach(void *v)
 		printf("iso_pcbdetach 3 \n");
 	}
 #endif
-	if (isop->isop_route.ro_rt != NULL)
-		rtflush((struct route *)&isop->isop_route);
+	rtcache_free((struct route *)&isop->isop_route);
 #ifdef ARGO_DEBUG
 	if (argo_debug[D_ISO]) {
 		printf("iso_pcbdetach 3.1\n");
Index: netiso/tp_iso.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/tp_iso.c,v
retrieving revision 1.26
diff -p -u -u -p -r1.26 tp_iso.c
--- netiso/tp_iso.c	9 Dec 2006 05:33:09 -0000	1.26
+++ netiso/tp_iso.c	9 Dec 2006 08:56:39 -0000
@@ -467,8 +467,7 @@ tpclnp_output_dg(struct mbuf *m0, ...)
 	/*
 	 *	Free route allocated by clnp (if the route was indeed allocated)
 	 */
-	if (tmppcb.isop_route.ro_rt != NULL)
-		rtflush((struct route *)&tmppcb.isop_route);
+	rtcache_free((struct route *)&tmppcb.isop_route);
 
 	return (err);
 }
Index: netkey/key.c
===================================================================
RCS file: /cvsroot/src/sys/netkey/key.c,v
retrieving revision 1.147
diff -p -u -u -p -r1.147 key.c
--- netkey/key.c	9 Dec 2006 05:33:09 -0000	1.147
+++ netkey/key.c	9 Dec 2006 08:56:40 -0000
@@ -2829,8 +2829,7 @@ key_delsah(sah)
 		return;
 	}
 
-	if (sah->sa_route.ro_rt != NULL)
-		rtflush(&(struct route *)sah->sa_route);
+	rtcache_free(&(struct route *)sah->sa_route);
 
 	/* remove from tree of SA index */
 	if (__LIST_CHAINED(sah))
@@ -8232,9 +8231,9 @@ key_sa_routechange(dst)
 
 	LIST_FOREACH(sah, &sahtree, chain) {
 		ro = &sah->sa_route;
-		if (ro->ro_rt != NULL && dst->sa_len == ro->ro_dst.sa_len &&
+		if (dst->sa_len == ro->ro_dst.sa_len &&
 		    bcmp(dst, &ro->ro_dst, dst->sa_len) == 0)
-			rtflush(ro);
+			rtcache_free(ro);
 	}
 
 	return;

--oTHb8nViIGeoXxdp--