TCP checksum error on local device

Previous thread: [PATCH -next 08/11] remove CONFIG_KMOD from net by Johannes Berg on Wednesday, July 9, 2008 - 1:28 am. (1 message)

Next thread: [patch 14/15] LTTng instrumentation - ipv4 by Mathieu Desnoyers on Wednesday, July 9, 2008 - 7:59 am. (1 message)
From: Kevin Spiteri
Date: Wednesday, July 9, 2008 - 7:34 am

When I send TCP data from localhost to localhost (either on 127.0.0.1
or on the public IP of the machine), the TCP checksum is wrong.

I am using the kernel that came with Xubuntu 8.04, /proc/version:
Linux version 2.6.24-19-generic (buildd@palmer) (gcc version 4.2.3
(Ubuntu 4.2.3-2ubuntu7)) #1 SMP Wed Jun 18 14:43:41 UTC 2008

When I run the sample program below and capture traffic on the lo
device using Wireshark, the TCP segment that contains data has an
incorrect checksum. All other segments have a correct checksum.

#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char **argv)
{
    int fd_srv, fd_s0, fd_s1;
    struct sockaddr_in address;
    socklen_t len = sizeof(address);
    char buffer[1] = {0};

    fd_srv = socket(AF_INET, SOCK_STREAM, 6);
    memset(&address, 0, len);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(0x7f000001);
    address.sin_port = htons(12345);
    bind(fd_srv, (struct sockaddr *)(&address), len);
    listen(fd_srv, 0);

    fd_s0 = socket(AF_INET, SOCK_STREAM, 6);
    connect(fd_s0, (struct sockaddr *)(&address), len);

    fd_s1 = accept(fd_srv, (struct sockaddr *)(&address), &len);
    close(fd_srv);

    write(fd_s0, buffer, 1);
    read(fd_s1, buffer, 1);
    close(fd_s0);
    close(fd_s1);

    return 0;
}
--

From: Kristof Provost
Date: Wednesday, July 9, 2008 - 8:10 am

I suspect this is intended and expected behaviour. The checksum is quite
useless as the packet never travels over the network and can't be
corrupted. 

The transmit code in net/ipv4/ip_output.c seems to mark packets for the
loopback interface with CHECKSUM_UNNECESSARY.

I guess the connection over loopback still carries the data like you'd
expect right?

Kristof

--

From: Kevin Spiteri
Date: Wednesday, July 9, 2008 - 8:28 am

Probably.

I saw the behaviour as strange because only the segment containing data 
had an incorrect TCP checksum, all other segments (SYN, SYN ACK, ACKs 
without data and FIN ACK) had a correct TCP checksum.

Also, the incorrect checksum field seems to depend on the IP address and 
the packet length, but not on the port number, sequence/acknowledgement 
number or data content. Thus, the incorrect checksum is the same when 
the sample is run repeatedly, it only changes when the data length 
The same happens when I bind the server socket on the public IP (e.g. 
10.111.110.71:12345) and connect from a socket on the same IP 
(10.111.110.71). But then, although the IP is for device eth0 rather 
than for device lo, the packet still never has to be transmitted and the 
Yes, the data was still received and correct.

Kevin

--

From: Ben Hutchings
Date: Wednesday, July 9, 2008 - 8:38 am

Kevin Spiteri wrote:
[...]

The TCP/IP stack will unconditionally start calculating a checksum as it
prepares some of the headers.  Then at a later stage it checks the checksum
capability of the destination route/device (checksum calculation may be
offloaded or unnecessary) and decides whether to update the TCP checksum to
include the rest of the packet, including the payload.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
--

Previous thread: [PATCH -next 08/11] remove CONFIG_KMOD from net by Johannes Berg on Wednesday, July 9, 2008 - 1:28 am. (1 message)

Next thread: [patch 14/15] LTTng instrumentation - ipv4 by Mathieu Desnoyers on Wednesday, July 9, 2008 - 7:59 am. (1 message)