1998-09-06 22:08:15

by David S. Miller

[permalink] [raw]
Subject: Re: IPv4 kernel messages

Date: Mon, 7 Sep 1998 01:12:16 +0200 (CEST)
From: Geert Uytterhoeven <[email protected]>

They're still there:

| Socket destroy delayed (r=0 w=160)
| TCPv4 bad checksum from 10.0.24.8:0071 to 10.0.24.4:040c, len=20/20/40

Are these just warnings to be disabled in 2.2, or is there something wrong?

10.0.24.4 runs Linux/m68k 2.1.119. 10.0.24.8 is a PPC running vger-19980903.

I see them only rarely on my main workstation which talks a lot to the
rest of the world. On my internal Linux-2.1.x machines I never see
it.

I would check out the csum routines on m68k and PPC to make sure they
are sane in all cases.

Here is the lifesaver development utility I have been using for a long
time to verify all major changes made to Sparc and MIPS checksumming
routines. It won't work for you as-is, but you can figure out what it
is supposed to do and link the PPC and M68k csum routines into it to
perform verifications. Note there is an ugly piece of MIPS inline asm
in here which you'll need to remove too as the last thing I used this
for was the Cobalt kernels :-) Note it also performs performance
metrics on your code too, so it's useful for speed tuning as well as
verification.

/* cksum_helper.c: Lifesaver development utility.
*
* Copyright (C) 1996 David S. Miller ([email protected])
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>

extern int gettimeofday();
extern int fprintf();

static struct timeval start_tv, stop_tv;

void
tvsub(tdiff, t1, t0)
struct timeval *tdiff, *t1, *t0;
{
tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
if (tdiff->tv_usec < 0)
tdiff->tv_sec--, tdiff->tv_usec += 1000000;
}

/*
* Start timing now.
*/
void
start()
{
(void) gettimeofday(&start_tv, (struct timezone *) 0);
}

/*
* Stop timing and return real time in microseconds.
*/
unsigned long
stop()
{
struct timeval tdiff;

(void) gettimeofday(&stop_tv, (struct timezone *) 0);

tvsub(&tdiff, &stop_tv, &start_tv);
return (tdiff.tv_sec * 1000000 + tdiff.tv_usec);
}

void
micro(s, n)
char *s;
int n;
{
struct timeval td;
int micro;

tvsub(&td, &stop_tv, &start_tv);
fprintf(stderr, "%s: %d secs\n", s, td.tv_sec);
micro = td.tv_sec * 1000000 + td.tv_usec;
fprintf(stderr, "%s: %d microseconds\n", s, micro / n);
}

void
milli(s, n)
char *s;
int n;
{
struct timeval td;
int milli;

tvsub(&td, &stop_tv, &start_tv);
milli = td.tv_sec * 1000 + td.tv_usec / 1000;
fprintf(stderr, "%s: %d milliseconds\n", s, milli / n);
}

/* Basically, we create buffers of varying sizes, feed them into
* a known working checksum routine and the one to be tested,
* if the test succeeds we just go on to the next buffer full of
* random data and try again. If it fails, the random data block
* is written into files with unique names for each failure buffer,
* and the two differing results go to stdout.
*/

/* What we test... */
extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
extern unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
extern unsigned short ip_fast_csum(const unsigned char * iph, unsigned int ihl);
extern unsigned short int csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
unsigned short len, unsigned short proto,
unsigned int sum);
extern unsigned short ip_compute_csum(unsigned char * buff, int len);

typedef signed char s8;
typedef unsigned char u8;

typedef signed short s16;
typedef unsigned short u16;

typedef signed int s32;
typedef unsigned int u32;

typedef signed long long s64;
typedef unsigned long long u64;

/* Now the portable checksum routine we assume works on all machines. */
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}

