cvs commit: src/sys/netinet in_gif.c

SUZUKI Shinsuke suz at crl.hitachi.co.jp
Mon Dec 6 23:18:03 PST 2004


>>>>> On Mon, 6 Dec 2004 19:02:43 +0000 (UTC)
>>>>> glebius at FreeBSD.org(Gleb Smirnoff)  said:

>   - Make route cacheing optional, configurable via IFF_LINK0 flag.
>   - Turn it off by default.
>   Revision  Changes    Path
>   1.27      +6 -0      src/sys/netinet/in_gif.c

Three comments, and one proposal.

- please comment this change in share/man/man4/gif.4

- you need the same fix to sys/netinet6/in6_gif.c (for IPv4 over IPv6
  tunnel)
  
- it seems like sys/net/if_stf.c also needs the similar fix
  (I haven't confirmed it though, I'll check it later)

- Here's a patch to update route cache periodically, to prevent
  unexpected gif failure due to a stale route cache.  Is it okay to
  commit it together with your change?

-------------- next part --------------
Index: net/if_gif.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_gif.h,v
retrieving revision 1.15
diff -u -u -r1.15 if_gif.h
--- net/if_gif.h	5 Apr 2004 16:55:15 -0000	1.15
+++ net/if_gif.h	7 Dec 2004 04:53:39 -0000
@@ -70,6 +70,7 @@
 	const struct encaptab *encap_cookie6;
 	void		*gif_netgraph;	/* ng_gif(4) netgraph node info */
 	LIST_ENTRY(gif_softc) gif_list; /* all gif's are linked */
+	time_t rtcache_expire;	/* expiration time of the cached route */
 };
 
 #define gif_ro gifsc_gifscr.gifscr_ro
Index: netinet/in_gif.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_gif.c,v
retrieving revision 1.27
diff -u -u -r1.27 in_gif.c
--- netinet/in_gif.c	6 Dec 2004 19:02:43 -0000	1.27
+++ netinet/in_gif.c	7 Dec 2004 04:53:39 -0000
@@ -83,6 +83,7 @@
 };
 
 static int ip_gif_ttl = GIF_TTL;
+static int in_gif_rtcachettl = 300; /* XXX appropriate value? configurable? */
 SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
 	&ip_gif_ttl,	0, "");
 
@@ -99,6 +100,7 @@
 	struct ip iphdr;	/* capsule IP header, host byte ordered */
 	int proto, error;
 	u_int8_t tos;
+	struct timeval mono_time;
 
 	if (sin_src == NULL || sin_dst == NULL ||
 	    sin_src->sin_family != AF_INET ||
@@ -174,23 +176,38 @@
 	}
 	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
 
-	if (dst->sin_family != sin_dst->sin_family ||
-	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
-		/* cache route doesn't match */
-		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) {
-			RTFREE(sc->gif_ro.ro_rt);
-			sc->gif_ro.ro_rt = NULL;
-		}
+	microtime(&mono_time);
+
+	/*
+	 * Check if the cached route is still valid.  If not, create another
+	 * one.
+	 * XXX: we should be able to let ip_output() to validate the cache
+	 * and to make a new route (see in6_gif_output()).  However, FreeBSD's
+	 * ip_output() does not make a clone for the new route, while we'd
+	 * like do so in case of route changes.  Thus, we reluctantly put
+	 * almost duplicated logic here.
+	 */
+	if (sc->gif_ro.ro_rt && (!(sc->gif_ro.ro_rt->rt_flags & RTF_UP) ||
+	    dst->sin_family != sin_dst->sin_family ||
+	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr ||
+	    sc->rtcache_expire == 0 || mono_time.tv_sec >= sc->rtcache_expire)) {
+		/* 
+		 * The cache route doesn't match, has been invalidated, or has 
+		 * expired.
+		 */
+		RTFREE(sc->gif_ro.ro_rt);
+		sc->gif_ro.ro_rt = NULL;
 #if 0
 		sc->gif_if.if_mtu = GIF_MTU;
 #endif
 	}
 
 	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;
+
 		rtalloc_ign(&sc->gif_ro, 0);
 		if (sc->gif_ro.ro_rt == NULL) {
 			m_freem(m);
@@ -199,9 +216,13 @@
 
 		/* if it constitutes infinite encapsulation, punt. */
 		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+			RTFREE(sc->gif_ro.ro_rt);
+			sc->gif_ro.ro_rt = NULL;
 			m_freem(m);
 			return ENETUNREACH;	/* XXX */
 		}
+
+		sc->rtcache_expire = mono_time.tv_sec + in_gif_rtcachettl;
 #if 0
 		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
 			- sizeof(struct ip);
Index: netinet6/in6_gif.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6_gif.c,v
retrieving revision 1.16
diff -u -u -r1.16 in6_gif.c
--- netinet6/in6_gif.c	29 Oct 2003 15:07:04 -0000	1.16
+++ netinet6/in6_gif.c	7 Dec 2004 04:53:39 -0000
@@ -72,6 +72,7 @@
 
 static int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
 			 struct ifnet *);
+static int in6_gif_rtcachettl = 300; /* XXX see in_gif.c */
 
 extern  struct domain inet6domain;
 struct ip6protosw in6_gif_protosw =
@@ -93,8 +94,9 @@
 	struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
 	struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
 	struct ip6_hdr *ip6;
-	int proto;
+	int proto, error;
 	u_int8_t itos, otos;
+	struct timeval mono_time;
 
 	if (sin6_src == NULL || sin6_dst == NULL ||
 	    sin6_src->sin6_family != AF_INET6 ||
@@ -173,23 +175,24 @@
 	ip6->ip6_flow &= ~htonl(0xff << 20);
 	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)) {
+	microtime(&mono_time);
+
+	if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||
+	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr) ||
+	    sc->rtcache_expire == 0 || mono_time.tv_sec >= sc->rtcache_expire)) {
 		/* cache route doesn't match */
-		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) {
-			RTFREE(sc->gif_ro6.ro_rt);
-			sc->gif_ro6.ro_rt = NULL;
-		}
+		RTFREE(sc->gif_ro6.ro_rt);
+		sc->gif_ro6.ro_rt = NULL;
 #if 0
 		sc->gif_if.if_mtu = GIF_MTU;
 #endif
 	}
 
 	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;
 		rtalloc((struct route *)&sc->gif_ro6);
 		if (sc->gif_ro6.ro_rt == NULL) {
 			m_freem(m);
@@ -198,6 +201,8 @@
 
 		/* if it constitutes infinite encapsulation, punt. */
 		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
+			sc->gif_ro6.ro_rt = NULL;
+			RTFREE(sc->gif_ro6.ro_rt);
 			m_freem(m);
 			return ENETUNREACH;	/*XXX*/
 		}
@@ -213,10 +218,19 @@
 	 * it is too painful to ask for resend of inner packet, to achieve
 	 * path MTU discovery for encapsulated packets.
 	 */
-	return (ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL));
+	error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
 #else
-	return (ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL));
+	error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL);
 #endif
+
+	/*
+	 * if a (new) cached route has been created in ip6_output(), extend
+	 * the expiration time.
+	 */
+	if (sc->gif_ro6.ro_rt && mono_time.tv_sec >= sc->rtcache_expire)
+		sc->rtcache_expire = mono_time.tv_sec + in6_gif_rtcachettl;
+
+	return (error);
 }
 
 int




More information about the cvs-all mailing list