From: Victor Julien Date: Tue, 27 Mar 2012 08:05:51 +0000 (+0200) Subject: flow: make flow use lookup3.c hashing algorithm. Improves hash table distribution. X-Git-Tag: suricata-1.3beta1~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c10370907a95d586f987ea341c14ed6d65802af5;p=thirdparty%2Fsuricata.git flow: make flow use lookup3.c hashing algorithm. Improves hash table distribution. --- diff --git a/src/flow-hash.c b/src/flow-hash.c index 4326203699..9ce8067bb9 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -40,6 +40,8 @@ #include "util-time.h" #include "util-debug.h" +#include "util-hash-lookup3.h" + #define FLOW_DEFAULT_FLOW_PRUNE 5 SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx); @@ -139,6 +141,54 @@ void FlowHashDebugDeinit(void) { #endif /* FLOW_DEBUG_STATS */ +/** \brief compare two raw ipv6 addrs + * + * \note we don't care about the real ipv6 ip's, this is just + * to consistently fill the FlowHashKey6 struct, without all + * the ntohl calls. + * + * \warning do not use elsewhere unless you know what you're doing. + * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely + * what you are looking for. + */ +static inline int FlowHashRawAddressIPv6GtU32(uint32_t *a, uint32_t *b) +{ + int i; + + for (i = 0; i < 4; i++) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + break; + } + + return 0; +} + +typedef struct FlowHashKey4_ { + union { + struct { + uint32_t src, dst; + uint16_t sp, dp; + uint16_t proto; /**< u16 so proto and recur add up to u32 */ + uint16_t recur; /**< u16 so proto and recur add up to u32 */ + }; + uint32_t u32[4]; + }; +} FlowHashKey4; + +typedef struct FlowHashKey6_ { + union { + struct { + uint32_t src[4], dst[4]; + uint16_t sp, dp; + uint16_t proto; /**< u16 so proto and recur add up to u32 */ + uint16_t recur; /**< u16 so proto and recur add up to u32 */ + }; + uint32_t u32[10]; + }; +} FlowHashKey6; + /* calculate the hash key for this packet * * we're using: @@ -152,53 +202,107 @@ void FlowHashDebugDeinit(void) { * * For ICMP we only consider UNREACHABLE errors atm. */ -uint32_t FlowGetKey(Packet *p) { - FlowKey *k = (FlowKey *)p; +static inline uint32_t FlowGetKey(Packet *p) { uint32_t key; if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { - key = (flow_config.hash_rand + k->proto + k->sp + k->dp + \ - k->src.addr_data32[0] + k->dst.addr_data32[0] + \ - k->recursion_level) % flow_config.hash_size; -/* - SCLogDebug("TCP/UCP key %"PRIu32, key); - - SCLogDebug("proto %u, sp %u, dp %u, src %u, dst %u, reclvl %u", - k->proto, k->sp, k->dp, k->src.addr_data32[0], k->dst.addr_data32[0], - k->recursion_level); -*/ + FlowHashKey4 fhk; + if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { + fhk.src = p->src.addr_data32[0]; + fhk.dst = p->dst.addr_data32[0]; + } else { + fhk.src = p->dst.addr_data32[0]; + fhk.dst = p->src.addr_data32[0]; + } + if (p->sp > p->dp) { + fhk.sp = p->sp; + fhk.dp = p->dp; + } else { + fhk.sp = p->dp; + fhk.dp = p->sp; + } + fhk.proto = (uint16_t)p->proto; + fhk.recur = (uint16_t)p->recursion_level; + + uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand); + key = hash % flow_config.hash_size; + } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { -// SCLogDebug("valid ICMPv4 DEST UNREACH error packet"); - - key = (flow_config.hash_rand + ICMPV4_GET_EMB_PROTO(p) + - p->icmpv4vars.emb_sport + \ - p->icmpv4vars.emb_dport + \ - IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)) + \ - IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)) + \ - k->recursion_level) % flow_config.hash_size; -/* - SCLogDebug("ICMP DEST UNREACH key %"PRIu32, key); - - SCLogDebug("proto %u, sp %u, dp %u, src %u, dst %u, reclvl %u", - ICMPV4_GET_EMB_PROTO(p), p->icmpv4vars.emb_sport, - p->icmpv4vars.emb_dport, IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)), - IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)), k->recursion_level); -*/ + uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); + uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)); + FlowHashKey4 fhk; + if (psrc > pdst) { + fhk.src = psrc; + fhk.dst = pdst; + } else { + fhk.src = pdst; + fhk.dst = psrc; + } + if (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport) { + fhk.sp = p->icmpv4vars.emb_sport; + fhk.dp = p->icmpv4vars.emb_dport; + } else { + fhk.sp = p->icmpv4vars.emb_dport; + fhk.dp = p->icmpv4vars.emb_sport; + } + fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p); + fhk.recur = (uint16_t)p->recursion_level; + + uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand); + key = hash % flow_config.hash_size; + } else { - key = (flow_config.hash_rand + k->proto + \ - k->src.addr_data32[0] + k->dst.addr_data32[0] + \ - k->recursion_level) % flow_config.hash_size; + FlowHashKey4 fhk; + if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { + fhk.src = p->src.addr_data32[0]; + fhk.dst = p->dst.addr_data32[0]; + } else { + fhk.src = p->dst.addr_data32[0]; + fhk.dst = p->src.addr_data32[0]; + } + fhk.sp = 0xfeed; + fhk.dp = 0xbeef; + fhk.proto = (uint16_t)p->proto; + fhk.recur = (uint16_t)p->recursion_level; + uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand); + key = hash % flow_config.hash_size; + } + } else if (p->ip6h != NULL) { + FlowHashKey6 fhk; + if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { + fhk.src[0] = p->src.addr_data32[0]; + fhk.src[1] = p->src.addr_data32[1]; + fhk.src[2] = p->src.addr_data32[2]; + fhk.src[3] = p->src.addr_data32[3]; + fhk.dst[0] = p->dst.addr_data32[0]; + fhk.dst[1] = p->dst.addr_data32[1]; + fhk.dst[2] = p->dst.addr_data32[2]; + fhk.dst[3] = p->dst.addr_data32[3]; + } else { + fhk.src[0] = p->dst.addr_data32[0]; + fhk.src[1] = p->dst.addr_data32[1]; + fhk.src[2] = p->dst.addr_data32[2]; + fhk.src[3] = p->dst.addr_data32[3]; + fhk.dst[0] = p->src.addr_data32[0]; + fhk.dst[1] = p->src.addr_data32[1]; + fhk.dst[2] = p->src.addr_data32[2]; + fhk.dst[3] = p->src.addr_data32[3]; } - } else if (p->ip6h != NULL) - key = (flow_config.hash_rand + k->proto + k->sp + k->dp + \ - k->src.addr_data32[0] + k->src.addr_data32[1] + \ - k->src.addr_data32[2] + k->src.addr_data32[3] + \ - k->dst.addr_data32[0] + k->dst.addr_data32[1] + \ - k->dst.addr_data32[2] + k->dst.addr_data32[3] + \ - k->recursion_level) % flow_config.hash_size; - else + if (p->sp > p->dp) { + fhk.sp = p->sp; + fhk.dp = p->dp; + } else { + fhk.sp = p->dp; + fhk.dp = p->sp; + } + fhk.proto = (uint16_t)p->proto; + fhk.recur = (uint16_t)p->recursion_level; + + uint32_t hash = hashword(fhk.u32, 10, flow_config.hash_rand); + key = hash % flow_config.hash_size; + } else key = 0; return key;