]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
flow: make flow use lookup3.c hashing algorithm. Improves hash table distribution.
authorVictor Julien <victor@inliniac.net>
Tue, 27 Mar 2012 08:05:51 +0000 (10:05 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 27 Mar 2012 08:05:51 +0000 (10:05 +0200)
src/flow-hash.c

index 4326203699e3a979c71df78b0032e8eb152e2f00..9ce8067bb906974d8e3da46e4dd278b82ab80616 100644 (file)
@@ -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;