Module Name:    src
Committed By:   knakahara
Date:           Wed Dec 14 11:19:15 UTC 2016

Modified Files:
        src/sys/net: if_etherip.h if_gif.c if_gif.h
        src/sys/netinet: in_gif.c
        src/sys/netinet6: in6_gif.c

Log Message:
fix race of gif_softc->gif_ro when we send multiple flows over gif on 
NET_MPSAFE enabled kernel.

make gif_softc->gif_ro percpu as well as ipforward_rt to resolve this race.
and add future TODO comment for etherip(4).


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/net/if_etherip.h
cvs rdiff -u -r1.123 -r1.124 src/sys/net/if_gif.c
cvs rdiff -u -r1.24 -r1.25 src/sys/net/if_gif.h
cvs rdiff -u -r1.85 -r1.86 src/sys/netinet/in_gif.c
cvs rdiff -u -r1.81 -r1.82 src/sys/netinet6/in6_gif.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_etherip.h
diff -u src/sys/net/if_etherip.h:1.11 src/sys/net/if_etherip.h:1.12
--- src/sys/net/if_etherip.h:1.11	Sat Jul 28 00:43:24 2012
+++ src/sys/net/if_etherip.h	Wed Dec 14 11:19:15 2016
@@ -1,4 +1,4 @@
-/*      $NetBSD: if_etherip.h,v 1.11 2012/07/28 00:43:24 matt Exp $        */
+/*      $NetBSD: if_etherip.h,v 1.12 2016/12/14 11:19:15 knakahara Exp $        */
 
 /*
  *  Copyright (c) 2006, Hans Rosenfeld <rosenf...@grumpf.hope-2000.org>
@@ -46,7 +46,11 @@ struct etherip_softc {
 	struct ethercom sc_ec;
 	struct sockaddr *sc_src;                /* tunnel source address      */
 	struct sockaddr *sc_dst;                /* tunnel destination address */
-	struct route     sc_ro;			/* cached inet route          */
+	struct route     sc_ro;			/*
+						 * cached inet route
+						 * TODO:
+						 * we must make percpu when MP-ify
+						 */
 	void *sc_si;                            /* softintr handle            */
 	LIST_ENTRY(etherip_softc) etherip_list; /* list of etherip tunnels    */
 };

Index: src/sys/net/if_gif.c
diff -u src/sys/net/if_gif.c:1.123 src/sys/net/if_gif.c:1.124
--- src/sys/net/if_gif.c:1.123	Thu Sep 15 06:59:32 2016
+++ src/sys/net/if_gif.c	Wed Dec 14 11:19:15 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gif.c,v 1.123 2016/09/15 06:59:32 knakahara Exp $	*/
+/*	$NetBSD: if_gif.c,v 1.124 2016/12/14 11:19:15 knakahara Exp $	*/
 /*	$KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.123 2016/09/15 06:59:32 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.124 2016/12/14 11:19:15 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -240,6 +240,9 @@ gif_clone_create(struct if_clone *ifc, i
 
 	gifattach0(sc);
 
+	sc->gif_ro_percpu = percpu_alloc(sizeof(struct route));
+	KASSERTMSG(sc->gif_ro_percpu != NULL,
+	    "failed to allocate sc->gif_ro_percpu");
 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
 	return (0);
 }
@@ -271,6 +274,14 @@ gifattach0(struct gif_softc *sc)
 	bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
 }
 
+void
+gif_rtcache_free_pc(void *p, void *arg __unused, struct cpu_info *ci __unused)
+{
+	struct route *ro = p;
+
+	rtcache_free(ro);
+}
+
 static int
 gif_clone_destroy(struct ifnet *ifp)
 {
@@ -281,8 +292,8 @@ gif_clone_destroy(struct ifnet *ifp)
 	gif_delete_tunnel(&sc->gif_if);
 	bpf_detach(ifp);
 	if_detach(ifp);
-	rtcache_free(&sc->gif_ro);
-
+	percpu_foreach(sc->gif_ro_percpu, gif_rtcache_free_pc, NULL);
+	percpu_free(sc->gif_ro_percpu, sizeof(struct route));
 	kmem_free(sc, sizeof(struct gif_softc));
 
 	return (0);

Index: src/sys/net/if_gif.h
diff -u src/sys/net/if_gif.h:1.24 src/sys/net/if_gif.h:1.25
--- src/sys/net/if_gif.h:1.24	Fri Jun 24 04:38:12 2016
+++ src/sys/net/if_gif.h	Wed Dec 14 11:19:15 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gif.h,v 1.24 2016/06/24 04:38:12 knakahara Exp $	*/
+/*	$NetBSD: if_gif.h,v 1.25 2016/12/14 11:19:15 knakahara Exp $	*/
 /*	$KAME: if_gif.h,v 1.23 2001/07/27 09:21:42 itojun Exp $	*/
 
 /*
@@ -38,6 +38,7 @@
 #define _NET_IF_GIF_H_
 
 #include <sys/queue.h>
+#include <sys/percpu.h>
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -52,9 +53,7 @@ struct gif_softc {
 	struct ifnet	gif_if;	   /* common area - must be at the top */
 	struct sockaddr	*gif_psrc; /* Physical src addr */
 	struct sockaddr	*gif_pdst; /* Physical dst addr */
