summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoakim Tjernlund <Joakim.Tjernlund@transmode.se>2008-11-05 19:02:49 +0100
committerDavid Lamparter <equinox@diac24.net>2010-02-04 01:18:21 +0100
commit69dd8e5692bc22967b5508f763be7d056fffa9de (patch)
treed8412964a82c86bc03766186bdaa5af2fad47eca
parentdca6c883ea6219460efbe3dadde4b8b9cb12c845 (diff)
downloadquagga-69dd8e5692bc22967b5508f763be7d056fffa9de.tar.bz2
quagga-69dd8e5692bc22967b5508f763be7d056fffa9de.tar.xz
lib: Optimize Fletcher and Internet checksums
Did some simple optimizations to reduce the number of instructions in the hot path for both fletcher_checksum() and in_cksum().
-rw-r--r--lib/checksum.c53
1 files changed, 19 insertions, 34 deletions
diff --git a/lib/checksum.c b/lib/checksum.c
index 3ddde815..af4f2550 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -14,27 +14,20 @@ in_cksum(void *parg, int nbytes)
{
u_short *ptr = parg;
register long sum; /* assumes long == 32 bits */
- u_short oddbyte;
register u_short answer; /* assumes u_short == 16 bits */
-
+ register int count;
/*
* Our algorithm is simple, using a 32-bit accumulator (sum),
* we add sequential 16-bit words to it, and at the end, fold back
* all the carry bits from the top 16 bits into the lower 16 bits.
*/
-
sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if (nbytes == 1) {
- oddbyte = 0; /* make sure top half is zero */
- *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
- sum += oddbyte;
- }
+ count = nbytes >> 1; /* div by 2 */
+ for(ptr--; count; --count)
+ sum += *++ptr;
+
+ if (nbytes & 1) /* Odd */
+ sum += *(u_char *)(++ptr); /* one byte only */
/*
* Add back carry outs from top 16 bits to low 16 bits.
@@ -56,11 +49,8 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset)
{
u_int8_t *p;
int x, y, c0, c1;
- u_int16_t checksum;
u_int16_t *csum;
size_t partial_len, i, left = len;
-
- checksum = 0;
assert (offset < len);
@@ -68,47 +58,42 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset)
* Zero the csum in the packet.
*/
csum = (u_int16_t *) (buffer + offset);
- *(csum) = 0;
+ *csum = 0;
- p = buffer;
+ p = buffer - 1;
c0 = 0;
c1 = 0;
while (left != 0)
{
partial_len = MIN(left, MODX);
+ left -= partial_len;
- for (i = 0; i < partial_len; i++)
+ do
{
- c0 = c0 + *(p++);
+ c0 = c0 + *(++p);
c1 += c0;
- }
+ } while (--partial_len);
c0 = c0 % 255;
c1 = c1 % 255;
-
- left -= partial_len;
}
-
+
/* The cast is important, to ensure the mod is taken as a signed value. */
x = (int)((len - offset - 1) * c0 - c1) % 255;
if (x <= 0)
x += 255;
y = 510 - c0 - x;
- if (y > 255)
+ if (y > 255)
y -= 255;
-
+
/*
* Now we write this to the packet.
* We could skip this step too, since the checksum returned would
* be stored into the checksum field by the caller.
+ * Checksum is always big endian.
*/
- buffer[offset] = x;
- buffer[offset + 1] = y;
-
- /* Take care of the endian issue */
- checksum = htons((x << 8) | (y & 0xFF));
-
- return checksum;
+ *csum = htons((x << 8) | (y & 0xFF));
+ return *csum;
}