From 86a43b4d325ddc850fa9dc4711670880f35b11e8 Mon Sep 17 00:00:00 2001 From: lijia Date: Wed, 24 Oct 2018 09:36:45 +0800 Subject: create new project. --- src/common/linux_jhash_algo.c | 267 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 src/common/linux_jhash_algo.c (limited to 'src/common/linux_jhash_algo.c') diff --git a/src/common/linux_jhash_algo.c b/src/common/linux_jhash_algo.c new file mode 100644 index 0000000..31fa7ec --- /dev/null +++ b/src/common/linux_jhash_algo.c @@ -0,0 +1,267 @@ + +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * These are functions for producing 32-bit hashes for hash table lookup. + * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() + * are externally useful functions. Routines to test the hash are included + * if SELF_TEST is defined. You can use this free for any purpose. It's in + * the public domain. It has no warranty. + * + * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are my fault. + * Jozsef + */ + +#include "flowood.h" + +/* An arbitrary initial parameter */ +#define JHASH_INITVAL (0x20180601) /* flowood项目代码启动开发的日期 */ + + +#ifndef u32 +typedef unsigned int u32; +#endif + +#ifndef __u32 +typedef unsigned int __u32; +#endif + +/* Best hash sizes are of power of two */ +#define jhash_size(n) ((u32)1<<(n)) +/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */ +#define jhash_mask(n) (jhash_size(n)-1) + + +/** + * rol32 - rotate a 32-bit value left + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u32 rol32(__u32 word, unsigned int shift) +{ + return (word << shift) | (word >> (32 - shift)); +} + +/* __jhash_mix -- mix 3 32-bit values reversibly. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= c; a ^= rol32(c, 4); c += b; \ + b -= a; b ^= rol32(a, 6); a += c; \ + c -= b; c ^= rol32(b, 8); b += a; \ + a -= c; a ^= rol32(c, 16); c += b; \ + b -= a; b ^= rol32(a, 19); a += c; \ + c -= b; c ^= rol32(b, 4); b += a; \ +} + +/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ +#define __jhash_final(a, b, c) \ +{ \ + c ^= b; c -= rol32(b, 14); \ + a ^= c; a -= rol32(c, 11); \ + b ^= a; b -= rol32(a, 25); \ + c ^= b; c -= rol32(b, 16); \ + a ^= c; a -= rol32(c, 4); \ + b ^= a; b -= rol32(a, 14); \ + c ^= b; c -= rol32(b, 24); \ +} + +#if 0 +/* jhash - hash an arbitrary key + * @k: sequence of bytes as key + * @length: the length of the key + * @initval: the previous hash, or an arbitray value + * + * The generic version, hashes an arbitrary sequence of bytes. + * No alignment or length assumptions are made about the input key. + * + * Returns the hash value of the key. The result depends on endianness. + */ +static inline u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c; + const u8 *k = key; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + length + initval; + + /* All but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += __get_unaligned_cpu32(k); + b += __get_unaligned_cpu32(k + 4); + c += __get_unaligned_cpu32(k + 8); + __jhash_mix(a, b, c); + length -= 12; + k += 12; + } + /* Last block: affect all 32 bits of (c) */ + /* All the case statements fall through */ + switch (length) { + case 12: c += (u32)k[11]<<24; + case 11: c += (u32)k[10]<<16; + case 10: c += (u32)k[9]<<8; + case 9: c += k[8]; + case 8: b += (u32)k[7]<<24; + case 7: b += (u32)k[6]<<16; + case 6: b += (u32)k[5]<<8; + case 5: b += k[4]; + case 4: a += (u32)k[3]<<24; + case 3: a += (u32)k[2]<<16; + case 2: a += (u32)k[1]<<8; + case 1: a += k[0]; + __jhash_final(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} +#endif + +/* jhash2 - hash an array of u32's + * @k: the key which must be an array of u32's + * @length: the number of u32's in the key + * @initval: the previous hash, or an arbitray value + * + * Returns the hash value of the key. + */ +static inline u32 jhash2(const u32 *k, u32 length, u32 initval) +{ + u32 a, b, c; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + (length<<2) + initval; + + /* Handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + length -= 3; + k += 3; + } + + /* Handle the last 3 u32's: all the case statements fall through */ + switch (length) { + case 3: c += k[2]; + case 2: b += k[1]; + case 1: a += k[0]; + __jhash_final(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} + + +/* jhash_3words - hash exactly 3, 2 or 1 word(s) */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_INITVAL; + b += JHASH_INITVAL; + c += initval; + + __jhash_final(a, b, c); + + return c; +} + +/* + NAT转换表和计算数据包指纹复用一个函数, 靠参数sport_with_no_id_hash区分: + sport_with_no_id_hash=0: 用于计算四元组HASH, + sport_with_no_id_hash=1: 用于计算数据包指纹; + + NOTE: + 做四元组hash计算时, 不需要看dir_reverse, + 因为C2S方向和S2C方向生成的key的四元组实际二进制是一样的, + 都遵循大地址做为源的规则, 只是dir_reverse不同, + C2S和S2C的来包方向不一样, dir_reverse肯定是相反的. +*/ +unsigned int flwd_tuple5_hash(const flwd_tuple5_t *tuple5, int sport_with_no_id_hash) +{ + unsigned int sip; + unsigned int dip; + unsigned int hash_val = 0; + unsigned short sport; /* 计算四元组HASH时, 用全部的bit; 计算指纹信息时, 只用sport的最低8bit端口值, 即不含网关id, hash */ + unsigned short dport; + + if(flwd_likely(FLWD_IP_ADDR_TYPE_V4 == tuple5->addr_type)){ + sip = tuple5->ippair_v4.sip_net_order; + dip = tuple5->ippair_v4.dip_net_order; + }else{ + sip = tuple5->ippair_v6->sip_net_order.s6_addr32[0]; /* 使用最低4字节 */ + dip = tuple5->ippair_v6->dip_net_order.s6_addr32[0]; /* 使用最低4字节 */ + } + + if(sport_with_no_id_hash){ + sport = ntohs(tuple5->sport_net_order) & FLWD_UDP_SPORT_ACTUAL_PORT_MASK; /* 只用真正的端口值, 不用id和hash字段 */ + }else{ + sport = tuple5->sport_net_order; + } + dport = tuple5->dport_net_order; + + hash_val = (unsigned int)sport; + hash_val |= ((unsigned int)dport << 16); + hash_val += JHASH_INITVAL; + + __jhash_final(sip, dip, hash_val); + + return hash_val; +} + + + +unsigned int __flwd_tuple5_hash(const flwd_tuple5_t *tuple5) +{ + unsigned int sip; + unsigned int dip; + unsigned int port_union; + unsigned short sport_no_id_hash; /* 计算四元组HASH时, 只用sport的最低8bit端口值, 不含网关id, hash */ + unsigned short dport; + + if(flwd_likely(FLWD_IP_ADDR_TYPE_V4 == tuple5->addr_type)){ + if(0 == tuple5->dir_reverse){ + sip = tuple5->ippair_v4.sip_net_order; + dip = tuple5->ippair_v4.dip_net_order; + sport_no_id_hash = ntohs(tuple5->sport_net_order) & FLWD_UDP_SPORT_ACTUAL_PORT_MASK; /* 只用真正的端口值, 不用id和hash字段 */ + dport = tuple5->dport_net_order; + }else{ + sip = tuple5->ippair_v4.dip_net_order; + dip = tuple5->ippair_v4.sip_net_order; + sport_no_id_hash = ntohs(tuple5->dport_net_order) & FLWD_UDP_SPORT_ACTUAL_PORT_MASK; /* 只用真正的端口值, 不用id和hash字段 */ + dport = tuple5->sport_net_order; + } + }else{ + if(0 == tuple5->dir_reverse){ + sip = tuple5->ippair_v6->sip_net_order.s6_addr32[0]; /* 使用最低4字节 */ + dip = tuple5->ippair_v6->dip_net_order.s6_addr32[0]; /* 使用最低4字节 */ + sport_no_id_hash = ntohs(tuple5->sport_net_order) & FLWD_UDP_SPORT_ACTUAL_PORT_MASK; + dport = tuple5->dport_net_order; + }else{ + sip = tuple5->ippair_v6->dip_net_order.s6_addr32[0]; /* 使用最低4字节 */ + dip = tuple5->ippair_v6->sip_net_order.s6_addr32[0]; /* 使用最低4字节 */ + sport_no_id_hash = ntohs(tuple5->dport_net_order) & FLWD_UDP_SPORT_ACTUAL_PORT_MASK; + dport = tuple5->sport_net_order; + } + } + + port_union = (unsigned int)sport_no_id_hash; + port_union |= ((unsigned int)dport << 16); + port_union += JHASH_INITVAL; + + __jhash_final(sip, dip, port_union); + + return port_union; +} + -- cgit v1.2.3