int reference_cksum(u16 *w, int len)
{
int sum = 0;
int mlen = 0;
int byte_swapped = 0;

union {
u8 c[2];
u16 s;
} s_util;
union {
u16 s[2];
u32 l;
} l_util;

/* Force to even boundary. */
if ((1 & (long) w) && (len > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(u8 *)w;
w = (u16 *)((s8 *)w + 1);
len--;
byte_swapped = 1;
}
/* Unroll the loop to make overhead from
* branches &c small.
*/
while ((len -= 32) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
w += 16;
}
len += 32;
while ((len -= 8) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
w += 4;
}
len += 8;
if (len == 0 && byte_swapped == 0)
goto fini;
REDUCE;
while ((len -= 2) >= 0) {
sum += *w++;
}
if (byte_swapped) {
REDUCE;
sum <<= 8;
byte_swapped = 0;
if (len == -1) {
s_util.c[1] = *(u8 *)w;
sum += s_util.s;
len = 0;
} else
len = -1;
} else if (len == -1)
s_util.c[0] = *(u8 *)w;
fini:
if (len == -1) {
/* Follow the standard (the odd byte may be shifted left
* by 8 bits or not as determined by endian-ness of the
* machine).
*/
s_util.c[1] = 0;
sum += s_util.s;
}
REDUCE;
return (~sum & 0xffff);
}

/* XXX */
static __inline__ unsigned short int csum_fold(unsigned int sum)
{
__asm__("
.set noat
sll $1,%0,16
addu %0,$1
sltu $1,%0,$1
srl %0,%0,16
addu %0,$1
xori %0,0xffff
.set at"
: "=r" (sum)
: "0" (sum)
: "$1");

return sum;
}

static int filenum = 0;

struct iphdr {
unsigned char version:4,
ihl:4;
unsigned char tos;
unsigned short tot_len;
unsigned short id;
unsigned short frag_off;
unsigned char ttl;
unsigned char protocol;
unsigned short check;
unsigned int saddr;
unsigned int daddr;
/*The options start here. */
};

struct timeval random_seed;

static void verify_ip_fast_csum(void)
{
struct iphdr **buffers;
struct iphdr *this;
int i, b, iters=512;
u16 ctr=52;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * 512);
if(!buffers)
goto outofmem;
for(i = 0; i < 512; i++) {
this = (struct iphdr *) malloc((sizeof(struct iphdr)));
if(!this)
goto outofmem;
buffers[i] = this;
}
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
printf("verify_ip_fast_csum");
again:
putchar('.');
fflush(stdout);
for(i = 0; i < 512; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < (sizeof(struct iphdr)); b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
for(i = 0; i < 512; i++) {
unsigned short csum, csum2;

this = buffers[i];
csum = ip_fast_csum((const unsigned char *)this, 5);
csum2 = reference_cksum((u16 *)this, 20);
if(csum != csum2) {
printf("buffer %d gets bogus csum %04x (ref=<%04x>)!\n",
i, csum, csum2);
exit(1);
}
this->check = csum;
if((csum = ip_fast_csum((const unsigned char *)this, 5))) {
printf("verify_ip_fast_csum: buffer %d gets bogus csum %04x!\n",
i, csum);
exit(1);
}
if((csum2 = reference_cksum((u16 *)this, 20))) {
printf("verify_ip_fast_csum: buffer %d gets bogus csum2 %04x!\n",
i, csum2);
exit(1);
}
}
if(--iters > 0)
goto again;
printf("done\n");
fflush(stdout);
for(i = 0; i < 512; i++)
free(buffers[i]);
free(buffers);
return;

outofmem:
printf("Out of memory in verify_ip_fast_csum!\n");
exit(1);
}

static char compare_buffer[2048];

static void verify_csum_partial(void)
{
int *sizes;
struct iphdr **buffers;
struct iphdr *this;
int i, b, iters=512;
u16 ctr=62;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * 512);
sizes = (int *) malloc(sizeof(int) * 512);
if(!buffers)
goto outofmem;
printf("verify_csum_partial");
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
again:
for(i = 0; i < 512; i++) {
int sz;

sz = random() & 0x7ff;
if(sz > 1500) sz=1500;
if(sz < sizeof(struct iphdr)) sz=sizeof(struct iphdr);

sizes[i] = sz;
this = (struct iphdr *) malloc(sz);
if(!this)
goto outofmem;
buffers[i] = this;
}
putchar('.');
fflush(stdout);
for(i = 0; i < 512; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < sizes[i]; b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
for(i = 0; i < 512; i++) {
u32 lcsum;
unsigned short csum, csum2;

this = buffers[i];
lcsum = csum_partial(((const unsigned char *)this)+2, sizes[i], 0);
csum2 = reference_cksum(((u16 *)this)+1, sizes[i]);
csum = csum_fold(lcsum);
if(csum != csum2) {
u16 *ptr = (u16 *) this;

printf("csum_partial: buffer %d gets bogus "
"csum %04x (ref=<%04x>)!\n",
i, csum, csum2);
printf("csum_partial: buffer dump lngth=%d\n", sizes[i]);
for(b = 0; b < sizes[i]/2; b++) {
printf("[%04x]\n", ((u16 *)this)[b]);
}
printf("\n");
exit(1);
}

this->check = csum;
if((csum = csum_fold(csum_partial(((const unsigned char *)this)+2,
sizes[i], 0)))) {
printf("verify_csum_partial: buffer %d gets bogus csum %04x!\n",
i, csum);
exit(1);
}
if((csum2 = reference_cksum(((u16 *)this)+1, sizes[i]))) {
printf("verify_csum_partial: buffer %d gets bogus csum2 %04x!\n",
i, csum2);
exit(1);
}
}
for(i=0; i<512; i++)
free(buffers[i]);
if(--iters > 0)
goto again;
printf("done\n");
fflush(stdout);
free(buffers);
return;

outofmem:
printf("Out of memory in verify_csum_partial!\n");
exit(1);
}

static void verify_csum_partial_cunaligned(void)
{
int *sizes;
struct iphdr **buffers;
struct iphdr *this;
int i, b, iters=512;
u16 ctr=62;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * 512);
sizes = (int *) malloc(sizeof(int) * 512);
if(!buffers)
goto outofmem;
printf("verify_csum_partial");
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
again:
for(i = 0; i < 512; i++) {
int sz;

#if 0
sz = random() & 0x7ff;
if(sz > 1500) sz=1500;
if(sz < sizeof(struct iphdr)) sz=sizeof(struct iphdr);
#else
sz = 11;
#endif
sizes[i] = sz;
this = (struct iphdr *) malloc(sz);
if(!this)
goto outofmem;
buffers[i] = this;
}
putchar('.');
fflush(stdout);
for(i = 0; i < 512; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < sizes[i]; b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
for(i = 0; i < 512; i++) {
u32 lcsum;
unsigned short csum, csum2;

this = buffers[i];
lcsum = csum_partial_copy(((const unsigned char *)this) + 2,
compare_buffer, sizes[i], 0);
csum2 = reference_cksum((((u16 *)this)+1), sizes[i]);
csum = csum_fold(lcsum);
if(csum != csum2) {
u16 *ptr = (u16 *) this;

printf("csum_partial: buffer %d gets bogus "
"csum %04x (ref=<%04x>)!\n",
i, csum, csum2);
printf("csum_partial: buffer dump lngth=%d\n", sizes[i]);
for(b = 0; b < sizes[i]/2; b++) {
printf("[%04x]\n", ((u16 *)this)[b]);
}
printf("\n");
exit(1);
}
this->check = csum;
if((csum = csum_fold(csum_partial_copy(((const unsigned char *)this) + 2,
compare_buffer, sizes[i], 0)))) {
printf("verify_csum_partial: buffer %d gets bogus csum %04x!\n",
i, csum);
exit(1);
}
if((csum2 = reference_cksum((((u16 *)this)+1), sizes[i]))) {
printf("verify_csum_partial: buffer %d gets bogus csum2 %04x!\n",
i, csum2);
exit(1);
}
}
for(i=0; i<512; i++)
free(buffers[i]);
if(--iters > 0)
goto again;
printf("done\n");
fflush(stdout);
free(buffers);
return;

outofmem:
printf("Out of memory in verify_csum_partial!\n");
exit(1);
}

static void verify_csum_partial_copy(void)
{
int *sizes;
struct iphdr **buffers;
struct iphdr *this;
char *dst = compare_buffer;
int i, b, iters=512;
u16 ctr=62;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * 512);
sizes = (int *) malloc(sizeof(int) * 512);
if(!buffers)
goto outofmem;
printf("verify_csum_partial_copy");
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
again:
for(i = 0; i < 512; i++) {
int sz;

sz = random() & 0x7ff;
if(sz > 1500) sz=1500;
if(sz < sizeof(struct iphdr)) sz=sizeof(struct iphdr);
sizes[i] = sz;
this = (struct iphdr *) malloc(sz);
if(!this)
goto outofmem;
buffers[i] = this;
}
putchar('.');
fflush(stdout);
for(i = 0; i < 512; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < sizes[i]; b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
for(i = 0; i < 512; i++) {
u32 lcsum;
unsigned short csum, csum2;

this = buffers[i];
lcsum = csum_partial_copy((const unsigned char *)this, dst, sizes[i], 0);
csum2 = reference_cksum((u16 *)this, sizes[i]);
if(memcmp(this, dst, sizes[i])) {
printf("csum_partial_copy: buffer %d mismatch after copy!\n", i);
}
csum = csum_fold(lcsum);
if(csum != csum2) {
u16 *ptr = (u16 *) this;

printf("csum_partial_copy: buffer %d gets bogus "
"csum %04x (ref=<%04x>)!\n",
i, csum, csum2);
printf("csum_partial_copy: buffer dump lngth=%d\n", sizes[i]);
#if 0
for(b = 0; b < sizes[i]/2; b++) {
printf("[%04x]\n", ((u16 *)this)[b]);
}
printf("\n");
#endif
exit(1);
}
this->check = csum;
if((csum = csum_fold(csum_partial_copy((const unsigned char *)this,
dst, sizes[i], 0)))) {
printf("verify_csum_partial_copy: buffer %d gets bogus "
"csum %04x!\n",
i, csum);
exit(1);
}
if((csum2 = reference_cksum((u16 *)this, sizes[i]))) {
printf("verify_csum_partial_copy: buffer %d gets bogus "
"csum2 %04x!\n",
i, csum2);
exit(1);
}
}
for(i=0; i<512; i++)
free(buffers[i]);
if(--iters > 0)
goto again;
printf("done\n");
fflush(stdout);
free(buffers);
return;

outofmem:
printf("Out of memory in verify_csum_partial_copy!\n");
exit(1);
}

#define N 10000

static void measure_ip_fast_csum(void)
{
struct iphdr **buffers;
struct iphdr *this;
int i, b, iters=512;
int clock;
u16 ctr=52;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * 512);
if(!buffers)
goto outofmem;
for(i = 0; i < 512; i++) {
this = (struct iphdr *) malloc((sizeof(struct iphdr)));
if(!this)
goto outofmem;
buffers[i] = this;
}
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
printf("measure_ip_fast_csum...");
fflush(stdout);
for(i = 0; i < 512; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < (sizeof(struct iphdr)); b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
start();
for(b = 0; b < N; b++) {
for(i = 0; i < 512; i++) {
this = buffers[i];
ip_fast_csum((const unsigned char *)this, 5);
}
}
clock = stop();
printf("done\n");
fflush(stdout);
printf("ip_fast_csum: %d iterations takes %ld microseconds\n", N, clock);
clock = clock/N;
printf("ip_fast_csum: 1 iteration takes <%ld microseconds>==", clock);
clock = (int)((double)(((double)clock) / ((double)512.00)) * (double)100.00);
printf("<%ld nanoseconds>\n", clock);
for(i = 0; i < 512; i++)
free(buffers[i]);
free(buffers);
return;

outofmem:
printf("Out of memory in measure_ip_fast_csum!\n");
exit(1);
}

#define NBUFS 256

static void measure_csum_partial(void)
{
int *sizes;
struct iphdr **buffers;
struct iphdr *this;
int i, b, iter;
u16 ctr=62;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * NBUFS);
sizes = (int *) malloc(sizeof(int) * NBUFS);
if(!buffers)
goto outofmem;
printf("measure_csum_partial\n");
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
for(i = 0; i < NBUFS; i++) {
int sz;

/* sz = (i + sizeof(struct iphdr)); */
sz = ((i+1) * 1024);
/* sz = ((i+32)); */
sizes[i] = sz;
this = (struct iphdr *) malloc(sz);
if(!this)
goto outofmem;
buffers[i] = this;
}
for(i = 0; i < NBUFS; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < sizes[i]; b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
for(b = 0; b < NBUFS; b++) {
int clock, sz;
const unsigned char *thing;

sz = sizes[b];
thing = (const unsigned char *) buffers[b];
start();
for(iter=0; iter < N; iter++) {
for(i = 0; i < 512; i++) {
csum_partial(thing, sz, 0);
}
}
clock = stop();
printf("csum_partial: sz[%d] %d iterations takes %ld microseconds\n",
sz, N, clock);
clock = clock/N;
printf("csum_partial: sz[%d] 1 iteration takes <%ld microseconds>==",
sz, clock);
clock = (int)((double)(((double)clock) /
((double)512.00)) * (double)100.00);
printf("<%ld nanoseconds>\n", clock);
fflush(stdout);
}
for(i=0; i<NBUFS; i++)
free(buffers[i]);
free(buffers);
return;

outofmem:
printf("Out of memory in measure_csum_partial!\n");
exit(1);
}

static void measure_csum_partial_copy(void)
{
int *sizes;
struct iphdr **buffers;
struct iphdr *this;
char *dst;
int i, b, iter;
int sz;
u16 ctr=62;

buffers = (struct iphdr **) malloc((sizeof(struct iphdr *)) * NBUFS);
sizes = (int *) malloc(sizeof(int) * NBUFS);
if(!buffers)
goto outofmem;
printf("measure_csum_partial_copy\n");
gettimeofday(&random_seed, (struct timezone *) 0);
srandom(random_seed.tv_usec);
for(i = 0; i < NBUFS; i++) {
/* sz = (i + sizeof(struct iphdr)); */
/* sz = ((i+1) * 0x80); */
/* sz = ((i+32)); */
sz = (1024 * 1024);
sizes[i] = sz;
this = (struct iphdr *) malloc(sz);
if(!this)
goto outofmem;
buffers[i] = this;
}
dst = (char *) malloc(sz + 1024);
for(i = 0; i < NBUFS; i++) {
/* Fill with random bytes and zero csum field. */
this = buffers[i];
for(b = 0; b < sizes[i]; b++)
((u8 *)this)[b] = (random() >> 14) & 0xff;
this->check = 0;
}
for(b = 0; b < NBUFS; b++) {
int clock, sz;
const unsigned char *thing;

sz = sizes[b];
thing = (const unsigned char *) buffers[b];
start();
for(iter=0; iter < N; iter++) {
for(i = 0; i < 512; i++) {
csum_partial_copy(thing, dst, sz, 0);
}
}
clock = stop();
printf("csum_partial_copy: sz[%d] %d iterations takes %ld "
"microseconds\n",
sz, N, clock);
clock = clock/N;
printf("csum_partial_copy: sz[%d] 1 iteration takes <%ld "
"microseconds>==",
sz, clock);
clock = (int)((double)(((double)clock) /
((double)512.00)) * (double)100.00);
printf("<%ld nanoseconds>\n", clock);
fflush(stdout);
}
for(i=0; i<NBUFS; i++)
free(buffers[i]);
free(buffers);
return;

outofmem:
printf("Out of memory in measure_csum_partial_copy!\n");
exit(1);
}

void main(int argc, char **argv)
{
verify_csum_partial();
#if 0
verify_csum_partial_copy();
verify_csum_partial_cunaligned();
verify_ip_fast_csum();
measure_csum_partial();
measure_csum_partial_copy();
/* measure_ip_fast_csum(); */
#endif
exit(0);
}


1998-09-07 13:15:29

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: IPv4 kernel messages

On Sun, 6 Sep 1998, David S. Miller wrote:
> Date: Mon, 7 Sep 1998 01:12:16 +0200 (CEST)
> From: Geert Uytterhoeven <[email protected]>
>
> They're still there:
>
> | Socket destroy delayed (r=0 w=160)
> | TCPv4 bad checksum from 10.0.24.8:0071 to 10.0.24.4:040c, len=20/20/40
>
> Are these just warnings to be disabled in 2.2, or is there something wrong?
>
> 10.0.24.4 runs Linux/m68k 2.1.119. 10.0.24.8 is a PPC running vger-19980903.
> I see them only rarely on my main workstation which talks a lot to the
> rest of the world. On my internal Linux-2.1.x machines I never see
> it.
>
> I would check out the csum routines on m68k and PPC to make sure they
> are sane in all cases.
>
> Here is the lifesaver development utility I have been using for a long
> time to verify all major changes made to Sparc and MIPS checksumming
> routines. It won't work for you as-is, but you can figure out what it
> is supposed to do and link the PPC and M68k csum routines into it to
> perform verifications. Note there is an ugly piece of MIPS inline asm
> in here which you'll need to remove too as the last thing I used this
> for was the Cobalt kernels :-) Note it also performs performance
> metrics on your code too, so it's useful for speed tuning as well as
> verification.

