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