Source-Changes-HG archive

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

[src/trunk]: src/sys PR kern/53562



details:   https://anonhg.NetBSD.org/src/rev/dc992e5d2f5e
branches:  trunk
changeset: 446588:dc992e5d2f5e
user:      rin <rin%NetBSD.org@localhost>
date:      Wed Dec 12 01:46:47 2018 +0000

description:
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

diffstat:

 sys/net/if.c                        |   58 ++++++++------
 sys/net/if_bridge.c                 |  134 +++++++++++++++++++++++++++++++----
 sys/net/if_bridgevar.h              |    5 +-
 sys/rump/librump/rumpnet/net_stub.c |    5 +-
 4 files changed, 155 insertions(+), 47 deletions(-)

diffs (truncated from 381 to 300 lines):

diff -r 8e52348cb132 -r dc992e5d2f5e sys/net/if.c
--- a/sys/net/if.c      Wed Dec 12 01:40:20 2018 +0000
+++ b/sys/net/if.c      Wed Dec 12 01:46:47 2018 +0000
@@ -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 @@
 #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 @@
                /* 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;
diff -r 8e52348cb132 -r dc992e5d2f5e sys/net/if_bridge.c
--- a/sys/net/if_bridge.c       Wed Dec 12 01:40:20 2018 +0000
+++ b/sys/net/if_bridge.c       Wed Dec 12 01:46:47 2018 +0000
@@ -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 @@
 
 #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 @@
 
 #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_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_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_rtdelete(sc, ifs);
+       bridge_calc_csum_flags(sc);
 
        if (sc->sc_if.if_flags & IFF_RUNNING)
                bstp_initialization(sc);
@@ -1086,7 +1113,7 @@
                count++;
                len -= sizeof(bareq);
        }
- out:
+out:
        BRIDGE_RT_UNLOCK(sc);
 
        bac->ifbac_len = sizeof(bareq) * count;
@@ -1460,6 +1487,7 @@
        struct ether_header *eh;
        struct ifnet *dst_if;
        struct bridge_softc *sc;
+       struct mbuf *n;
        int s;
 
        /*
@@ -1493,7 +1521,7 @@
        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 @@
                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 @@
 



Home | Main Index | Thread Index | Old Index