Check for kernel version and use appropriate jhash version in HA plugin
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Martin Willi
|
||||
* Copyright (C) 2009-2011 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -18,7 +18,7 @@
|
||||
typedef u_int32_t u32;
|
||||
typedef u_int8_t u8;
|
||||
|
||||
#include <linux/jhash.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
@@ -28,6 +28,16 @@ typedef u_int8_t u8;
|
||||
|
||||
#define CLUSTERIP_DIR "/proc/net/ipt_CLUSTERIP"
|
||||
|
||||
/**
|
||||
* Versions of jhash used in the Linux kernel
|
||||
*/
|
||||
typedef enum {
|
||||
/* old variant, http://burtleburtle.net/bob/c/lookup2.c */
|
||||
JHASH_LOOKUP2,
|
||||
/* new variant, http://burtleburtle.net/bob/c/lookup3.c, since 2.6.37 */
|
||||
JHASH_LOOKUP3,
|
||||
} jhash_version_t;
|
||||
|
||||
typedef struct private_ha_kernel_t private_ha_kernel_t;
|
||||
|
||||
/**
|
||||
@@ -40,17 +50,98 @@ struct private_ha_kernel_t {
|
||||
*/
|
||||
ha_kernel_t public;
|
||||
|
||||
/**
|
||||
* Init value for jhash
|
||||
*/
|
||||
u_int initval;
|
||||
|
||||
/**
|
||||
* Total number of ClusterIP segments
|
||||
*/
|
||||
u_int count;
|
||||
|
||||
/**
|
||||
* jhash version the kernel uses
|
||||
*/
|
||||
jhash_version_t version;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the jhash version based on the uname().release
|
||||
*/
|
||||
static jhash_version_t get_jhash_version()
|
||||
{
|
||||
struct utsname utsname;
|
||||
int a, b, c;
|
||||
|
||||
if (uname(&utsname) == 0)
|
||||
{
|
||||
switch (sscanf(utsname.release, "%d.%d.%d", &a, &b, &c))
|
||||
{
|
||||
case 3:
|
||||
if (a == 2 && b == 6)
|
||||
{
|
||||
if (c < 37)
|
||||
{
|
||||
DBG1(DBG_CFG, "detected Linux %d.%d.%d, using old "
|
||||
"jhash", a, b, c);
|
||||
return JHASH_LOOKUP2;
|
||||
}
|
||||
DBG1(DBG_CFG, "detected Linux %d.%d.%d, using new "
|
||||
"jhash", a, b, c);
|
||||
return JHASH_LOOKUP3;
|
||||
}
|
||||
/* FALL */
|
||||
case 2:
|
||||
DBG1(DBG_CFG, "detected Linux %d.%d, using new jhash", a, b);
|
||||
return JHASH_LOOKUP3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBG1(DBG_CFG, "detecting Linux version failed, using new jhash");
|
||||
return JHASH_LOOKUP3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate 32 bit word x by k bits
|
||||
*/
|
||||
#define jhash_rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/**
|
||||
* jhash algorithm of two words, as used in kernel (using 0 as initval)
|
||||
*/
|
||||
static u_int32_t jhash(jhash_version_t version, u_int32_t a, u_int32_t b)
|
||||
{
|
||||
u_int32_t c = 0;
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case JHASH_LOOKUP2:
|
||||
a += 0x9e3779b9;
|
||||
b += 0x9e3779b9;
|
||||
|
||||
a -= b; a -= c; a ^= (c >> 13);
|
||||
b -= c; b -= a; b ^= (a << 8);
|
||||
c -= a; c -= b; c ^= (b >> 13);
|
||||
a -= b; a -= c; a ^= (c >> 12);
|
||||
b -= c; b -= a; b ^= (a << 16);
|
||||
c -= a; c -= b; c ^= (b >> 5);
|
||||
a -= b; a -= c; a ^= (c >> 3);
|
||||
b -= c; b -= a; b ^= (a << 10);
|
||||
c -= a; c -= b; c ^= (b >> 15);
|
||||
break;
|
||||
case JHASH_LOOKUP3:
|
||||
a += 0xdeadbeef;
|
||||
b += 0xdeadbeef;
|
||||
|
||||
c ^= b; c -= jhash_rot(b, 14);
|
||||
a ^= c; a -= jhash_rot(c, 11);
|
||||
b ^= a; b -= jhash_rot(a, 25);
|
||||
c ^= b; c -= jhash_rot(b, 16);
|
||||
a ^= c; a -= jhash_rot(c, 4);
|
||||
b ^= a; b -= jhash_rot(a, 14);
|
||||
c ^= b; c -= jhash_rot(b, 24);
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Segmentate a calculated hash
|
||||
*/
|
||||
@@ -78,7 +169,7 @@ METHOD(ha_kernel_t, get_segment, u_int,
|
||||
u_int32_t addr;
|
||||
|
||||
addr = host2int(host);
|
||||
hash = jhash_1word(ntohl(addr), this->initval);
|
||||
hash = jhash(this->version, ntohl(addr), 0);
|
||||
|
||||
return hash2segment(this, hash);
|
||||
}
|
||||
@@ -90,7 +181,7 @@ METHOD(ha_kernel_t, get_segment_spi, u_int,
|
||||
u_int32_t addr;
|
||||
|
||||
addr = host2int(host);
|
||||
hash = jhash_2words(ntohl(addr), ntohl(spi), this->initval);
|
||||
hash = jhash(this->version, ntohl(addr), ntohl(spi));
|
||||
|
||||
return hash2segment(this, hash);
|
||||
}
|
||||
@@ -100,7 +191,7 @@ METHOD(ha_kernel_t, get_segment_int, u_int,
|
||||
{
|
||||
unsigned long hash;
|
||||
|
||||
hash = jhash_1word(ntohl(n), this->initval);
|
||||
hash = jhash(this->version, ntohl(n), 0);
|
||||
|
||||
return hash2segment(this, hash);
|
||||
}
|
||||
@@ -255,7 +346,7 @@ ha_kernel_t *ha_kernel_create(u_int count)
|
||||
.deactivate = _deactivate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.initval = 0,
|
||||
.version = get_jhash_version(),
|
||||
.count = count,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user