svn commit: r195623 - in user/kmacy/head_ppacket/sys: net netinet

Kip Macy kmacy at FreeBSD.org
Sat Jul 11 21:46:21 UTC 2009


Author: kmacy
Date: Sat Jul 11 21:46:20 2009
New Revision: 195623
URL: http://svn.freebsd.org/changeset/base/195623

Log:
  - provide reference counting for gre_softc
  - serialize access to gre_softc
  - take first pass at decoupling ip_gre from if_gre

Modified:
  user/kmacy/head_ppacket/sys/net/if_gre.c
  user/kmacy/head_ppacket/sys/net/if_gre.h
  user/kmacy/head_ppacket/sys/netinet/ip_gre.c

Modified: user/kmacy/head_ppacket/sys/net/if_gre.c
==============================================================================
--- user/kmacy/head_ppacket/sys/net/if_gre.c	Sat Jul 11 17:36:59 2009	(r195622)
+++ user/kmacy/head_ppacket/sys/net/if_gre.c	Sat Jul 11 21:46:20 2009	(r195623)
@@ -86,9 +86,44 @@
 #endif
 
 #include <net/bpf.h>
-
 #include <net/if_gre.h>
 
+struct gre_softc {
+	struct mtx gre_mtx;
+	int gre_unit;
+	/*
+	 * refcount counts total references, not list external
+	 * like rtentry as that has proven to be error-prone
+	 */
+	int gre_refcnt;
+	u_int	gre_fibnum;	/* use this fib for envelopes */
+	struct route route;	/* routing entry that determines, where a
+				   encapsulated packet should go */
+	const struct encaptab *encap;	/* encapsulation cookie */
+
+	int called;		/* infinite recursion preventer */
+
+	uint32_t key;		/* key included in outgoing GRE packets */
+				/* zero means none */
+
+#define	MTX_BUF_SIZE	32
+	char sc_mtx_buf[MTX_BUF_SIZE];
+	LIST_ENTRY(gre_softc) sc_list;
+	struct gre_softc_external gre_ext;
+};
+#define	gre_src		gre_ext.g_src
+#define	gre_dst		gre_ext.g_dst
+#define	gre_proto	gre_ext.g_proto
+#define	gre_wccp_ver	gre_ext.g_wccp_ver
+LIST_HEAD(gre_softc_head, gre_softc);
+
+#define GRE_LOCK(sc)	mtx_lock(&(sc)->gre_mtx);
+#define GRE_UNLOCK(sc)	mtx_unlock(&(sc)->gre_mtx);
+#define	GRE_ADDREF(sc)	do {			\
+		GRE_LOCK(sc);			\
+		(sc)->gre_refcnt++;		\
+		GRE_UNLOCK(sc);			\
+	} while (0)
 /*
  * It is not easy to calculate the right value for a GRE MTU.
  * We leave this task to the admin and use the same default that
@@ -188,6 +223,9 @@ gre_clone_create(ifc, unit, params)
 		free(sc, M_GRE);
 		return (ENOSPC);
 	}
+	snprintf(sc->sc_mtx_buf, MTX_BUF_SIZE, "%s%d_mtx", ifc->ifc_name, unit);
+	mtx_init(&sc->gre_mtx, sc->sc_mtx_buf, NULL, MTX_DEF);
+	sc->gre_refcnt = 1;
 
 	GRE2IFP(sc)->if_softc = sc;
 	if_initname(GRE2IFP(sc), ifc->ifc_name, unit);
@@ -199,13 +237,13 @@ gre_clone_create(ifc, unit, params)
 	GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
 	GRE2IFP(sc)->if_output = gre_output;
 	GRE2IFP(sc)->if_ioctl = gre_ioctl;
-	sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
-	sc->g_proto = IPPROTO_GRE;
+	sc->gre_dst.s_addr = sc->gre_src.s_addr = INADDR_ANY;
+	sc->gre_proto = IPPROTO_GRE;
 	GRE2IFP(sc)->if_flags |= IFF_LINK0;
 	sc->encap = NULL;
 	sc->called = 0;
 	sc->gre_fibnum = curthread->td_proc->p_fibnum;
-	sc->wccp_ver = WCCP_V1;
+	sc->gre_wccp_ver = WCCP_V1;
 	sc->key = 0;
 	if_attach(GRE2IFP(sc));
 	bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t));
@@ -215,29 +253,43 @@ gre_clone_create(ifc, unit, params)
 	return (0);
 }
 
-static void
-gre_clone_destroy(ifp)
-	struct ifnet *ifp;
+void
+gre_free(struct gre_softc *sc)
 {
-	struct gre_softc *sc = ifp->if_softc;
+	struct ifnet *ifp;
 
-	mtx_lock(&gre_mtx);
-	LIST_REMOVE(sc, sc_list);
-	mtx_unlock(&gre_mtx);
+	GRE_LOCK(sc);	
+	(sc)->gre_refcnt--;
+	if ((sc)->gre_refcnt > 0) {
+		GRE_UNLOCK((sc));
+		return;
+	}
 
 #ifdef INET
 	if (sc->encap != NULL)
 		encap_detach(sc->encap);
 #endif
+	ifp = GRE2IFP(sc);
 	bpfdetach(ifp);
 	if_detach(ifp);
 	if_free(ifp);
 	free(sc, M_GRE);
 }
 
+static void
+gre_clone_destroy(struct ifnet *ifp)
+{
+	struct gre_softc *sc = ifp->if_softc;
+
+	mtx_lock(&gre_mtx);
+	LIST_REMOVE(sc, sc_list);
+	mtx_unlock(&gre_mtx);
+	gre_free(sc);
+}
+
 /*
  * The output routine. Takes a packet and encapsulates it in the protocol
- * given by sc->g_proto. See also RFC 1701 and RFC 2004
+ * given by sc->gre_proto. See also RFC 1701 and RFC 2004
  */
 static int
 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
