Source-Changes-HG archive

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

[src/trunk]: src/sys Implement support for IP/TCP/UDP checksum offloading pro...



details:   https://anonhg.NetBSD.org/src/rev/36b7fceeb725
branches:  trunk
changeset: 510611:36b7fceeb725
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Sat Jun 02 16:17:09 2001 +0000

description:
Implement support for IP/TCP/UDP checksum offloading provided by
network interfaces.  This works by pre-computing the pseudo-header
checksum and caching it, delaying the actual checksum to ip_output()
if the hardware cannot perform the sum for us.  In-bound checksums
can either be fully-checked by hardware, or summed up for final
verification by software.  This method was modeled after how this
is done in FreeBSD, although the code is significantly different in
most places.

We don't delay checksums for IPv6/TCP, but we do take advantage of the
cached pseudo-header checksum.

Note: hardware-assisted checksumming defaults to "off".  It is
enabled with ifconfig(8).  See the manual page for details.

Implement hardware-assisted checksumming on the DP83820 Gigabit Ethernet,
3c90xB/3c90xC 10/100 Ethernet, and Alteon Tigon/Tigon2 Gigabit Ethernet.

diffstat:

 sys/netinet/fil.c        |   19 ++++++-
 sys/netinet/in.h         |   50 ++++++++++++++++++-
 sys/netinet/ip_fil.c     |   18 ++++++-
 sys/netinet/ip_flow.c    |   30 +++++++++-
 sys/netinet/ip_input.c   |   58 ++++++++++++++++++++-
 sys/netinet/ip_mroute.c  |    7 ++-
 sys/netinet/ip_output.c  |   81 +++++++++++++++++++++++++++++-
 sys/netinet/tcp_input.c  |   80 ++++++++++++++++++++++--------
 sys/netinet/tcp_output.c |   47 +++++++++++------
 sys/netinet/tcp_subr.c   |   50 +++++++++++++++++-
 sys/netinet/udp_usrreq.c |  123 +++++++++++++++++++++++++++++++++++++++-------
 sys/netinet6/in6.h       |   51 +++++++++++++++++++-
 sys/sys/mbuf.h           |   36 ++++++++++++-
 sys/sys/sockio.h         |    4 +-
 14 files changed, 570 insertions(+), 84 deletions(-)

diffs (truncated from 1124 to 300 lines):

diff -r aeea6ccf7276 -r 36b7fceeb725 sys/netinet/fil.c
--- a/sys/netinet/fil.c Sat Jun 02 16:17:08 2001 +0000
+++ b/sys/netinet/fil.c Sat Jun 02 16:17:09 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fil.c,v 1.46 2001/03/26 06:13:12 mike Exp $    */
+/*     $NetBSD: fil.c,v 1.47 2001/06/02 16:17:09 thorpej Exp $ */
 
 /*
  * Copyright (C) 1993-2000 by Darren Reed.
@@ -9,7 +9,7 @@
  */
 #if !defined(lint)
 #if defined(__NetBSD__)
-static const char rcsid[] = "$NetBSD: fil.c,v 1.46 2001/03/26 06:13:12 mike Exp $";
+static const char rcsid[] = "$NetBSD: fil.c,v 1.47 2001/06/02 16:17:09 thorpej Exp $";
 #else
 static const char sccsid[] = "@(#)fil.c        1.36 6/5/96 (C) 1993-2000 Darren Reed";
 static const char rcsid[] = "@(#)Id: fil.c,v 2.35.2.30 2000/12/17 05:49:22 darrenr Exp";
@@ -764,6 +764,21 @@
        struct ip *ip = mtod(*mp, struct ip *);
        int rv, hlen = ip->ip_hl << 2;
 