-	union {
-		struct route  gifscr_ro;    /* xxx */
-	} gifsc_gifscr;
+	percpu_t *gif_ro_percpu;
 	int		gif_flags;
 	const struct encaptab *encap_cookie4;
 	const struct encaptab *encap_cookie6;
@@ -62,8 +61,6 @@ struct gif_softc {
 };
 #define GIF_ROUTE_TTL	10
 
-#define gif_ro gifsc_gifscr.gifscr_ro
-
 #define GIF_MTU		(1280)	/* Default MTU */
 #define	GIF_MTU_MIN	(1280)	/* Minimum MTU */
 #define	GIF_MTU_MAX	(8192)	/* Maximum MTU */
@@ -71,6 +68,8 @@ struct gif_softc {
 /* Prototypes */
 void	gif_input(struct mbuf *, int, struct ifnet *);
 
+void	gif_rtcache_free_pc(void *, void *, struct cpu_info *);
+
 #ifdef GIF_ENCAPCHECK
 int	gif_encapcheck(struct mbuf *, int, int, void *);
 #endif

Index: src/sys/netinet/in_gif.c
diff -u src/sys/netinet/in_gif.c:1.85 src/sys/netinet/in_gif.c:1.86
--- src/sys/netinet/in_gif.c:1.85	Mon Dec 12 03:55:57 2016
+++ src/sys/netinet/in_gif.c	Wed Dec 14 11:19:15 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_gif.c,v 1.85 2016/12/12 03:55:57 ozaki-r Exp $	*/
+/*	$NetBSD: in_gif.c,v 1.86 2016/12/14 11:19:15 knakahara Exp $	*/
 /*	$KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.85 2016/12/12 03:55:57 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.86 2016/12/14 11:19:15 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -83,6 +83,7 @@ int
 in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
 {
 	struct rtentry *rt;
+	struct route *ro;
 	struct gif_softc *sc = ifp->if_softc;
 	struct sockaddr_in *sin_src = satosin(sc->gif_psrc);
 	struct sockaddr_in *sin_dst = satosin(sc->gif_pdst);
@@ -170,21 +171,26 @@ in_gif_output(struct ifnet *ifp, int fam
 	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
 
 	sockaddr_in_init(&u.dst4, &sin_dst->sin_addr, 0);
-	if ((rt = rtcache_lookup(&sc->gif_ro, &u.dst)) == NULL) {
+
+	ro = percpu_getref(sc->gif_ro_percpu);
+	if ((rt = rtcache_lookup(ro, &u.dst)) == NULL) {
+		percpu_putref(sc->gif_ro_percpu);
 		m_freem(m);
 		return ENETUNREACH;
 	}
 
 	/* If the route constitutes infinite encapsulation, punt. */
 	if (rt->rt_ifp == ifp) {
-		rtcache_unref(rt, &sc->gif_ro);
-		rtcache_free(&sc->gif_ro);
+		rtcache_unref(rt, ro);
+		rtcache_free(ro);
+		percpu_putref(sc->gif_ro_percpu);
 		m_freem(m);
 		return ENETUNREACH;	/*XXX*/
 	}
-	rtcache_unref(rt, &sc->gif_ro);
+	rtcache_unref(rt, ro);
 
-	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
+	error = ip_output(m, NULL, ro, 0, NULL, NULL);
+	percpu_putref(sc->gif_ro_percpu);
 	return (error);
 }
 
@@ -399,7 +405,7 @@ in_gif_detach(struct gif_softc *sc)
 
 	error = in_gif_pause(sc);
 
-	rtcache_free(&sc->gif_ro);
+	percpu_foreach(sc->gif_ro_percpu, gif_rtcache_free_pc, NULL);
 
 	return error;
 }

