tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/40137: gem(4) drops TCP packets with tcp4csum-tx when on a bridge(4)



This is not a gem(4)-specific problem but common to all the
modern (offloading) NICs.  Here's a patch to fix this.  It
is for 5.0.2 but should basically be applicable to -current,
unless I've missed some changes such as intruduction of
kernel mutexes etc :)  By this patch a bridge(4) now has
capability flags when all the members have their offloading
engine (AND'ed).


Index: net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.230.4.1
diff -u -r1.230.4.1 if.c
--- net/if.c    24 Feb 2009 02:26:42 -0000      1.230.4.1
+++ net/if.c    8 Mar 2010 13:50:04 -0000
@@ -97,6 +97,7 @@
 #include "opt_atalk.h"
 #include "opt_natm.h"
 #include "opt_pfil_hooks.h"
+#include "bridge.h"
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -117,6 +118,9 @@
 #include <net/if_dl.h>
 #include <net/if_ether.h>
 #include <net/if_media.h>
+#if NBRIDGE > 0
+#include <net/if_bridgevar.h>
+#endif
 #include <net80211/ieee80211.h>
 #include <net80211/ieee80211_ioctl.h>
 #include <net/if_types.h>
@@ -518,6 +522,7 @@
        ifp->if_link_state = LINK_STATE_UNKNOWN;
 
        ifp->if_capenable = 0;
+       ifp->if_tso = 0;
        ifp->if_csum_flags_tx = 0;
        ifp->if_csum_flags_rx = 0;
 
@@ -1466,6 +1471,14 @@
                if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) {
                        ifp->if_csum_flags_rx |= M_CSUM_UDPv6;
                }
+               ifp->if_tso = ifp->if_capenable & (IFCAP_TSOv4|IFCAP_TSOv6);
+#if NBRIDGE > 0
+               if (ifp->if_bridge) {
+                       s = splnet();
+                       bridge_update_capflags(ifp->if_bridge);
+                       splx(s);
+               }
+#endif
                if (ifp->if_flags & IFF_UP)
                        return ENETRESET;
                return 0;
Index: net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.140
diff -u -r1.140 if.h
--- net/if.h    24 Oct 2008 17:07:33 -0000      1.140
+++ net/if.h    8 Mar 2010 13:50:04 -0000
@@ -275,6 +275,7 @@
        struct pfil_head if_pfil;       /* filtering point */
        uint64_t if_capabilities;       /* interface capabilities */
        uint64_t if_capenable;          /* capabilities enabled */
+       uint64_t if_tso;                /* TSO flags */
        union {
                void *          carp_s; /* carp structure (used by !carp ifs) */
                struct ifnet    *carp_d;/* ptr to carpdev (used by carp ifs) */
Index: net/if_bridge.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_bridge.c,v
retrieving revision 1.62.6.4
diff -u -r1.62.6.4 if_bridge.c
--- net/if_bridge.c     4 Apr 2009 18:03:06 -0000       1.62.6.4
+++ net/if_bridge.c     8 Mar 2010 13:50:05 -0000
@@ -173,6 +173,16 @@
 #define        BRIDGE_RTABLE_PRUNE_PERIOD      (5 * 60)
 #endif
 
+/*
+ * Convert if_capenable to if_csum_flags_tx.
+ */
+#define CSUM_FLAGS_TX(capenable)       \
+       ((((capenable) & IFCAP_CSUM_IPv4_Tx)?M_CSUM_IPv4:0) |   \
+        (((capenable) & IFCAP_CSUM_TCPv4_Tx)?M_CSUM_TCPv4:0) | \
+        (((capenable) & IFCAP_CSUM_UDPv4_Tx)?M_CSUM_UDPv4:0) | \
+        (((capenable) & IFCAP_CSUM_TCPv6_Tx)?M_CSUM_TCPv6:0) | \
+        (((capenable) & IFCAP_CSUM_UDPv6_Tx)?M_CSUM_UDPv6:0))
+
 int    bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
 
 static struct pool bridge_rtnode_pool;
@@ -588,7 +598,11 @@
        }
 
        ifs->if_bridge = NULL;
+       ifs->if_tso = ifs->if_capenable & (IFCAP_TSOv4|IFCAP_TSOv6);
+       ifs->if_csum_flags_tx = CSUM_FLAGS_TX(ifs->if_capenable);
+
        LIST_REMOVE(bif, bif_next);
+       bridge_update_capflags(sc);
 
        bridge_rtdelete(sc, ifs);
 
@@ -644,6 +658,7 @@
 
        ifs->if_bridge = sc;
        LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next);
+       bridge_update_capflags(sc);
 
        if (sc->sc_if.if_flags & IFF_RUNNING)
                bstp_initialization(sc);
@@ -1125,11 +1140,6 @@
        int len, error;
        short mflags;
 
