NetBSD-Bugs 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)



The following reply was made to PR kern/40137; it has been noted by GNATS.

From: David Holland <dholland-bugs%netbsd.org@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: kern/40137: gem(4) drops TCP packets with tcp4csum-tx when on
        a bridge(4)
Date: Sun, 14 Mar 2010 19:40:32 +0000

 (not sent to gnats)
 
    ------
 
 From: MINOURA Makoto <minoura%netbsd.org@localhost>
 To: gnats-admin%netbsd.org@localhost, netbsd-bugs%NetBSD.org@localhost
 Cc: tech-net%NetBSD.org@localhost
 Subject: Re: kern/40137: gem(4) drops TCP packets with tcp4csum-tx when on a
        bridge(4) 
 Date: Wed, 10 Mar 2010 22:14:23 +0900
 
 
 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