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);