+#if defined(M_CSUM_TCPv4)
+       /*
+        * If the packet is out-bound, we can't delay checksums
+        * here.  For in-bound, the checksum has already been
+        * validated.
+        */
+       if (dir == PFIL_OUT) {
+               if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
+                       in_delayed_cksum(*mp);
+                       (*mp)->m_pkthdr.csum_flags &=
+                           ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
+               }
+       }
+#endif /* M_CSUM_TCPv4 */
+
        /*
         * We get the packet with all fields in network byte
         * order.  We expect ip_len and ip_off to be in host
diff -r aeea6ccf7276 -r 36b7fceeb725 sys/netinet/in.h
--- a/sys/netinet/in.h  Sat Jun 02 16:17:08 2001 +0000
+++ b/sys/netinet/in.h  Sat Jun 02 16:17:09 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: in.h,v 1.54 2001/05/27 23:46:51 itojun Exp $   */
+/*     $NetBSD: in.h,v 1.55 2001/06/02 16:17:09 thorpej Exp $  */
 
 /*
  * Copyright (c) 1982, 1986, 1990, 1993
@@ -387,6 +387,53 @@
 #undef __KAME_NETINET_IN_H_INCLUDED_
 
 #ifdef _KERNEL
+/*
+ * in_cksum_phdr:
+ *
+ *     Compute significant parts of the IPv4 checksum pseudo-header
+ *     for use in a delayed TCP/UDP checksum calculation.
+ *
+ *     Args:
+ *
+ *             src             Source IP address
+ *             dst             Destination IP address
+ *             lenproto        htons(proto-hdr-len + proto-number)
+ */
+static __inline u_int16_t __attribute__((__unused__))
+in_cksum_phdr(u_int32_t src, u_int32_t dst, u_int32_t lenproto)
+{
+       u_int32_t sum;
+
+       sum = lenproto +
+             (u_int16_t)(src >> 16) +
+             (u_int16_t)(src /*& 0xffff*/) +
+             (u_int16_t)(dst >> 16) +
+             (u_int16_t)(dst /*& 0xffff*/);
+
+       sum = (u_int16_t)(sum >> 16) + (u_int16_t)(sum /*& 0xffff*/);
+
+       if (sum > 0xffff)
+               sum -= 0xffff;
+
+       return (sum);
+}
+
+/*
+ * in_cksum_addword:
+ *
+ *     Add the two 16-bit network-order values, carry, and return.
+ */
+static __inline u_int16_t __attribute__((__unused__))
+in_cksum_addword(u_int16_t a, u_int16_t b)
+{
+       u_int32_t sum = a + b;
+
+       if (sum > 0xffff)
+               sum -= 0xffff;
+
+       return (sum);
+}
+
 extern struct in_addr zeroin_addr;
 extern u_char  ip_protox[];
 
@@ -394,6 +441,7 @@
 int    in_canforward __P((struct in_addr));
 int    in_cksum __P((struct mbuf *, int));
 int    in4_cksum __P((struct mbuf *, u_int8_t, int, int));
+void   in_delayed_cksum __P((struct mbuf *));
 int    in_localaddr __P((struct in_addr));
 void   in_socktrim __P((struct sockaddr_in *));
 
diff -r aeea6ccf7276 -r 36b7fceeb725 sys/netinet/ip_fil.c
--- a/sys/netinet/ip_fil.c      Sat Jun 02 16:17:08 2001 +0000
+++ b/sys/netinet/ip_fil.c      Sat Jun 02 16:17:09 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_fil.c,v 1.67 2001/05/12 19:21:57 christos Exp $     */
+/*     $NetBSD: ip_fil.c,v 1.68 2001/06/02 16:17:09 thorpej Exp $      */
 
 /*
  * Copyright (C) 1993-2000 by Darren Reed.
@@ -9,7 +9,7 @@
  */
 #if !defined(lint)
 #if defined(__NetBSD__)
-static const char rcsid[] = "$NetBSD: ip_fil.c,v 1.67 2001/05/12 19:21:57 christos Exp $";
+static const char rcsid[] = "$NetBSD: ip_fil.c,v 1.68 2001/06/02 16:17:09 thorpej Exp $";
 #else
 static const char sccsid[] = "@(#)ip_fil.c     2.41 6/5/96 (C) 1993-2000 Darren Reed";
 static const char rcsid[] = "@(#)Id: ip_fil.c,v 2.42.2.17 2000/10/19 15:39:42 darrenr Exp";
@@ -1384,6 +1384,13 @@
        struct route iproute;
        frentry_t *fr;
 
+#if defined(__NetBSD__) && defined(M_CSUM_IPv4)
+       /*
+        * Clear any in-bound checksum flags for this packet.
+        */
+       m0->m_pkthdr.csum_flags = 0;
+#endif /* __NetBSD__ && M_CSUM_IPv4 */
+
        hlen = fin->fin_hlen;
        ip = mtod(m0, struct ip *);
 
@@ -1491,8 +1498,15 @@
 # endif
                ip->ip_len = htons(ip->ip_len);
                ip->ip_off = htons(ip->ip_off);
+# if defined(__NetBSD__) && defined(M_CSUM_IPv4)
+               if (ifp->if_csum_flags & M_CSUM_IPv4)
+                       m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
+               else if (ip->ip_sum == 0)
+                       ip->ip_sum = in_cksum(m, hlen);
+# else
                if (!ip->ip_sum)
                        ip->ip_sum = in_cksum(m, hlen);
+# endif /* __NetBSD__ && M_CSUM_IPv4 */
 # if   BSD >= 199306
                error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
                                          ro->ro_rt);
