Commit 5e13ffe6 authored by Martin Mareš's avatar Martin Mareš
Browse files

Faster checksum function.

parent 913f7dc9
......@@ -32,8 +32,6 @@ Core
- OSPF: refuse running on non-multicast devices
- lib: use better checksum function
Cleanup
~~~~~~~
- right usage of DBG vs. debug
......
......@@ -11,6 +11,62 @@
#include "nest/bird.h"
#include "checksum.h"
static u16 /* One-complement addition */
add16(u16 sum, u16 x)
{
u16 z = sum + x;
return z + (z < sum);
}
static u32
add32(u32 sum, u32 x)
{
u32 z = sum + x;
return z + (z < sum);
}
static u16
ipsum_calc_block(u16 *x, unsigned len, u16 sum)
{
int rest;
u32 tmp, *xx;
/*
* A few simple facts about the IP checksum (see RFC 1071 for detailed
* discussion):
*
* o It's associative and commutative.
* o It's byte order independent.
* o It's word size independent.
*
* This gives us a neat 32-bits-at-a-time algorithm which respects
* usual alignment requirements and is reasonably fast.
*/
ASSERT(!(len % 2));
if (!len)
return sum;
len >>= 1;
if ((unsigned long) x & 2) /* Align to 32-bit boundary */
{
sum = add16(sum, *x++);
len--;
}
rest = len & 1;
len >>= 1;
tmp = 0;
xx = (u32 *) x;
while (len)
{
tmp = add32(tmp, *xx++);
len--;
}
sum = add16(sum, add16(tmp & 0xffff, tmp >> 16U));
if (rest)
sum = add16(sum, *(u16 *) xx);
return sum;
}
static u16
ipsum_calc(void *frag, unsigned len, va_list args)
{
......@@ -18,14 +74,7 @@ ipsum_calc(void *frag, unsigned len, va_list args)
for(;;)
{
u16 *x = frag;
ASSERT(!(len % 2));
while (len)
{
u16 z = sum + *x++;
sum = z + (z < sum);
len -= 2;
}
sum = ipsum_calc_block(frag, len, sum);
frag = va_arg(args, void *);
if (!frag)
break;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment