/* 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; }