Subject: HW assisted IPv4/TCP/UDP checksumming -- in-bound
To: None <tech-net@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-net
Date: 05/18/2001 10:10:56
Folks...
I've done the low-hanging fruit part of HW assisted IPv4/TCP/UDP
checksums -- in-bound processing. This is quite trivial. Note
that the mbuf m_pkthdr change will be used for out-bound processing
as well.
Also included are the diffs to make the DP83820 Gigabit Ethernet chip
do in-bound IPv4/TCP/UDP checksum processing.
Comments?
--
-- Jason R. Thorpe <thorpej@zembu.com>
Index: sys/mbuf.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/mbuf.h,v
retrieving revision 1.57
diff -c -r1.57 mbuf.h
*** sys/mbuf.h 2001/04/30 01:13:21 1.57
--- sys/mbuf.h 2001/05/18 16:59:01
***************
*** 1,7 ****
/* $NetBSD: mbuf.h,v 1.57 2001/04/30 01:13:21 lukem Exp $ */
/*-
! * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
--- 1,7 ----
/* $NetBSD: mbuf.h,v 1.57 2001/04/30 01:13:21 lukem Exp $ */
/*-
! * Copyright (c) 1996, 1997, 1999, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
***************
*** 115,123 ****
--- 115,131 ----
struct pkthdr {
struct ifnet *rcvif; /* rcv interface */
int len; /* total packet length */
+ int csuminfo; /* checksum information */
struct mbuf *aux; /* extra data buffer; ipsec/others */
};
+ #define M_CSUM_IPv4 0x0001 /* IPv4 header */
+ #define M_CSUM_IPv4_BAD 0x0002 /* IPv4 header checksum bad */
+ #define M_CSUM_TCPv4 0x0004 /* TCP header/payload */
+ #define M_CSUM_TCPv4_BAD 0x0008 /* TCP header/payload checksum bad */
+ #define M_CSUM_UDPv4 0x0010 /* UDP header/payload */
+ #define M_CSUM_UDPv4_BAD 0x0020 /* UDP header/payload checksum bad */
+
/* description of external storage mapped into mbuf, valid if M_EXT set */
struct m_ext {
caddr_t ext_buf; /* start of buffer */
***************
*** 246,251 ****
--- 254,260 ----
(m)->m_nextpkt = (struct mbuf *)NULL; \
(m)->m_data = (m)->m_pktdat; \
(m)->m_flags = M_PKTHDR; \
+ (m)->m_pkthdr.csuminfo = 0; \
(m)->m_pkthdr.aux = (struct mbuf *)NULL; \
} else \
(m) = m_retryhdr((how), (type)); \
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_input.c,v
retrieving revision 1.133
diff -c -r1.133 ip_input.c
*** netinet/ip_input.c 2001/04/16 17:03:33 1.133
--- netinet/ip_input.c 2001/05/18 16:59:01
***************
*** 433,439 ****
}
}
! if (in_cksum(m, hlen) != 0) {
ipstat.ips_badsum++;
goto bad;
}
--- 433,444 ----
}
}
! if (m->m_pkthdr.csuminfo & M_CSUM_IPv4) {
! if (m->m_pkthdr.csuminfo & M_CSUM_IPv4_BAD) {
! ipstat.ips_badsum++;
! goto bad;
! }
! } else if (in_cksum(m, hlen) != 0) {
ipstat.ips_badsum++;
goto bad;
}
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_input.c,v
retrieving revision 1.124
diff -c -r1.124 tcp_input.c
*** netinet/tcp_input.c 2001/05/08 10:15:13 1.124
--- netinet/tcp_input.c 2001/05/18 16:59:02
***************
*** 956,968 ****
bzero(ipov->ih_x1, sizeof ipov->ih_x1);
ipov->ih_len = htons(tlen + off);
! if (in_cksum(m, len) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
}
#else
! if (in4_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
--- 956,978 ----
bzero(ipov->ih_x1, sizeof ipov->ih_x1);
ipov->ih_len = htons(tlen + off);
! if (m->m_pkthdr.csuminfo & M_CSUM_TCPv4) {
! if (m->m_pkthdr.csuminfo & M_CSUM_TCPv4_BAD) {
! tcpstat.tcps_rcvbadsum++;
! goto drop;
! }
! } else if (in_cksum(m, len) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
}
#else
! if (m->m_pkthdr.csuminfo & M_CSUM_TCPv4) {
! if (m->m_pkthdr.csuminfo & M_CSUM_TCPv4_BAD) {
! tcpstat.tcps_rcvbadsum++;
! goto drop;
! }
! } else if (in4_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0) {
tcpstat.tcps_rcvbadsum++;
goto drop;
}
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/udp_usrreq.c,v
retrieving revision 1.76
diff -c -r1.76 udp_usrreq.c
*** netinet/udp_usrreq.c 2001/05/08 10:15:14 1.76
--- netinet/udp_usrreq.c 2001/05/18 16:59:02
***************
*** 254,260 ****
* Checksum extended UDP header and data.
*/
if (uh->uh_sum) {
! if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0) {
udpstat.udps_badsum++;
m_freem(m);
return;
--- 254,266 ----
* Checksum extended UDP header and data.
*/
if (uh->uh_sum) {
! if (m->m_pkthdr.csuminfo & M_CSUM_UDPv4) {
! if (m->m_pkthdr.csuminfo & M_CSUM_UDPv4_BAD) {
! udpstat.udps_badsum++;
! m_freem(m);
! return;
! }
! } else if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0) {
udpstat.udps_badsum++;
m_freem(m);
return;
***************
*** 945,957 ****
* Checksum extended UDP header and data.
*/
if (uh->uh_sum) {
! bzero(((struct ipovly *)ip)->ih_x1,
! sizeof ((struct ipovly *)ip)->ih_x1);
! ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
! if (in_cksum(m, len + sizeof (struct ip)) != 0) {
! udpstat.udps_badsum++;
! m_freem(m);
! return;
}
}
--- 951,971 ----
* Checksum extended UDP header and data.
*/
if (uh->uh_sum) {
! if (m->m_pkthdr.csuminfo & M_CSUM_UDPv4) {
! if (m->m_pkthdr.csuminfo & M_CSUM_UDPv4_BAD) {
! udpstat.udps_badsum++;
! m_freem(m);
! return;
! }
! } else {
! bzero(((struct ipovly *)ip)->ih_x1,
! sizeof ((struct ipovly *)ip)->ih_x1);
! ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
! if (in_cksum(m, len + sizeof (struct ip)) != 0) {
! udpstat.udps_badsum++;
! m_freem(m);
! return;
! }
}
}
Index: dev/pci/if_sip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_sip.c,v
retrieving revision 1.30
diff -c -r1.30 if_sip.c
*** dev/pci/if_sip.c 2001/05/18 04:38:30 1.30
--- dev/pci/if_sip.c 2001/05/18 16:59:03
***************
*** 1,3 ****
--- 1,5 ----
+ #define SIP_EVENT_COUNTERS
+ #define SIP_HWCSUM
/* $NetBSD: if_sip.c,v 1.30 2001/05/18 04:38:30 thorpej Exp $ */
/*-
***************
*** 250,255 ****
--- 252,260 ----
struct evcnt sc_ev_txdstall; /* Tx stalled due to no txd */
struct evcnt sc_ev_txintr; /* Tx interrupts */
struct evcnt sc_ev_rxintr; /* Rx interrupts */
+ struct evcnt sc_ev_rxipsum; /* IP checksums checked in-bound */
+ struct evcnt sc_ev_rxtcpsum; /* TCP checksums checked in-bound */
+ struct evcnt sc_ev_rxudpsum; /* UDP checksums checked in-boudn */
#endif /* SIP_EVENT_COUNTERS */
u_int32_t sc_txcfg; /* prototype TXCFG register */
***************
*** 812,817 ****
--- 817,828 ----
NULL, sc->sc_dev.dv_xname, "txintr");
evcnt_attach_dynamic(&sc->sc_ev_rxintr, EVCNT_TYPE_INTR,
NULL, sc->sc_dev.dv_xname, "rxintr");
+ evcnt_attach_dynamic(&sc->sc_ev_rxipsum, EVCNT_TYPE_MISC,
+ NULL, sc->sc_dev.dv_xname, "rxipsum");
+ evcnt_attach_dynamic(&sc->sc_ev_rxtcpsum, EVCNT_TYPE_MISC,
+ NULL, sc->sc_dev.dv_xname, "rxtcpsum");
+ evcnt_attach_dynamic(&sc->sc_ev_rxudpsum, EVCNT_TYPE_MISC,
+ NULL, sc->sc_dev.dv_xname, "rxudpsum");
#endif /* SIP_EVENT_COUNTERS */
/*
***************
*** 1547,1552 ****
--- 1558,1589 ----
*mtod(vtag, int *) = ntohs(extsts & EXTSTS_VTCI);
vtag->m_len = sizeof(int);
}
+
+ #ifdef SIP_HWCSUM
+ /*
+ * Set the incoming checksum information for the
+ * packet.
+ */
+ if (extsts & EXTSTS_IPPKT) {
+ SIP_EVCNT_INCR(&sc->sc_ev_rxipsum);
+ m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
+ if (extsts & EXTSTS_Rx_IPERR)
+ m->m_pkthdr.csuminfo |= M_CSUM_IPv4_BAD;
+ if (extsts & EXTSTS_TCPPKT) {
+ SIP_EVCNT_INCR(&sc->sc_ev_rxtcpsum);
+ m->m_pkthdr.csuminfo |= M_CSUM_TCPv4;
+ if (extsts & EXTSTS_Rx_TCPERR)
+ m->m_pkthdr.csuminfo |=
+ M_CSUM_TCPv4_BAD;
+ } else if (extsts & EXTSTS_UDPPKT) {
+ SIP_EVCNT_INCR(&sc->sc_ev_rxtcpsum);
+ m->m_pkthdr.csuminfo |= M_CSUM_UDPv4;
+ if (extsts & EXTSTS_Rx_UDPERR)
+ m->m_pkthdr.csuminfo |=
+ M_CSUM_UDPv4_BAD;
+ }
+ }
+ #endif /* SIP_HWCSUM */
#endif /* DP83820 */
/* Pass it on. */
***************
*** 1783,1798 ****
--- 1820,1847 ----
#ifdef DP83820
/*
* Initialize the VLAN/IP receive control register.
+ * We enable checksum computation on all incoming
+ * packets, and do not reject packets w/ bad checksums.
*/
+ #ifdef SIP_HWCSUM
+ reg = VRCR_IPEN;
+ #else
reg = 0;
+ #endif
if (sc->sc_ethercom.ec_nvlans != 0)
reg |= VRCR_VTDEN|VRCR_VTREN;
bus_space_write_4(st, sh, SIP_VRCR, reg);
/*
* Initialize the VLAN/IP transmit control register.
+ * We enable outgoing checksum computation on a
+ * per-packet basis.
*/
+ #ifdef SIP_HWCSUM
+ reg = VTCR_PPCHK;
+ #else
reg = 0;
+ #endif
if (sc->sc_ethercom.ec_nvlans != 0)
reg |= VTCR_VPPTI;
bus_space_write_4(st, sh, SIP_VTCR, reg);