Thanks! The PPC checksumming code passed the test, but the m68k code seems to
be broken. I got:

verify_ip_fast_csum: buffer 0 gets bogus csum abe7!

Ulrik De Bie wrote:
> I think the following information is interesting here. I have the same with
> Linux/i486 running recent-vger and PPC running recent-vger.
>
> So both intel and m68k are wrong, or ppc is wrong. Which would give a big
> hint to the latter.

Since PPC passed the test, this would indicate that ia32 is incorrect, too.

But if I understand it correctly, the test isn't exhaustive, right?

Greetings,

Geert

P.S. I put the code I used (i.e. Dave's with adaptations for ppc and m68k) on
my webpage: http://www.cs.kuleuven.ac.be/~geert/bin/cksum_helper.c
--
Geert Uytterhoeven [email protected]
Wavelets, Linux/{m68k~Amiga,PPC~CHRP} http://www.cs.kuleuven.ac.be/~geert/
Department of Computer Science -- Katholieke Universiteit Leuven -- Belgium


1998-09-07 13:26:08

by Andrea Arcangeli

[permalink] [raw]
Subject: Re: IPv4 kernel messages

On Sun, 6 Sep 1998, David S. Miller wrote:

>Here is the lifesaver development utility I have been using for a long

Cool! ;-)