Index: src/sys/netinet6/in6_gif.c
diff -u src/sys/netinet6/in6_gif.c:1.81 src/sys/netinet6/in6_gif.c:1.82
--- src/sys/netinet6/in6_gif.c:1.81	Mon Dec 12 03:55:57 2016
+++ src/sys/netinet6/in6_gif.c	Wed Dec 14 11:19:15 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_gif.c,v 1.81 2016/12/12 03:55:57 ozaki-r Exp $	*/
+/*	$NetBSD: in6_gif.c,v 1.82 2016/12/14 11:19:15 knakahara Exp $	*/
 /*	$KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.81 2016/12/12 03:55:57 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.82 2016/12/14 11:19:15 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -86,6 +86,7 @@ int
 in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
 {
 	struct rtentry *rt;
+	struct route *ro;
 	struct gif_softc *sc = ifp->if_softc;
 	struct sockaddr_in6 *sin6_src = satosin6(sc->gif_psrc);
 	struct sockaddr_in6 *sin6_dst = satosin6(sc->gif_pdst);
@@ -176,20 +177,23 @@ in6_gif_output(struct ifnet *ifp, int fa
 	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
 
 	sockaddr_in6_init(&u.dst6, &sin6_dst->sin6_addr, 0, 0, 0);
-	rt = rtcache_lookup(&sc->gif_ro, &u.dst);
+	ro = percpu_getref(sc->gif_ro_percpu);
+	rt = rtcache_lookup(ro, &u.dst);
 	if (rt == NULL) {
+		percpu_putref(sc->gif_ro_percpu);
 		m_freem(m);
 		return ENETUNREACH;
 	}
 
 	/* If the route constitutes infinite encapsulation, punt. */
 	if (rt->rt_ifp == ifp) {
-		rtcache_unref(rt, &sc->gif_ro);
-		rtcache_free(&sc->gif_ro);
+		rtcache_unref(rt, ro);
+		rtcache_free(ro);
+		percpu_putref(sc->gif_ro_percpu);
 		m_freem(m);
 		return ENETUNREACH;	/* XXX */
 	}
-	rtcache_unref(rt, &sc->gif_ro);
+	rtcache_unref(rt, ro);
 
 #ifdef IPV6_MINMTU
 	/*
@@ -197,11 +201,11 @@ in6_gif_output(struct ifnet *ifp, int fa
 	 * it is too painful to ask for resend of inner packet, to achieve
 	 * path MTU discovery for encapsulated packets.
 	 */
-	error = ip6_output(m, 0, &sc->gif_ro, IPV6_MINMTU, NULL, NULL, NULL);
+	error = ip6_output(m, 0, ro, IPV6_MINMTU, NULL, NULL, NULL);
 #else
-	error = ip6_output(m, 0, &sc->gif_ro, 0, NULL, NULL, NULL);
+	error = ip6_output(m, 0, ro, 0, NULL, NULL, NULL);
 #endif
-
+	percpu_putref(sc->gif_ro_percpu);
 	return (error);
 }
 
@@ -402,7 +406,7 @@ in6_gif_detach(struct gif_softc *sc)
 
 	error = in6_gif_pause(sc);
 
-	rtcache_free(&sc->gif_ro);
+	percpu_foreach(sc->gif_ro_percpu, gif_rtcache_free_pc, NULL);
 
 	return error;
 }
@@ -426,6 +430,7 @@ in6_gif_ctlinput(int cmd, const struct s
 	struct ip6ctlparam *ip6cp = NULL;
 	struct ip6_hdr *ip6;
 	const struct sockaddr_in6 *dst6;
+	struct route *ro;
 
 	if (sa->sa_family != AF_INET6 ||
 	    sa->sa_len != sizeof(struct sockaddr_in6))
@@ -454,13 +459,15 @@ in6_gif_ctlinput(int cmd, const struct s
 	if (sc->gif_psrc->sa_family != AF_INET6)
 		return NULL;
 
-	dst6 = satocsin6(rtcache_getdst(&sc->gif_ro));
+	ro = percpu_getref(sc->gif_ro_percpu);
+	dst6 = satocsin6(rtcache_getdst(ro));
 	/* XXX scope */
 	if (dst6 == NULL)
 		;
 	else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr))
-		rtcache_free(&sc->gif_ro);
+		rtcache_free(ro);
 
+	percpu_putref(sc->gif_ro_percpu);
 	return NULL;
 }
 

Reply via email to