@@ -256,7 +308,8 @@ gre_output(struct ifnet *ifp, struct mbu
 	struct mobile_h mob_h;
 	u_int32_t af;
 	int extra = 0;
-
+	
+	GRE_LOCK(sc);
 	/*
 	 * gre may cause infinite recursion calls when misconfigured.
 	 * We'll prevent this by introducing upper limit.
@@ -271,7 +324,7 @@ gre_output(struct ifnet *ifp, struct mbu
 
 	if (!((ifp->if_flags & IFF_UP) &&
 	    (ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
-	    sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
+	    sc->gre_src.s_addr == INADDR_ANY || sc->gre_dst.s_addr == INADDR_ANY) {
 		m_freem(m);
 		error = ENETDOWN;
 		goto end;
@@ -293,7 +346,7 @@ gre_output(struct ifnet *ifp, struct mbu
 
 	m->m_flags &= ~(M_BCAST|M_MCAST);
 
-	if (sc->g_proto == IPPROTO_MOBILE) {
+	if (sc->gre_proto == IPPROTO_MOBILE) {
 		if (dst->sa_family == AF_INET) {
 			struct mbuf *m0;
 			int msiz;
@@ -313,19 +366,19 @@ gre_output(struct ifnet *ifp, struct mbu
 			memset(&mob_h, 0, MOB_H_SIZ_L);
 			mob_h.proto = (ip->ip_p) << 8;
 			mob_h.odst = ip->ip_dst.s_addr;
-			ip->ip_dst.s_addr = sc->g_dst.s_addr;
+			ip->ip_dst.s_addr = sc->gre_dst.s_addr;
 
 			/*
 			 * If the packet comes from our host, we only change
 			 * the destination address in the IP header.
 			 * Else we also need to save and change the source
 			 */
-			if (in_hosteq(ip->ip_src, sc->g_src)) {
+			if (in_hosteq(ip->ip_src, sc->gre_src)) {
 				msiz = MOB_H_SIZ_S;
 			} else {
 				mob_h.proto |= MOB_H_SBIT;
 				mob_h.osrc = ip->ip_src.s_addr;
-				ip->ip_src.s_addr = sc->g_src.s_addr;
+				ip->ip_src.s_addr = sc->gre_src.s_addr;
 				msiz = MOB_H_SIZ_L;
 			}
 			mob_h.proto = htons(mob_h.proto);
@@ -365,13 +418,13 @@ gre_output(struct ifnet *ifp, struct mbu
 			error = EINVAL;
 			goto end;
 		}
-	} else if (sc->g_proto == IPPROTO_GRE) {
+	} else if (sc->gre_proto == IPPROTO_GRE) {
 		switch (dst->sa_family) {
 		case AF_INET:
 			ip = mtod(m, struct ip *);
 			gre_ip_tos = ip->ip_tos;
 			gre_ip_id = ip->ip_id;
-			if (sc->wccp_ver == WCCP_V2) {
+			if (sc->gre_wccp_ver == WCCP_V2) {
 				extra = sizeof(uint32_t);
 				etype =  WCCP_PROTOCOL_TYPE;
 			} else {
@@ -417,7 +470,7 @@ gre_output(struct ifnet *ifp, struct mbu
 	M_SETFIB(m, sc->gre_fibnum); /* The envelope may use a different FIB */
 
 	gh = mtod(m, struct greip *);
-	if (sc->g_proto == IPPROTO_GRE) {
+	if (sc->gre_proto == IPPROTO_GRE) {
 		uint32_t *options = gh->gi_options;
 
 		memset((void *)gh, 0, sizeof(struct greip) + extra);
@@ -432,10 +485,10 @@ gre_output(struct ifnet *ifp, struct mbu
 		}
 	}
 
-	gh->gi_pr = sc->g_proto;
-	if (sc->g_proto != IPPROTO_MOBILE) {
-		gh->gi_src = sc->g_src;
-		gh->gi_dst = sc->g_dst;
+	gh->gi_pr = sc->gre_proto;
+	if (sc->gre_proto != IPPROTO_MOBILE) {
+		gh->gi_src = sc->gre_src;
+		gh->gi_dst = sc->gre_dst;
 		((struct ip*)gh)->ip_v = IPPROTO_IPV4;
 		((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
 		((struct ip*)gh)->ip_ttl = GRE_TTL;
@@ -454,6 +507,7 @@ gre_output(struct ifnet *ifp, struct mbu
 	error = ip_output(m, NULL, &sc->route, IP_FORWARDING,
 	    (struct ip_moptions *)NULL, (struct inpcb *)NULL);
   end:
+	GRE_UNLOCK(sc);
 	sc->called = 0;
 	if (error)
 		ifp->if_oerrors++;
@@ -467,7 +521,6 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 	struct if_laddrreq *lifr = (struct if_laddrreq *)data;
 	struct in_aliasreq *aifr = (struct in_aliasreq *)data;
 	struct gre_softc *sc = ifp->if_softc;
-	int s;
 	struct sockaddr_in si;
 	struct sockaddr *sa = NULL;
 	int error, adj;
@@ -477,7 +530,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 	error = 0;
 	adj = 0;
 
-	s = splnet();
+	GRE_LOCK(sc);
 	switch (cmd) {
 	case SIOCSIFADDR:
 		ifp->if_flags |= IFF_UP;
@@ -492,13 +545,13 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		if ((error = priv_check(curthread, PRIV_NET_SETIFFLAGS)) != 0)
 			break;
 		if ((ifr->ifr_flags & IFF_LINK0) != 0)
-			sc->g_proto = IPPROTO_GRE;
+			sc->gre_proto = IPPROTO_GRE;
 		else
-			sc->g_proto = IPPROTO_MOBILE;
+			sc->gre_proto = IPPROTO_MOBILE;
 		if ((ifr->ifr_flags & IFF_LINK2) != 0)
-			sc->wccp_ver = WCCP_V2;
+			sc->gre_wccp_ver = WCCP_V2;
 		else
-			sc->wccp_ver = WCCP_V1;
+			sc->gre_wccp_ver = WCCP_V1;
 		goto recompute;
 	case SIOCSIFMTU:
 		/*
@@ -573,8 +626,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		 */
 		if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
 			break;
-		sc->g_proto = ifr->ifr_flags;
-		switch (sc->g_proto) {
+		sc->gre_proto = ifr->ifr_flags;
+		switch (sc->gre_proto) {
 		case IPPROTO_GRE:
 			ifp->if_flags |= IFF_LINK0;
 			break;
@@ -587,7 +640,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		}
 		goto recompute;
 	case GREGPROTO:
-		ifr->ifr_flags = sc->g_proto;
+		ifr->ifr_flags = sc->gre_proto;
 		break;
 	case GRESADDRS:
 	case GRESADDRD:
@@ -600,9 +653,9 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		 */
 		sa = &ifr->ifr_addr;
 		if (cmd == GRESADDRS)
-			sc->g_src = (satosin(sa))->sin_addr;
+			sc->gre_src = (satosin(sa))->sin_addr;
 		if (cmd == GRESADDRD)
-			sc->g_dst = (satosin(sa))->sin_addr;
+			sc->gre_dst = (satosin(sa))->sin_addr;
 	recompute:
 #ifdef INET
 		if (sc->encap != NULL) {
@@ -610,8 +663,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 			sc->encap = NULL;
 		}
 #endif
-		if ((sc->g_src.s_addr != INADDR_ANY) &&
-		    (sc->g_dst.s_addr != INADDR_ANY)) {
+		if ((sc->gre_src.s_addr != INADDR_ANY) &&
+		    (sc->gre_dst.s_addr != INADDR_ANY)) {
 			bzero(&sp, sizeof(sp));
 			bzero(&sm, sizeof(sm));
 			bzero(&dp, sizeof(dp));
@@ -620,14 +673,14 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 			    sizeof(struct sockaddr_in);
 			sp.sin_family = sm.sin_family = dp.sin_family =
 			    dm.sin_family = AF_INET;
-			sp.sin_addr = sc->g_src;
-			dp.sin_addr = sc->g_dst;
+			sp.sin_addr = sc->gre_src;
+			dp.sin_addr = sc->gre_dst;
 			sm.sin_addr.s_addr = dm.sin_addr.s_addr =
 			    INADDR_BROADCAST;
 #ifdef INET
-			sc->encap = encap_attach(AF_INET, sc->g_proto,
+			sc->encap = encap_attach(AF_INET, sc->gre_proto,
 			    sintosa(&sp), sintosa(&sm), sintosa(&dp),
-			    sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
+			    sintosa(&dm), (sc->gre_proto == IPPROTO_GRE) ?
 				&in_gre_protosw : &in_mobile_protosw, sc);
 			if (sc->encap == NULL)
 				printf("%s: unable to attach encap\n",
@@ -645,7 +698,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		memset(&si, 0, sizeof(si));
 		si.sin_family = AF_INET;
 		si.sin_len = sizeof(struct sockaddr_in);
-		si.sin_addr.s_addr = sc->g_src.s_addr;
+		si.sin_addr.s_addr = sc->gre_src.s_addr;
 		sa = sintosa(&si);
 		ifr->ifr_addr = *sa;
 		break;
@@ -653,7 +706,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		memset(&si, 0, sizeof(si));
 		si.sin_family = AF_INET;
 		si.sin_len = sizeof(struct sockaddr_in);
-		si.sin_addr.s_addr = sc->g_dst.s_addr;
+		si.sin_addr.s_addr = sc->gre_dst.s_addr;
 		sa = sintosa(&si);
 		ifr->ifr_addr = *sa;
 		break;
@@ -674,8 +727,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 			error = EINVAL;
 			break;
 		}
-		sc->g_src = aifr->ifra_addr.sin_addr;
-		sc->g_dst = aifr->ifra_dstaddr.sin_addr;
+		sc->gre_src = aifr->ifra_addr.sin_addr;
+		sc->gre_dst = aifr->ifra_dstaddr.sin_addr;
 		goto recompute;
 	case SIOCSLIFPHYADDR:
 		/*
@@ -694,8 +747,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 			error = EINVAL;
 			break;
 		}
-		sc->g_src = (satosin(&lifr->addr))->sin_addr;
-		sc->g_dst =
+		sc->gre_src = (satosin(&lifr->addr))->sin_addr;
+		sc->gre_dst =
 		    (satosin(&lifr->dstaddr))->sin_addr;
 		goto recompute;
 	case SIOCDIFPHYADDR:
@@ -705,49 +758,49 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		 */
 		if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
 			break;
-		sc->g_src.s_addr = INADDR_ANY;
-		sc->g_dst.s_addr = INADDR_ANY;
+		sc->gre_src.s_addr = INADDR_ANY;
+		sc->gre_dst.s_addr = INADDR_ANY;
 		goto recompute;
 	case SIOCGLIFPHYADDR:
-		if (sc->g_src.s_addr == INADDR_ANY ||
-		    sc->g_dst.s_addr == INADDR_ANY) {
+		if (sc->gre_src.s_addr == INADDR_ANY ||
+		    sc->gre_dst.s_addr == INADDR_ANY) {
 			error = EADDRNOTAVAIL;
 			break;
 		}
 		memset(&si, 0, sizeof(si));
 		si.sin_family = AF_INET;
 		si.sin_len = sizeof(struct sockaddr_in);
-		si.sin_addr.s_addr = sc->g_src.s_addr;
+		si.sin_addr.s_addr = sc->gre_src.s_addr;
 		memcpy(&lifr->addr, &si, sizeof(si));
-		si.sin_addr.s_addr = sc->g_dst.s_addr;
+		si.sin_addr.s_addr = sc->gre_dst.s_addr;
 		memcpy(&lifr->dstaddr, &si, sizeof(si));
 		break;
 	case SIOCGIFPSRCADDR:
 #ifdef INET6
 	case SIOCGIFPSRCADDR_IN6:
 #endif
-		if (sc->g_src.s_addr == INADDR_ANY) {
+		if (sc->gre_src.s_addr == INADDR_ANY) {
 			error = EADDRNOTAVAIL;
 			break;
 		}
 		memset(&si, 0, sizeof(si));
 		si.sin_family = AF_INET;
 		si.sin_len = sizeof(struct sockaddr_in);
-		si.sin_addr.s_addr = sc->g_src.s_addr;
+		si.sin_addr.s_addr = sc->gre_src.s_addr;
 		bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
 		break;
 	case SIOCGIFPDSTADDR:
 #ifdef INET6
 	case SIOCGIFPDSTADDR_IN6:
 #endif
-		if (sc->g_dst.s_addr == INADDR_ANY) {
+		if (sc->gre_dst.s_addr == INADDR_ANY) {
 			error = EADDRNOTAVAIL;
 			break;
 		}
 		memset(&si, 0, sizeof(si));
 		si.sin_family = AF_INET;
 		si.sin_len = sizeof(struct sockaddr_in);
-		si.sin_addr.s_addr = sc->g_dst.s_addr;
+		si.sin_addr.s_addr = sc->gre_dst.s_addr;
 		bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
 		break;
 	case GRESKEY:
@@ -779,7 +832,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
 		break;
 	}
 
-	splx(s);
+	GRE_UNLOCK(sc);
 	return (error);
 }
 
@@ -802,7 +855,7 @@ gre_compute_route(struct gre_softc *sc)
 	ro = &sc->route;
 
 	memset(ro, 0, sizeof(struct route));
-	((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
+	((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->gre_dst;
 	ro->ro_dst.sa_family = AF_INET;
 	ro->ro_dst.sa_len = sizeof(ro->ro_dst);
 
@@ -843,7 +896,7 @@ gre_compute_route(struct gre_softc *sc)
 	 * the route and search one to this interface ...
 	 */
 	if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0)
-		((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
+		((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->gre_dst;
 
 #ifdef DIAGNOSTIC
 	printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
@@ -883,6 +936,31 @@ gre_in_cksum(u_int16_t *p, u_int len)
 	return (~sum);
 }
 
+/*
+ * Find the gre interface associated with our src/dst/proto set.
+ *
+ */
+struct gre_softc *
+gre_lookup(struct mbuf *m, u_char proto,
+    int (*func)(struct gre_softc_external *, struct mbuf *, u_char))
+{
+	struct gre_softc *sc;
+
+	mtx_lock(&gre_mtx);
+	for (sc = LIST_FIRST(&gre_softc_list); sc != NULL;
+	     sc = LIST_NEXT(sc, sc_list)) {
+		if (func(&sc->gre_ext, m, proto) &&
+		    ((GRE2IFP(sc)->if_flags & IFF_UP) != 0)) {
+			GRE_ADDREF(sc);
+			mtx_unlock(&gre_mtx);
+			return (sc);
+		}
+	}
+	mtx_unlock(&gre_mtx);
+
+	return (NULL);
+}
+
 static int
 gremodevent(module_t mod, int type, void *data)
 {

Modified: user/kmacy/head_ppacket/sys/net/if_gre.h
==============================================================================
--- user/kmacy/head_ppacket/sys/net/if_gre.h	Sat Jul 11 17:36:59 2009	(r195622)
+++ user/kmacy/head_ppacket/sys/net/if_gre.h	Sat Jul 11 21:46:20 2009	(r195623)
@@ -54,30 +54,19 @@ typedef enum {
 	WCCP_V2
 } wccp_ver_t;
 
-struct gre_softc {
-	struct ifnet *sc_ifp;
-	LIST_ENTRY(gre_softc) sc_list;
-	int gre_unit;
-	int gre_flags;
-	u_int	gre_fibnum;	/* use this fib for envelopes */
+/*
+ * The binary contract is to have the ifp at the front of the softc
+ *
+ */
+#define	GRE2IFP(sc)	(*(struct ifnet **)(&sc))
+struct gre_softc_external {
+	struct ifnet *gre_ifp;
 	struct in_addr g_src;	/* source address of gre packets */
 	struct in_addr g_dst;	/* destination address of gre packets */
-	struct route route;	/* routing entry that determines, where a
-				   encapsulated packet should go */
 	u_char g_proto;		/* protocol of encapsulator */
-
-	const struct encaptab *encap;	/* encapsulation cookie */
-
-	int called;		/* infinite recursion preventer */
-
-	uint32_t key;		/* key included in outgoing GRE packets */
-				/* zero means none */
-
-	wccp_ver_t wccp_ver;	/* version of the WCCP */
+	wccp_ver_t g_wccp_ver;	/* version of the WCCP */
 };
-#define	GRE2IFP(sc)	((sc)->sc_ifp)
-
-
+	
 struct gre_h {
 	u_int16_t flags;	/* GRE flags */
 	u_int16_t ptype;	/* protocol type of payload typically
@@ -184,11 +173,11 @@ struct mobip_h {
 #define GRESKEY		_IOW('i', 108, struct ifreq)
 
 #ifdef _KERNEL
-LIST_HEAD(gre_softc_head, gre_softc);
-extern struct mtx gre_mtx;
-extern struct gre_softc_head gre_softc_list;
-
+struct gre_softc;
 u_int16_t	gre_in_cksum(u_int16_t *, u_int);
+struct gre_softc *gre_lookup(struct mbuf *m, u_char proto,
+    int (*func)(struct gre_softc_external *, struct mbuf *, u_char));
+void gre_free(struct gre_softc *sc);
 #endif /* _KERNEL */
 
 #endif

Modified: user/kmacy/head_ppacket/sys/netinet/ip_gre.c
==============================================================================
--- user/kmacy/head_ppacket/sys/netinet/ip_gre.c	Sat Jul 11 17:36:59 2009	(r195622)
+++ user/kmacy/head_ppacket/sys/netinet/ip_gre.c	Sat Jul 11 21:46:20 2009	(r195623)
@@ -91,35 +91,14 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/stdarg.h>
 
-#if 1
-void gre_inet_ntoa(struct in_addr in);	/* XXX */
-#endif
-
-static struct gre_softc *gre_lookup(struct mbuf *, u_int8_t);
-
-static struct mbuf *gre_input2(struct mbuf *, int, u_char);
-
-/*
- * De-encapsulate a packet and feed it back through ip input (this
- * routine is called whenever IP gets a packet with proto type
- * IPPROTO_GRE and a local destination address).
- * This really is simple
- */
-void
-gre_input(struct mbuf *m, int off)
+static int
+gre_input_lookup_func(struct gre_softc_external *sc, struct mbuf *m, u_char proto)
 {
-	int proto;
-
-	proto = (mtod(m, struct ip *))->ip_p;
-
-	m = gre_input2(m, off, proto);
+	struct ip *ip = mtod(m, struct ip *);
 
-	/*
-	 * If no matching tunnel that is up is found. We inject
-	 * the mbuf to raw ip socket to see if anyone picks it up.
-	 */
-	if (m != NULL)
-		rip_input(m, off);
+	return ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
+	    (sc->g_src.s_addr == ip->ip_dst.s_addr) &&
+	    (sc->g_proto == proto));
 }
 
 /*
@@ -137,15 +116,15 @@ gre_input2(struct mbuf *m ,int hlen, u_c
 	u_int16_t flags;
 	u_int32_t af;
 
-	if ((sc = gre_lookup(m, proto)) == NULL) {
+	if ((sc = gre_lookup(m, proto, gre_input_lookup_func)) == NULL) {
 		/* No matching tunnel or tunnel is down. */
 		return (m);
 	}
 
 	if (m->m_len < sizeof(*gip)) {
 		m = m_pullup(m, sizeof(*gip));
-		if (m == NULL)
-			return (NULL);
+		if (m == NULL) 
+			goto done;
 	}
 	gip = mtod(m, struct greip *);
 
@@ -164,7 +143,7 @@ gre_input2(struct mbuf *m ,int hlen, u_c
 			hlen += 4;
 		/* We don't support routing fields (variable length) */
 		if (flags & GRE_RP)
-			return (m);
+			goto done;
 		if (flags & GRE_KP)
 			hlen += 4;
 		if (flags & GRE_SP)
@@ -172,7 +151,7 @@ gre_input2(struct mbuf *m ,int hlen, u_c
 
 		switch (ntohs(gip->gi_ptype)) { /* ethertypes */
 		case WCCP_PROTOCOL_TYPE:
-			if (sc->wccp_ver == WCCP_V2)
+			if (((struct gre_softc_external *)sc)->g_wccp_ver == WCCP_V2)
 				hlen += 4;
 			/* FALLTHROUGH */
 		case ETHERTYPE_IP:	/* shouldn't need a schednetisr(), */
@@ -193,17 +172,18 @@ gre_input2(struct mbuf *m ,int hlen, u_c
 #endif
 		default:
 			/* Others not yet supported. */
-			return (m);
+			goto done;
 		}
 		break;
 	default:
 		/* Others not yet supported. */
-		return (m);
+		goto done;
 	}
 
 	if (hlen > m->m_pkthdr.len) {
 		m_freem(m);
-		return (NULL);
+		m = NULL;
+		goto done;
 	}
 	/* Unlike NetBSD, in FreeBSD m_adj() adjusts m->m_pkthdr.len as well */
 	m_adj(m, hlen);
@@ -213,11 +193,37 @@ gre_input2(struct mbuf *m ,int hlen, u_c
 	}
 
 	m->m_pkthdr.rcvif = GRE2IFP(sc);
-
+	gre_free(sc);
 	netisr_queue(isr, m);
 
 	/* Packet is done, no further processing needed. */
 	return (NULL);
+done:
+	gre_free(sc);
+	return (m);
+}
+
+/*
+ * De-encapsulate a packet and feed it back through ip input (this
+ * routine is called whenever IP gets a packet with proto type
+ * IPPROTO_GRE and a local destination address).
+ * This really is simple
+ */
+void
+gre_input(struct mbuf *m, int off)
+{
+	int proto;
+
+	proto = (mtod(m, struct ip *))->ip_p;
+
+	m = gre_input2(m, off, proto);
+
+	/*
+	 * If no matching tunnel that is up is found. We inject
+	 * the mbuf to raw ip socket to see if anyone picks it up.
+	 */
+	if (m != NULL)
+		rip_input(m, off);
 }
 
 /*
@@ -226,7 +232,6 @@ gre_input2(struct mbuf *m ,int hlen, u_c
  * encapsulating header was not prepended, but instead inserted
  * between IP header and payload
  */
-
 void
 gre_mobile_input(struct mbuf *m, int hlen)
 {
@@ -235,7 +240,7 @@ gre_mobile_input(struct mbuf *m, int hle
 	struct gre_softc *sc;
 	int msiz;
 
-	if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) {
+	if ((sc = gre_lookup(m, IPPROTO_MOBILE, gre_input_lookup_func)) == NULL) {
 		/* No matching tunnel or tunnel is down. */
 		m_freem(m);
 		return;
@@ -244,7 +249,7 @@ gre_mobile_input(struct mbuf *m, int hle
 	if (m->m_len < sizeof(*mip)) {
 		m = m_pullup(m, sizeof(*mip));
 		if (m == NULL)
-			return;
+			goto done;
 	}
 	ip = mtod(m, struct ip *);
 	mip = mtod(m, struct mobip_h *);
@@ -261,7 +266,7 @@ gre_mobile_input(struct mbuf *m, int hle
 	if (m->m_len < (ip->ip_hl << 2) + msiz) {
 		m = m_pullup(m, (ip->ip_hl << 2) + msiz);
 		if (m == NULL)
-			return;
+			goto done;
 		ip = mtod(m, struct ip *);
 		mip = mtod(m, struct mobip_h *);
 	}
@@ -271,7 +276,7 @@ gre_mobile_input(struct mbuf *m, int hle
 
 	if (gre_in_cksum((u_int16_t *)&mip->mh, msiz) != 0) {
 		m_freem(m);
-		return;
+		goto done;
 	}
 
 	bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) +
@@ -297,38 +302,8 @@ gre_mobile_input(struct mbuf *m, int hle
 	}
 
 	m->m_pkthdr.rcvif = GRE2IFP(sc);
-
 	netisr_queue(NETISR_IP, m);
-}
-
-/*
- * Find the gre interface associated with our src/dst/proto set.
- *
- * XXXRW: Need some sort of drain/refcount mechanism so that the softc
- * reference remains valid after it's returned from gre_lookup().  Right
- * now, I'm thinking it should be reference-counted with a gre_dropref()
- * when the caller is done with the softc.  This is complicated by how
- * to handle destroying the gre softc; probably using a gre_drain() in
- * in_gre.c during destroy.
- */
-static struct gre_softc *
-gre_lookup(struct mbuf *m, u_int8_t proto)
-{
-	struct ip *ip = mtod(m, struct ip *);
-	struct gre_softc *sc;
 
-	mtx_lock(&gre_mtx);
-	for (sc = LIST_FIRST(&gre_softc_list); sc != NULL;
-	     sc = LIST_NEXT(sc, sc_list)) {
-		if ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
-		    (sc->g_src.s_addr == ip->ip_dst.s_addr) &&
-		    (sc->g_proto == proto) &&
-		    ((GRE2IFP(sc)->if_flags & IFF_UP) != 0)) {
-			mtx_unlock(&gre_mtx);
-			return (sc);
-		}
-	}
-	mtx_unlock(&gre_mtx);
-
-	return (NULL);
+done:
+	gre_free(sc);
 }


More information about the svn-src-user mailing list