-       /*
-        * Clear any in-bound checksum flags for this packet.
-        */
-       m->m_pkthdr.csum_flags = 0;
-
 #ifdef PFIL_HOOKS
        if (runfilt) {
                if (pfil_run_hooks(&sc->sc_if.if_pfil, &m,
@@ -2256,3 +2266,32 @@
 }
 # endif /* INET6 */
 #endif /* BRIDGE_IPF && PFIL_HOOKS */
+
+void
+bridge_update_capflags(struct bridge_softc *sc)
+{
+       uint64_t capabilities = ~0;
+       uint64_t capenable = ~0;
+       struct bridge_iflist *bif;
+       int tso = 0, csum_flags_tx = 0;
+
+       LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+               capabilities &= bif->bif_ifp->if_capabilities;
+               capenable &= bif->bif_ifp->if_capenable;
+       }
+       if (capabilities == ~0) { /* nobody here */
+               sc->sc_if.if_capabilities = 0;
+               sc->sc_if.if_capenable = 0;
+               return;
+       }
+       sc->sc_if.if_capabilities = capabilities;
+       sc->sc_if.if_capenable = capenable;
+
+       tso = capenable & (IFCAP_TSOv4|IFCAP_TSOv6);
+       csum_flags_tx = CSUM_FLAGS_TX(capenable);
+
+       LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+               bif->bif_ifp->if_tso = tso;
+               bif->bif_ifp->if_csum_flags_tx = csum_flags_tx;
+       }
+}
Index: net/if_bridgevar.h
===================================================================
RCS file: /cvsroot/src/sys/net/if_bridgevar.h,v
retrieving revision 1.11.46.1
diff -u -r1.11.46.1 if_bridgevar.h
--- net/if_bridgevar.h  4 Apr 2009 18:00:03 -0000       1.11.46.1
+++ net/if_bridgevar.h  8 Mar 2010 13:50:05 -0000
@@ -318,5 +318,7 @@
 void   bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *,
            int);
 
+void   bridge_update_capflags(struct bridge_softc *);
+
 #endif /* _KERNEL */
 #endif /* !_NET_IF_BRIDGEVAR_H_ */
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_output.c,v
retrieving revision 1.200.10.1
diff -u -r1.200.10.1 ip_output.c
--- netinet/ip_output.c 9 Jul 2009 19:35:56 -0000       1.200.10.1
+++ netinet/ip_output.c 8 Mar 2010 13:50:06 -0000
@@ -825,7 +825,7 @@
 
                if (__predict_true(
                    (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) == 0 ||
-                   (ifp->if_capenable & IFCAP_TSOv4) != 0)) {
+                   (ifp->if_tso & IFCAP_TSOv4) != 0)) {
                        error =
                            (*ifp->if_output)(ifp, m,
                                (m->m_flags & M_MCAST) ?
Index: netinet/tcp_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_output.c,v
retrieving revision 1.167
diff -u -r1.167 tcp_output.c
--- netinet/tcp_output.c        28 Apr 2008 20:24:09 -0000      1.167
+++ netinet/tcp_output.c        8 Mar 2010 13:50:06 -0000
@@ -637,7 +637,7 @@
                                       IPSEC_DIR_OUTBOUND) &&
 #endif
                  (rt = rtcache_validate(&tp->t_inpcb->inp_route)) != NULL &&
-                 (rt->rt_ifp->if_capenable & IFCAP_TSOv4) != 0;
+                 (rt->rt_ifp->if_tso & IFCAP_TSOv4) != 0;
 #endif /* defined(INET) */
 #if defined(INET6)
        has_tso6 = tp->t_in6pcb != NULL &&
@@ -646,7 +646,7 @@
                                       IPSEC_DIR_OUTBOUND) &&
 #endif
                  (rt = rtcache_validate(&tp->t_in6pcb->in6p_route)) != NULL &&
-                 (rt->rt_ifp->if_capenable & IFCAP_TSOv6) != 0;
+                 (rt->rt_ifp->if_tso & IFCAP_TSOv6) != 0;
 #endif /* defined(INET6) */
        has_tso = (has_tso4 || has_tso6) && !alwaysfrag;
 
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.135.2.1
diff -u -r1.135.2.1 ip6_output.c
--- netinet6/ip6_output.c       20 Apr 2009 22:56:04 -0000      1.135.2.1
+++ netinet6/ip6_output.c       8 Mar 2010 13:50:08 -0000
@@ -980,7 +980,7 @@
 
                KASSERT(dst != NULL);
                if (__predict_true(!tso ||
-                   (ifp->if_capenable & IFCAP_TSOv6) != 0)) {
+                   (ifp->if_tso & IFCAP_TSOv6) != 0)) {
                        error = nd6_output(ifp, origifp, m, dst, rt);
                } else {
                        error = ip6_tso_output(ifp, origifp, m, dst, rt);


Home | Main Index | Thread Index | Old Index