linux-mips
[Top] [All Lists]

MIPS checksum bug

To: linux-mips@linux-mips.org
Subject: MIPS checksum bug
From: Bryan Phillippe <u1@terran.org>
Date: Tue, 16 Sep 2008 22:15:41 -0700
Original-recipient: rfc822;linux-mips@linux-mips.org
References: <072748C6-07A9-4167-A8A5-80D0F7D9C784@darkforest.org>
Sender: linux-mips-bounce@linux-mips.org
Hello,

It appears that the following problem once reported for Sparc64 affects MIPS/64 as well:

original report: http://www.spinics.net/lists/sparclinux/msg00173.html
resolution: http://www.spinics.net/lists/sparclinux/msg00179.html

The net result is that when TCP fragments unacked segments due to PMTU discovery, the shortened segment can have a bad TCP csum. I'm testing on Linux-2.6.26 (FWIW, on a Cavium CN3010). My repro is fairly simple: MIPS/64 client behind a Linux router, where the Linux router has an outbound MTU of 1492. When the client attempts to send segments of size 1460 (1500), the router sends back an ICMP unreachable/PMTU and the client resends the first portion of the segment reduced to 1452 (1492), and the segments *often* (but not always) have a bad TCP csum. Note that you can't have hardware checksums enabled or the bug is masked.

I've experimented with the following change:

--- /home/bp/tmp/csum_partial.S.orig    2008-09-16 12:01:00.000000000 -0700
+++ arch/mips/lib/csum_partial.S        2008-09-16 11:51:44.000000000 -0700
@@ -281,6 +281,23 @@
        .set    reorder
        /* Add the passed partial csum.  */
        ADDC(sum, a2)
+
+       /* fold checksum again to clear the high bits before returning */
+       .set    push
+       .set    noat
+#ifdef USE_DOUBLE
+       dsll32  v1, sum, 0
+       daddu   sum, v1
+       sltu    v1, sum, v1
+       dsra32  sum, sum, 0
+       addu    sum, v1
+#endif
+       sll     v1, sum, 16
+       addu    sum, v1
+       sltu    v1, sum, v1
+       srl     sum, sum, 16
+       addu    sum, v1
+
        jr      ra
        .set    noreorder
        END(csum_partial)

and it seems to fix the problem for me.  Can you comment?

Thanks,
--
-bp


<Prev in Thread] Current Thread [Next in Thread>