Author: dwmalone
Date: Tue Oct 14 19:48:58 2008
New Revision: 183893
URL: http://svn.freebsd.org/changeset/base/183893

Log:
  Some people's 6to4 routers seem to have been blowing up because of
  the unlocked route caching in if_stf. Add a mutex that protects
  access to cached route. Various versions of this patch were tested
  by Pekka Savola, Nick Sayer and Wouter Snels.
  
  Approved by:    re (gnn)

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/dev/twa/   (props changed)
  stable/7/sys/net/if_stf.c

Modified: stable/7/sys/net/if_stf.c
==============================================================================
--- stable/7/sys/net/if_stf.c   Tue Oct 14 19:02:47 2008        (r183892)
+++ stable/7/sys/net/if_stf.c   Tue Oct 14 19:48:58 2008        (r183893)
@@ -89,6 +89,7 @@
 #include <sys/protosw.h>
 #include <sys/proc.h>
 #include <sys/queue.h>
+#include <sys/sysctl.h>
 #include <machine/cpu.h>
 
 #include <sys/malloc.h>
@@ -119,6 +120,13 @@
 
 #include <security/mac/mac_framework.h>
 
+SYSCTL_DECL(_net_link);
+SYSCTL_NODE(_net_link, IFT_STF, stf, CTLFLAG_RW, 0, "6to4 Interface");
+
+static int stf_route_cache = 1;
+SYSCTL_INT(_net_link_stf, OID_AUTO, route_cache, CTLFLAG_RW,
+    &stf_route_cache, 0, "Caching of IPv4 routes for 6to4 Output");
+
 #define STFNAME                "stf"
 #define STFUNIT                0
 
@@ -137,15 +145,15 @@ struct stf_softc {
                struct route_in6 __sc_ro6; /* just for safety */
        } __sc_ro46;
 #define sc_ro  __sc_ro46.__sc_ro4
+       struct mtx      sc_ro_mtx;
        u_int   sc_fibnum;
        const struct encaptab *encap_cookie;
 };
 #define STF2IFP(sc)    ((sc)->sc_ifp)
 
 /*
- * XXXRW: Note that mutable fields in the softc are not currently locked:
- * in particular, sc_ro needs to be protected from concurrent entrance
- * of stf_output().
+ * Note that mutable fields in the softc are not currently locked.
+ * We do lock sc_ro in stf_output though.
  */
 static MALLOC_DEFINE(M_STF, STFNAME, "6to4 Tunnel Interface");
 static const int ip_stf_ttl = 40;
@@ -231,6 +239,7 @@ stf_clone_create(struct if_clone *ifc, c
        ifp->if_dname = ifc->ifc_name;
        ifp->if_dunit = IF_DUNIT_NONE;
 
+       mtx_init(&(sc)->sc_ro_mtx, "stf ro", NULL, MTX_DEF);
        sc->encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV6,
            stf_encapcheck, &in_stf_protosw, sc);
        if (sc->encap_cookie == NULL) {
@@ -257,6 +266,7 @@ stf_clone_destroy(struct if_clone *ifc, 
 
        err = encap_detach(sc->encap_cookie);
        KASSERT(err == 0, ("Unexpected error detaching encap_cookie"));
+       mtx_destroy(&(sc)->sc_ro_mtx);
        bpfdetach(ifp);
        if_detach(ifp);
        if_free(ifp);
@@ -398,6 +408,7 @@ stf_output(ifp, m, dst, rt)
 {
        struct stf_softc *sc;
        struct sockaddr_in6 *dst6;
+       struct route *cached_route;
        struct in_addr in4;
        caddr_t ptr;
        struct sockaddr_in *dst4;
@@ -406,9 +417,9 @@ stf_output(ifp, m, dst, rt)
        struct ip6_hdr *ip6;
        struct in6_ifaddr *ia6;
        u_int32_t af;
-#ifdef MAC
        int error;
 
+#ifdef MAC
        error = mac_check_ifnet_transmit(ifp, m);
        if (error) {
                m_freem(m);
@@ -507,9 +518,15 @@ stf_output(ifp, m, dst, rt)
        else
                ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos);
 
+       if (!stf_route_cache) {
+               cached_route = NULL;
+               goto sendit;
+       }
+
        /*
-        * XXXRW: Locking of sc_ro required.
+        * Do we have a cached route?
         */
+       mtx_lock(&(sc)->sc_ro_mtx);
        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) {
@@ -527,14 +544,21 @@ stf_output(ifp, m, dst, rt)
                rtalloc_fib(&sc->sc_ro, sc->sc_fibnum);
                if (sc->sc_ro.ro_rt == NULL) {
                        m_freem(m);
+                       mtx_unlock(&(sc)->sc_ro_mtx);
                        ifp->if_oerrors++;
                        return ENETUNREACH;
                }
        }
+       cached_route = &sc->sc_ro;
 
+sendit:
        M_SETFIB(m, sc->sc_fibnum);
        ifp->if_opackets++;
-       return ip_output(m, NULL, &sc->sc_ro, 0, NULL, NULL);
+       error = ip_output(m, NULL, cached_route, 0, NULL, NULL);
+
+       if (cached_route != NULL)
+               mtx_unlock(&(sc)->sc_ro_mtx);
+       return error;
 }
 
 static int
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to