Module Name: src
Committed By: rin
Date: Wed Dec 12 01:46:47 UTC 2018
Modified Files:
src/sys/net: if.c if_bridge.c if_bridgevar.h
src/sys/rump/librump/rumpnet: net_stub.c
Log Message:
PR kern/53562
Handle TX offload in software when a packet is sent via
bridge_output(). We can send it as is in the following
exceptional cases:
For unicast:
(1) When the destination interface is the same as source.
(2) When the destination supports all TX offload options
specified in a packet.
For multicast/broadcast:
(3) When all the members of the bridge support the specified
TX offload options.
For (3), add sc_csum_flags_tx flag to bridge softc, which is
logical AND b/w capabilities of TX offload options in member
interface (ifp->if_csum_flags_tx). The flag is updated when a
member is (i) added to or (ii) removed from a bridge, or (iii)
if_csum_flags_tx flag of a member interface is manipulated via
ifconfig(8).
Turn on M_CSUM_TSOv[46] bit in ifp->if_csum_flags_tx flag when
TSO[46] is enabled for that interface.
OK msaitoh thorpej
To generate a diff of this commit:
cvs rdiff -u -r1.441 -r1.442 src/sys/net/if.c
cvs rdiff -u -r1.160 -r1.161 src/sys/net/if_bridge.c
cvs rdiff -u -r1.32 -r1.33 src/sys/net/if_bridgevar.h
cvs rdiff -u -r1.36 -r1.37 src/sys/rump/librump/rumpnet/net_stub.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.441 src/sys/net/if.c:1.442
--- src/sys/net/if.c:1.441 Thu Nov 15 10:23:56 2018
+++ src/sys/net/if.c Wed Dec 12 01:46:47 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if.c,v 1.441 2018/11/15 10:23:56 maxv Exp $ */
+/* $NetBSD: if.c,v 1.442 2018/12/12 01:46:47 rin Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.441 2018/11/15 10:23:56 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.442 2018/12/12 01:46:47 rin Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -149,6 +149,11 @@ __KERNEL_RCSID(0, "$NetBSD: if.c,v 1.441
#include "fddi.h"
#include "token.h"
+#include "bridge.h"
+#if NBRIDGE > 0
+#include <net/if_bridgevar.h>
+#endif
+
#include "carp.h"
#if NCARP > 0
#include <netinet/ip_carp.h>
@@ -2909,40 +2914,41 @@ ifioctl_common(struct ifnet *ifp, u_long
/* Pre-compute the checksum flags mask. */
ifp->if_csum_flags_tx = 0;
ifp->if_csum_flags_rx = 0;
- if (ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) {
+ if (ifp->if_capenable & IFCAP_CSUM_IPv4_Tx)
ifp->if_csum_flags_tx |= M_CSUM_IPv4;
- }
- if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) {
+ if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx)
ifp->if_csum_flags_rx |= M_CSUM_IPv4;
- }
- if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) {
+ if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx)
ifp->if_csum_flags_tx |= M_CSUM_TCPv4;
- }
- if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) {
+ if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx)
ifp->if_csum_flags_rx |= M_CSUM_TCPv4;
- }
- if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) {
+ if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx)
ifp->if_csum_flags_tx |= M_CSUM_UDPv4;
- }
- if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) {
+ if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx)
ifp->if_csum_flags_rx |= M_CSUM_UDPv4;
- }
- if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) {
+ if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx)
ifp->if_csum_flags_tx |= M_CSUM_TCPv6;
- }
- if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) {
+ if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx)
ifp->if_csum_flags_rx |= M_CSUM_TCPv6;
- }
- if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) {
+ if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx)
ifp->if_csum_flags_tx |= M_CSUM_UDPv6;
- }
- if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) {
+ if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx)
ifp->if_csum_flags_rx |= M_CSUM_UDPv6;
- }
+
+ if (ifp->if_capenable & IFCAP_TSOv4)
+ ifp->if_csum_flags_tx |= M_CSUM_TSOv4;
+ if (ifp->if_capenable & IFCAP_TSOv6)
+ ifp->if_csum_flags_tx |= M_CSUM_TSOv6;
+
+#if NBRIDGE > 0
+ if (ifp->if_bridge != NULL)
+ bridge_calc_csum_flags(ifp->if_bridge);
+#endif
+
if (ifp->if_flags & IFF_UP)
return ENETRESET;
return 0;
Index: src/sys/net/if_bridge.c
diff -u src/sys/net/if_bridge.c:1.160 src/sys/net/if_bridge.c:1.161
--- src/sys/net/if_bridge.c:1.160 Fri Nov 9 06:44:31 2018
+++ src/sys/net/if_bridge.c Wed Dec 12 01:46:47 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bridge.c,v 1.160 2018/11/09 06:44:31 ozaki-r Exp $ */
+/* $NetBSD: if_bridge.c,v 1.161 2018/12/12 01:46:47 rin Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.160 2018/11/09 06:44:31 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.161 2018/12/12 01:46:47 rin Exp $");
#ifdef _KERNEL_OPT
#include "opt_bridge_ipf.h"
@@ -112,6 +112,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_bridge.c,
#include <net/if_ether.h>
#include <net/if_bridgevar.h>
+#include <net/ether_sw_offload.h>
#if defined(BRIDGE_IPF)
/* Used for bridge_ip[6]_checkbasic */
@@ -123,7 +124,6 @@ __KERNEL_RCSID(0, "$NetBSD: if_bridge.c,
#include <netinet/ip6.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ip6_var.h>
#include <netinet6/ip6_private.h> /* XXX */
#endif /* BRIDGE_IPF */
@@ -750,6 +750,30 @@ bridge_delete_member(struct bridge_softc
BRIDGE_LOCK(sc);
}
+/*
+ * bridge_calc_csum_flags:
+ *
+ * Calculate logical and b/w csum flags each member interface supports.
+ */
+void
+bridge_calc_csum_flags(struct bridge_softc *sc)
+{
+ struct bridge_iflist *bif;
+ struct ifnet *ifs;
+ int flags = ~0;
+
+ BRIDGE_LOCK(sc);
+ BRIDGE_IFLIST_READER_FOREACH(bif, sc) {
+ ifs = bif->bif_ifp;
+ flags &= ifs->if_csum_flags_tx;
+ }
+ sc->sc_csum_flags_tx = flags;
+ BRIDGE_UNLOCK(sc);
+#ifdef DEBUG
+ printf("%s: 0x%x\n", __func__, flags);
+#endif
+}
+
static int
bridge_ioctl_add(struct bridge_softc *sc, void *arg)
{
@@ -827,12 +851,14 @@ bridge_ioctl_add(struct bridge_softc *sc
BRIDGE_UNLOCK(sc);
+ bridge_calc_csum_flags(sc);
+
if (sc->sc_if.if_flags & IFF_RUNNING)
bstp_initialization(sc);
else
bstp_stop(sc);
- out:
+out:
if_put(ifs, &psref);
if (error) {
if (bif != NULL)
@@ -890,6 +916,7 @@ bridge_ioctl_del(struct bridge_softc *sc
}
bridge_rtdelete(sc, ifs);
+ bridge_calc_csum_flags(sc);
if (sc->sc_if.if_flags & IFF_RUNNING)
bstp_initialization(sc);
@@ -1086,7 +1113,7 @@ bridge_ioctl_rts(struct bridge_softc *sc
count++;
len -= sizeof(bareq);
}
- out:
+out:
BRIDGE_RT_UNLOCK(sc);
bac->ifbac_len = sizeof(bareq) * count;
@@ -1460,6 +1487,7 @@ bridge_output(struct ifnet *ifp, struct
struct ether_header *eh;
struct ifnet *dst_if;
struct bridge_softc *sc;
+ struct mbuf *n;
int s;
/*
@@ -1493,7 +1521,7 @@ bridge_output(struct ifnet *ifp, struct
if (__predict_false(sc == NULL) ||
(sc->sc_if.if_flags & IFF_RUNNING) == 0) {
dst_if = ifp;
- goto sendunicast;
+ goto unicast_asis;
}
/*
@@ -1504,13 +1532,85 @@ bridge_output(struct ifnet *ifp, struct
dst_if = NULL;
else
dst_if = bridge_rtlookup(sc, eh->ether_dhost);
- if (dst_if == NULL) {
+
+ /*
+ * In general, we need to handle TX offload in software before
+ * enqueueing a packet. However, we can send it as is in the
+ * cases of unicast via (1) the source interface, or (2) an
+ * interface which supports the specified offload options.
+ * For multicast or broadcast, send it as is only if (3) all
+ * the member interfaces support the specified options.
+ */
+
+ /*
+ * Unicast via the source interface.
+ */
+ if (dst_if == ifp)
+ goto unicast_asis;
+
+ /*
+ * Unicast via other interface.
+ */
+ if (dst_if != NULL) {
+ KASSERT(m->m_flags & M_PKTHDR);
+ if (TX_OFFLOAD_SUPPORTED(dst_if->if_csum_flags_tx,
+ m->m_pkthdr.csum_flags)) {
+ /*
+ * Unicast via an interface which supports the
+ * specified offload options.
+ */
+ goto unicast_asis;
+ }
+
+ /*
+ * Handle TX offload in software. For TSO, a packet is
+ * split into multiple chunks. Thus, the return value of
+ * ether_sw_offload_tx() is mbuf chain consists of them.
+ */
+ m = ether_sw_offload_tx(ifp, m);
+ if (m == NULL)
+ return 0;
+
+ do {
+ n = m->m_nextpkt;
+ if ((dst_if->if_flags & IFF_RUNNING) == 0)
+ m_freem(m);
+ else
+ bridge_enqueue(sc, dst_if, m, 0);
+ m = n;
+ } while (m != NULL);
+
+ return 0;
+ }
+
+ /*
+ * Multicast or broadcast.
+ */
+ if (TX_OFFLOAD_SUPPORTED(sc->sc_csum_flags_tx,
+ m->m_pkthdr.csum_flags)) {
+ /*
+ * Specified TX offload options are supported by all
+ * the member interfaces of this bridge.
+ */
+ m->m_nextpkt = NULL; /* XXX */
+ } else {
+ /*
+ * Otherwise, handle TX offload in software.
+ */
+ m = ether_sw_offload_tx(ifp, m);
+ if (m == NULL)
+ return 0;
+ }
+
+ do {
/* XXX Should call bridge_broadcast, but there are locking
* issues which need resolving first. */
struct bridge_iflist *bif;
struct mbuf *mc;
bool used = false;
+ n = m->m_nextpkt;
+
BRIDGE_PSZ_RENTER(s);
BRIDGE_IFLIST_READER_FOREACH(bif, sc) {
struct psref psref;
@@ -1594,21 +1694,19 @@ next:
if (!used)
m_freem(m);
- return 0;
- }
- sendunicast:
+ m = n;
+ } while (m != NULL);
+ return 0;
+
+unicast_asis:
/*
* XXX Spanning tree consideration here?
*/
-
- if ((dst_if->if_flags & IFF_RUNNING) == 0) {
+ if ((dst_if->if_flags & IFF_RUNNING) == 0)
m_freem(m);
- return 0;
- }
-
- bridge_enqueue(sc, dst_if, m, 0);
-
+ else
+ bridge_enqueue(sc, dst_if, m, 0);
return 0;
}
Index: src/sys/net/if_bridgevar.h
diff -u src/sys/net/if_bridgevar.h:1.32 src/sys/net/if_bridgevar.h:1.33
--- src/sys/net/if_bridgevar.h:1.32 Wed Apr 18 04:01:58 2018
+++ src/sys/net/if_bridgevar.h Wed Dec 12 01:46:47 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bridgevar.h,v 1.32 2018/04/18 04:01:58 ozaki-r Exp $ */
+/* $NetBSD: if_bridgevar.h,v 1.33 2018/12/12 01:46:47 rin Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -327,6 +327,7 @@ struct bridge_softc {
struct work sc_rtage_wk;
uint32_t sc_rthash_key; /* key for hash */
uint32_t sc_filter_flags; /* ipf and flags */
+ int sc_csum_flags_tx;
};
extern const uint8_t bstp_etheraddr[];
@@ -343,6 +344,8 @@ void bstp_input(struct bridge_softc *, s
void bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *,
int);
+void bridge_calc_csum_flags(struct bridge_softc *);
+
#define BRIDGE_LOCK(_sc) mutex_enter(&(_sc)->sc_iflist_psref.bip_lock)
#define BRIDGE_UNLOCK(_sc) mutex_exit(&(_sc)->sc_iflist_psref.bip_lock)
#define BRIDGE_LOCKED(_sc) mutex_owned(&(_sc)->sc_iflist_psref.bip_lock)
Index: src/sys/rump/librump/rumpnet/net_stub.c
diff -u src/sys/rump/librump/rumpnet/net_stub.c:1.36 src/sys/rump/librump/rumpnet/net_stub.c:1.37
--- src/sys/rump/librump/rumpnet/net_stub.c:1.36 Mon May 14 17:34:26 2018
+++ src/sys/rump/librump/rumpnet/net_stub.c Wed Dec 12 01:46:47 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: net_stub.c,v 1.36 2018/05/14 17:34:26 maxv Exp $ */
+/* $NetBSD: net_stub.c,v 1.37 2018/12/12 01:46:47 rin Exp $ */
/*
* Copyright (c) 2008 Antti Kantee. All Rights Reserved.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: net_stub.c,v 1.36 2018/05/14 17:34:26 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: net_stub.c,v 1.37 2018/12/12 01:46:47 rin Exp $");
#include <sys/mutex.h>
#include <sys/param.h>
@@ -63,6 +63,7 @@ rumpnet_stub(void)
/* bridge */
__weak_alias(bridge_ifdetach,rumpnet_stub);
__weak_alias(bridge_output,rumpnet_stub);
+__weak_alias(bridge_calc_csum_flags,rumpnet_stub);
/* agr */
__weak_alias(agr_input,rumpnet_stub);