diff -r aeea6ccf7276 -r 36b7fceeb725 sys/netinet/ip_flow.c
--- a/sys/netinet/ip_flow.c     Sat Jun 02 16:17:08 2001 +0000
+++ b/sys/netinet/ip_flow.c     Sat Jun 02 16:17:09 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_flow.c,v 1.17 2001/04/13 23:30:22 thorpej Exp $     */
+/*     $NetBSD: ip_flow.c,v 1.18 2001/06/02 16:17:09 thorpej Exp $     */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -179,10 +179,24 @@
                return 0;
 
        /*
-        * Veryify the IP header checksum.
+        * Verify the IP header checksum.
         */
-       if (in_cksum(m, sizeof(struct ip)) != 0)
-               return 0;
+       switch (m->m_pkthdr.csum_flags &
+               ((m->m_pkthdr.rcvif->if_csum_flags & M_CSUM_IPv4) |
+                M_CSUM_IPv4_BAD)) {
+       case M_CSUM_IPv4|M_CSUM_IPv4_BAD:
+               return (0);
+
+       case M_CSUM_IPv4:
+               /* Checksum was okay. */
+               break;
+
+       default:
+               /* Must compute it ourselves. */
+               if (in_cksum(m, sizeof(struct ip)) != 0)
+                       return (0);
+               break;
+       }
 
        /*
         * Route and interface still up?
@@ -199,12 +213,20 @@
                return 0;
 
        /*
+        * Clear any in-bound checksum flags for this packet.
+        */
+       m->m_pkthdr.csum_flags = 0;
+
+       /*
         * Everything checks out and so we can forward this packet.
         * Modify the TTL and incrementally change the checksum.
         * 
         * This method of adding the checksum works on either endian CPU.
         * If htons() is inlined, all the arithmetic is folded; otherwise
         * the htons()s are combined by CSE due to the __const__ attribute.
+        *
+        * Don't bother using HW checksumming here -- the incremental
+        * update is pretty fast.
         */
        ip->ip_ttl -= IPTTLDEC;
        if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8))
diff -r aeea6ccf7276 -r 36b7fceeb725 sys/netinet/ip_input.c
--- a/sys/netinet/ip_input.c    Sat Jun 02 16:17:08 2001 +0000
+++ b/sys/netinet/ip_input.c    Sat Jun 02 16:17:09 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_input.c,v 1.134 2001/05/21 03:31:36 lukem Exp $     */
+/*     $NetBSD: ip_input.c,v 1.135 2001/06/02 16:17:09 thorpej Exp $   */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -105,6 +105,7 @@
 #include "opt_pfil_hooks.h"
 #include "opt_ipsec.h"
 #include "opt_mrouting.h"
+#include "opt_inet_csum.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -270,6 +271,24 @@
 
 struct pool ipqent_pool;
 
+#ifdef INET_CSUM_COUNTERS
+#include <sys/device.h>
+
+struct evcnt ip_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "inet", "hwcsum bad");
+struct evcnt ip_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "inet", "hwcsum ok");
+struct evcnt ip_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
+    NULL, "inet", "swcsum");
+
+#define        INET_CSUM_COUNTER_INCR(ev)      (ev)->ev_count++
+
+#else
+
+#define        INET_CSUM_COUNTER_INCR(ev)      /* nothing */
+
+#endif /* INET_CSUM_COUNTERS */
+
 /*
  * We need to save the IP options in case a protocol wants to respond
  * to an incoming packet over the same route if the packet got here
@@ -332,6 +351,12 @@
                printf("ip_init: WARNING: unable to register pfil hook, "
                    "error %d\n", i);
 #endif /* PFIL_HOOKS */
+
+#ifdef INET_CSUM_COUNTERS
+       evcnt_attach_static(&ip_hwcsum_bad);
+       evcnt_attach_static(&ip_hwcsum_ok);
+       evcnt_attach_static(&ip_swcsum);
+#endif /* INET_CSUM_COUNTERS */
 }
 
 struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
@@ -433,9 +458,24 @@
                }
        }
 
-       if (in_cksum(m, hlen) != 0) {
-               ipstat.ips_badsum++;
-               goto bad;
+       switch (m->m_pkthdr.csum_flags &
+               ((m->m_pkthdr.rcvif->if_csum_flags & M_CSUM_IPv4) |
+                M_CSUM_IPv4_BAD)) {
+       case M_CSUM_IPv4|M_CSUM_IPv4_BAD:
+               INET_CSUM_COUNTER_INCR(&ip_hwcsum_bad);
+               goto badcsum;
+
+       case M_CSUM_IPv4:
+               /* Checksum was okay. */
+               INET_CSUM_COUNTER_INCR(&ip_hwcsum_ok);
+               break;
+
+       default:
+               /* Must compute it ourselves. */
+               INET_CSUM_COUNTER_INCR(&ip_swcsum);
+               if (in_cksum(m, hlen) != 0)
+                       goto bad;
+               break;
        }
 
        /* Retrieve the packet length. */



Home | Main Index | Thread Index | Old Index