>time to verify all major changes made to Sparc and MIPS checksumming
>routines. It won't work for you as-is, but you can figure out what it
>is supposed to do and link the PPC and M68k csum routines into it to
>perform verifications. Note there is an ugly piece of MIPS inline asm
>in here which you'll need to remove too as the last thing I used this
>for was the Cobalt kernels :-) Note it also performs performance

The asm looks wrong.

>/* XXX */
>static __inline__ unsigned short int csum_fold(unsigned int sum)
>{
> __asm__("
> .set noat
> sll $1,%0,16
> addu %0,$1
> sltu $1,%0,$1
^^^^^^^^^^^^^^^^

With my MIPS emulator sltu do soemthing like "<" C operator, $1 return
only 0 or 1 and so the asm seems far from what csum_fold should do (I
emulated the asm in C and does not work).

Here my C implementation of csum_fold() that seems to work with the
csum_partial() in the current arch/i386/lib/checksum.c.

--- cksum_helper.c.orig Mon Sep 7 14:51:25 1998
+++ cksum_helper.c Mon Sep 7 17:17:24 1998
@@ -180,6 +180,15 @@
/* XXX */
static __inline__ unsigned short int csum_fold(unsigned int sum)
{
+#ifndef __mips__ /* or better #ifndef buggy ;-) */
+ union {
+ u16 s[2];
+ u32 l;
+ } l_util;
+
+ REDUCE;
+ return ~sum & 0xffff;
+#else
__asm__("
.set noat
sll $1,%0,16
@@ -194,6 +203,7 @@
: "$1");

return sum;
+#endif
}

static int filenum = 0;
@@ -215,6 +225,7 @@

struct timeval random_seed;

+#if 0
static void verify_ip_fast_csum(void)
{
struct iphdr **buffers;
@@ -280,6 +291,7 @@
printf("Out of memory in verify_ip_fast_csum!\n");
exit(1);
}
+#endif

static char compare_buffer[2048];

@@ -555,6 +567,7 @@

#define N 10000

+#if 0
static void measure_ip_fast_csum(void)
{
struct iphdr **buffers;
@@ -607,6 +620,7 @@
printf("Out of memory in measure_ip_fast_csum!\n");
exit(1);
}
+#endif

#define NBUFS 256

@@ -748,7 +762,7 @@
exit(1);
}

-void main(int argc, char **argv)
+int main(int argc, char **argv)
{
verify_csum_partial();
#if 0

Andrea[s] Arcangeli