[gPXE-devel] [PATCH 1/2] [net] Adding RX packet checksum offload support

Guo-Fu Tseng cooldavid at cooldavid.org
Fri Jul 30 09:02:18 EDT 2010


From: Guo-Fu Tseng <cooldavid at cooldavid.org>

Add a field in struct io_buffer to pass checksum status from hardware.
If the hardware dose not support just ignore this field, it'll work as
usual.

I see that net/ipv6 does not check for checksum, so I temporary ignored
it.

Signed-off-by: Guo-Fu Tseng <cooldavid at cooldavid.org>
---
 src/core/iobuf.c         |    1 +
 src/include/gpxe/iobuf.h |   13 +++++++++++++
 src/net/ipv4.c           |    8 +++++---
 src/net/tcp.c            |   18 ++++++++++--------
 src/net/udp.c            |    2 +-
 5 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/src/core/iobuf.c b/src/core/iobuf.c
index 1ce7890..731a3c7 100644
--- a/src/core/iobuf.c
+++ b/src/core/iobuf.c
@@ -58,6 +58,7 @@ struct io_buffer * alloc_iob ( size_t len ) {
 	iobuf = ( struct io_buffer * ) ( data + len );
 	iobuf->head = iobuf->data = iobuf->tail = data;
 	iobuf->end = iobuf;
+	iobuf->csum_stat = 0;
 	return iobuf;
 }
 
diff --git a/src/include/gpxe/iobuf.h b/src/include/gpxe/iobuf.h
index 8f05f9e..423500b 100644
--- a/src/include/gpxe/iobuf.h
+++ b/src/include/gpxe/iobuf.h
@@ -34,6 +34,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define IOB_ZLEN 64
 
 /**
+ * Checksum Offloading Status
+ *
+ * Checksum status definitions. Currently only used for RX path.
+ */
+#define CHECKSUM_NONE 0
+#define CHECKSUM_UNNECESSARY 1
+#define CHECKSUM_COMPLETE 2
+#define CHECKSUM_PARTIAL 3
+
+/**
  * A persistent I/O buffer
  *
  * This data structure encapsulates a long-lived I/O buffer.  The
@@ -57,6 +67,9 @@ struct io_buffer {
 	void *tail;
 	/** End of the buffer */
         void *end;
+
+	/** Checksum Offloading Status **/
+	uint32_t csum_stat;
 };
 
 /**
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index 92d0684..f065ca6 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -390,7 +390,7 @@ static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused
 		struct sockaddr_tcpip st;
 	} src, dest;
 	uint16_t csum;
-	uint16_t pshdr_csum;
+	uint16_t pshdr_csum = 0;
 	int rc;
 
 	/* Sanity check the IPv4 header */
@@ -414,7 +414,8 @@ static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused
 		      "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
 		goto err;
 	}
-	if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
+	if ( ( iobuf->csum_stat != CHECKSUM_COMPLETE ) &&
+	     ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
 		DBG ( "IPv4 checksum incorrect (is %04x including checksum "
 		      "field, should be 0000)\n", csum );
 		goto err;
@@ -441,7 +442,8 @@ static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused
 	 * checksum and then strip off the IPv4 header.
 	 */
 	iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
-	pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
+	if ( iobuf->csum_stat != CHECKSUM_COMPLETE )
+		pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
 	iob_pull ( iobuf, hdrlen );
 
 	/* Fragment reassembly */
diff --git a/src/net/tcp.c b/src/net/tcp.c
index f9fd409..6a7b340 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -924,15 +924,17 @@ static int tcp_rx ( struct io_buffer *iobuf,
 		rc = -EINVAL;
 		goto discard;
 	}
-	csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
-				       iob_len ( iobuf ) );
-	if ( csum != 0 ) {
-		DBG ( "TCP checksum incorrect (is %04x including checksum "
-		      "field, should be 0000)\n", csum );
-		rc = -EINVAL;
-		goto discard;
+	if ( iobuf->csum_stat != CHECKSUM_COMPLETE ) {
+		csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
+					       iob_len ( iobuf ) );
+		if ( csum != 0 ) {
+			DBG ( "TCP checksum incorrect (is %04x including checksum "
+			      "field, should be 0000)\n", csum );
+			rc = -EINVAL;
+			goto discard;
+		}
 	}
-	
+
 	/* Parse parameters from header and strip header */
 	tcp = tcp_demux ( tcphdr->dest );
 	start_seq = seq = ntohl ( tcphdr->seq );
diff --git a/src/net/udp.c b/src/net/udp.c
index 1441d53..26c4c28 100644
--- a/src/net/udp.c
+++ b/src/net/udp.c
@@ -298,7 +298,7 @@ static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
 		rc = -EINVAL;
 		goto done;
 	}
-	if ( udphdr->chksum ) {
+	if ( udphdr->chksum && ( iobuf->csum_stat != CHECKSUM_COMPLETE ) ) {
 		csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
 		if ( csum != 0 ) {
 			DBG ( "UDP checksum incorrect (is %04x including "
-- 
1.7.1



More information about the gPXE-devel mailing list